From 77823a3ff9f635c4196a66d5374feea85b027e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Thu, 6 Jun 2019 22:02:38 -0700 Subject: [PATCH] Updated spirv-tools. --- 3rdparty/spirv-tools/.appveyor.yml | 4 +- 3rdparty/spirv-tools/.gitignore | 1 + 3rdparty/spirv-tools/Android.mk | 2 +- 3rdparty/spirv-tools/BUILD.gn | 1 + 3rdparty/spirv-tools/CMakeLists.txt | 7 +- 3rdparty/spirv-tools/DEPS | 2 +- 3rdparty/spirv-tools/README.md | 2 - 3rdparty/spirv-tools/external/CMakeLists.txt | 12 + .../include/generated/build-version.inc | 2 +- .../include/generated/core.insts-unified1.inc | 4 + .../include/generated/enum_string_mapping.inc | 16 +- .../include/generated/extension_enum.inc | 2 + .../generated/operand.kinds-unified1.inc | 24 +- .../include/spirv-tools/instrument.hpp | 44 +- .../include/spirv-tools/libspirv.h | 17 + .../include/spirv-tools/libspirv.hpp | 20 + .../include/spirv-tools/optimizer.hpp | 3 +- 3rdparty/spirv-tools/source/CMakeLists.txt | 7 +- .../spirv-tools/source/comp/CMakeLists.txt | 52 - .../spirv-tools/source/comp/bit_stream.cpp | 348 - 3rdparty/spirv-tools/source/comp/bit_stream.h | 280 - .../spirv-tools/source/comp/huffman_codec.h | 389 - 3rdparty/spirv-tools/source/comp/markv.cpp | 112 - 3rdparty/spirv-tools/source/comp/markv.h | 74 - .../spirv-tools/source/comp/markv_codec.cpp | 793 - .../spirv-tools/source/comp/markv_codec.h | 337 - .../spirv-tools/source/comp/markv_decoder.cpp | 925 - .../spirv-tools/source/comp/markv_decoder.h | 175 - .../spirv-tools/source/comp/markv_encoder.cpp | 486 - .../spirv-tools/source/comp/markv_encoder.h | 167 - .../spirv-tools/source/comp/markv_logger.h | 93 - .../spirv-tools/source/comp/markv_model.h | 232 - .../spirv-tools/source/comp/move_to_front.cpp | 456 - .../spirv-tools/source/comp/move_to_front.h | 384 - .../spirv-tools/source/fuzz/CMakeLists.txt | 120 + .../spirv-tools/source/fuzz/fact_manager.cpp | 46 + .../spirv-tools/source/fuzz/fact_manager.h | 53 + 3rdparty/spirv-tools/source/fuzz/fuzzer.cpp | 131 + 3rdparty/spirv-tools/source/fuzz/fuzzer.h | 74 + .../source/fuzz/fuzzer_context.cpp | 48 + .../spirv-tools/source/fuzz/fuzzer_context.h | 64 + .../spirv-tools/source/fuzz/fuzzer_pass.cpp | 31 + .../spirv-tools/source/fuzz/fuzzer_pass.h | 61 + .../fuzz/fuzzer_pass_add_dead_breaks.cpp | 105 + .../source/fuzz/fuzzer_pass_add_dead_breaks.h | 38 + .../fuzzer_pass_add_useful_constructs.cpp | 182 + .../fuzz/fuzzer_pass_add_useful_constructs.h | 46 + .../fuzz/fuzzer_pass_permute_blocks.cpp | 85 + .../source/fuzz/fuzzer_pass_permute_blocks.h | 39 + .../source/fuzz/fuzzer_pass_split_blocks.cpp | 99 + .../source/fuzz/fuzzer_pass_split_blocks.h | 39 + .../spirv-tools/source/fuzz/fuzzer_util.cpp | 36 + .../spirv-tools/source/fuzz/fuzzer_util.h | 38 + .../source/fuzz/id_use_descriptor.cpp | 82 + .../source/fuzz/id_use_descriptor.h | 42 + .../fuzz/protobufs/spirvfuzz_protobufs.h | 52 + .../source/fuzz/protobufs/spvtoolsfuzz.proto | 226 + .../source/fuzz/pseudo_random_generator.cpp | 47 + .../source/fuzz/pseudo_random_generator.h | 47 + .../fuzz/random_generator.cpp} | 24 +- .../source/fuzz/random_generator.h | 45 + .../transformation_add_constant_boolean.cpp | 60 + .../transformation_add_constant_boolean.h | 44 + .../transformation_add_constant_scalar.cpp | 83 + .../fuzz/transformation_add_constant_scalar.h | 46 + .../fuzz/transformation_add_dead_break.cpp | 316 + .../fuzz/transformation_add_dead_break.h | 61 + .../fuzz/transformation_add_type_boolean.cpp | 58 + .../fuzz/transformation_add_type_boolean.h | 43 + .../fuzz/transformation_add_type_float.cpp | 61 + .../fuzz/transformation_add_type_float.h | 44 + .../fuzz/transformation_add_type_int.cpp | 63 + .../source/fuzz/transformation_add_type_int.h | 45 + .../fuzz/transformation_move_block_down.cpp | 102 + .../fuzz/transformation_move_block_down.h | 46 + ..._boolean_constant_with_constant_binary.cpp | 282 + ...ce_boolean_constant_with_constant_binary.h | 59 + .../fuzz/transformation_split_block.cpp | 183 + .../source/fuzz/transformation_split_block.h | 52 + 3rdparty/spirv-tools/source/id_descriptor.cpp | 78 - 3rdparty/spirv-tools/source/id_descriptor.h | 63 - 3rdparty/spirv-tools/source/link/linker.cpp | 19 +- .../source/opt/const_folding_rules.cpp | 26 + 3rdparty/spirv-tools/source/opt/constants.cpp | 2 - 3rdparty/spirv-tools/source/opt/constants.h | 7 +- .../source/opt/dead_branch_elim_pass.cpp | 85 +- .../source/opt/dead_branch_elim_pass.h | 7 +- ...ld_spec_constant_op_and_composite_pass.cpp | 117 +- ...fold_spec_constant_op_and_composite_pass.h | 8 +- .../source/opt/inst_bindless_check_pass.h | 7 +- .../source/opt/instrument_pass.cpp | 130 +- .../spirv-tools/source/opt/instrument_pass.h | 39 +- .../spirv-tools/source/opt/ir_context.cpp | 7 +- 3rdparty/spirv-tools/source/opt/ir_context.h | 8 +- 3rdparty/spirv-tools/source/opt/optimizer.cpp | 20 +- .../source/opt/remove_duplicates_pass.cpp | 89 +- .../source/opt/remove_duplicates_pass.h | 6 - .../source/opt/struct_cfg_analysis.cpp | 24 + .../source/opt/struct_cfg_analysis.h | 21 + .../spirv-tools/source/opt/type_manager.cpp | 62 +- .../spirv-tools/source/opt/type_manager.h | 2 + 3rdparty/spirv-tools/source/opt/types.cpp | 42 +- 3rdparty/spirv-tools/source/opt/types.h | 31 +- .../source/spirv_fuzzer_options.cpp | 31 + .../spirv-tools/source/spirv_fuzzer_options.h | 33 + 3rdparty/spirv-tools/source/val/construct.cpp | 23 +- 3rdparty/spirv-tools/source/val/construct.h | 4 +- 3rdparty/spirv-tools/source/val/function.cpp | 24 + 3rdparty/spirv-tools/source/val/function.h | 16 + 3rdparty/spirv-tools/source/val/validate.cpp | 2 +- 3rdparty/spirv-tools/source/val/validate.h | 3 + .../source/val/validate_builtins.cpp | 189 +- .../spirv-tools/source/val/validate_cfg.cpp | 4 + .../val/validate_execution_limitations.cpp | 11 + .../source/val/validate_extensions.cpp | 17 +- .../spirv-tools/source/val/validate_image.cpp | 68 +- .../spirv-tools/source/val/validate_misc.cpp | 81 + .../source/val/validate_mode_setting.cpp | 26 + .../source/val/validation_state.cpp | 6 + .../spirv-tools/source/val/validation_state.h | 1 + 3rdparty/spirv-tools/test/CMakeLists.txt | 25 +- 3rdparty/spirv-tools/test/bit_stream.cpp | 1025 -- 3rdparty/spirv-tools/test/comp/CMakeLists.txt | 29 - .../test/comp/markv_codec_test.cpp | 829 - 3rdparty/spirv-tools/test/fuzz/CMakeLists.txt | 36 + .../spirv-tools/test/fuzz/fuzz_test_util.cpp | 89 + .../spirv-tools/test/fuzz/fuzz_test_util.h | 65 + .../spirv-tools/test/fuzz/fuzzer_test.cpp | 464 + ...ansformation_add_constant_boolean_test.cpp | 155 + ...ransformation_add_constant_scalar_test.cpp | 209 + .../transformation_add_dead_break_test.cpp | 2261 +++ .../transformation_add_type_boolean_test.cpp | 83 + .../transformation_add_type_float_test.cpp | 84 + .../fuzz/transformation_add_type_int_test.cpp | 98 + .../transformation_move_block_down_test.cpp | 830 + ...ean_constant_with_constant_binary_test.cpp | 630 + .../fuzz/transformation_split_block_test.cpp | 773 + 3rdparty/spirv-tools/test/fuzzers/BUILD.gn | 46 + .../spvtools_opt_vulkantowebgpu_fuzzer.cpp | 38 + .../spvtools_opt_webgputovulkan_fuzzer.cpp | 38 + .../fuzzers/spvtools_val_webgpu_fuzzer.cpp | 36 + 3rdparty/spirv-tools/test/huffman_codec.cpp | 317 - 3rdparty/spirv-tools/test/link/CMakeLists.txt | 1 + .../spirv-tools/test/link/linker_fixture.h | 97 + .../spirv-tools/test/link/type_match_test.cpp | 144 + .../spirv-tools/test/move_to_front_test.cpp | 828 - .../test/opt/dead_branch_elim_test.cpp | 88 + .../opt/fold_spec_const_op_composite_test.cpp | 21 +- 3rdparty/spirv-tools/test/opt/fold_test.cpp | 143 +- .../test/opt/inst_bindless_check_test.cpp | 4050 +++++ .../spirv-tools/test/opt/optimizer_test.cpp | 121 +- .../test/opt/struct_cfg_analysis_test.cpp | 358 +- .../test/opt/type_manager_test.cpp | 89 +- 3rdparty/spirv-tools/test/opt/types_test.cpp | 60 +- .../spirv-tools/test/stats/CMakeLists.txt | 27 - .../test/stats/stats_aggregate_test.cpp | 438 - .../test/stats/stats_analyzer_test.cpp | 174 - .../test/val/val_builtins_test.cpp | 321 +- .../spirv-tools/test/val/val_cfg_test.cpp | 172 + .../test/val/val_code_generator.cpp | 2 + .../test/val/val_ext_inst_test.cpp | 25 +- .../spirv-tools/test/val/val_modes_test.cpp | 99 + .../spirv-tools/test/val/val_opencl_test.cpp | 211 + 3rdparty/spirv-tools/tools/CMakeLists.txt | 26 +- 3rdparty/spirv-tools/tools/comp/markv.cpp | 385 - .../tools/comp/markv_model_factory.cpp | 50 - .../tools/comp/markv_model_shader.cpp | 84 - .../tools/comp/markv_model_shader.h | 47 - .../markv_model_shader_default_autogen.inc | 14519 ---------------- 3rdparty/spirv-tools/tools/fuzz/fuzz.cpp | 255 + 3rdparty/spirv-tools/tools/io.h | 3 + 3rdparty/spirv-tools/tools/opt/opt.cpp | 18 + .../spirv-tools/tools/stats/spirv_stats.cpp | 165 - .../spirv-tools/tools/stats/spirv_stats.h | 93 - 3rdparty/spirv-tools/tools/stats/stats.cpp | 173 - .../tools/stats/stats_analyzer.cpp | 235 - .../spirv-tools/tools/stats/stats_analyzer.h | 58 - .../spirv-tools/utils/check_code_format.sh | 6 +- .../spirv-tools/utils/check_symbol_exports.py | 9 +- scripts/shaderc.lua | 3 +- 180 files changed, 16816 insertions(+), 25402 deletions(-) delete mode 100644 3rdparty/spirv-tools/source/comp/CMakeLists.txt delete mode 100644 3rdparty/spirv-tools/source/comp/bit_stream.cpp delete mode 100644 3rdparty/spirv-tools/source/comp/bit_stream.h delete mode 100644 3rdparty/spirv-tools/source/comp/huffman_codec.h delete mode 100644 3rdparty/spirv-tools/source/comp/markv.cpp delete mode 100644 3rdparty/spirv-tools/source/comp/markv.h delete mode 100644 3rdparty/spirv-tools/source/comp/markv_codec.cpp delete mode 100644 3rdparty/spirv-tools/source/comp/markv_codec.h delete mode 100644 3rdparty/spirv-tools/source/comp/markv_decoder.cpp delete mode 100644 3rdparty/spirv-tools/source/comp/markv_decoder.h delete mode 100644 3rdparty/spirv-tools/source/comp/markv_encoder.cpp delete mode 100644 3rdparty/spirv-tools/source/comp/markv_encoder.h delete mode 100644 3rdparty/spirv-tools/source/comp/markv_logger.h delete mode 100644 3rdparty/spirv-tools/source/comp/markv_model.h delete mode 100644 3rdparty/spirv-tools/source/comp/move_to_front.cpp delete mode 100644 3rdparty/spirv-tools/source/comp/move_to_front.h create mode 100644 3rdparty/spirv-tools/source/fuzz/CMakeLists.txt create mode 100644 3rdparty/spirv-tools/source/fuzz/fact_manager.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fact_manager.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_context.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/fuzzer_util.h create mode 100644 3rdparty/spirv-tools/source/fuzz/id_use_descriptor.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/id_use_descriptor.h create mode 100644 3rdparty/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h create mode 100644 3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto create mode 100644 3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.h rename 3rdparty/spirv-tools/{tools/comp/markv_model_factory.h => source/fuzz/random_generator.cpp} (57%) create mode 100644 3rdparty/spirv-tools/source/fuzz/random_generator.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_split_block.h delete mode 100644 3rdparty/spirv-tools/source/id_descriptor.cpp delete mode 100644 3rdparty/spirv-tools/source/id_descriptor.h create mode 100644 3rdparty/spirv-tools/source/spirv_fuzzer_options.cpp create mode 100644 3rdparty/spirv-tools/source/spirv_fuzzer_options.h create mode 100644 3rdparty/spirv-tools/source/val/validate_misc.cpp delete mode 100644 3rdparty/spirv-tools/test/bit_stream.cpp delete mode 100644 3rdparty/spirv-tools/test/comp/CMakeLists.txt delete mode 100644 3rdparty/spirv-tools/test/comp/markv_codec_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/CMakeLists.txt create mode 100644 3rdparty/spirv-tools/test/fuzz/fuzz_test_util.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/fuzz_test_util.h create mode 100644 3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp create mode 100644 3rdparty/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp create mode 100644 3rdparty/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp create mode 100644 3rdparty/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp delete mode 100644 3rdparty/spirv-tools/test/huffman_codec.cpp create mode 100644 3rdparty/spirv-tools/test/link/type_match_test.cpp delete mode 100644 3rdparty/spirv-tools/test/move_to_front_test.cpp delete mode 100644 3rdparty/spirv-tools/test/stats/CMakeLists.txt delete mode 100644 3rdparty/spirv-tools/test/stats/stats_aggregate_test.cpp delete mode 100644 3rdparty/spirv-tools/test/stats/stats_analyzer_test.cpp delete mode 100644 3rdparty/spirv-tools/tools/comp/markv.cpp delete mode 100644 3rdparty/spirv-tools/tools/comp/markv_model_factory.cpp delete mode 100644 3rdparty/spirv-tools/tools/comp/markv_model_shader.cpp delete mode 100644 3rdparty/spirv-tools/tools/comp/markv_model_shader.h delete mode 100644 3rdparty/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc create mode 100644 3rdparty/spirv-tools/tools/fuzz/fuzz.cpp delete mode 100644 3rdparty/spirv-tools/tools/stats/spirv_stats.cpp delete mode 100644 3rdparty/spirv-tools/tools/stats/spirv_stats.h delete mode 100644 3rdparty/spirv-tools/tools/stats/stats.cpp delete mode 100644 3rdparty/spirv-tools/tools/stats/stats_analyzer.cpp delete mode 100644 3rdparty/spirv-tools/tools/stats/stats_analyzer.h diff --git a/3rdparty/spirv-tools/.appveyor.yml b/3rdparty/spirv-tools/.appveyor.yml index 669de030a..77cd89c90 100644 --- a/3rdparty/spirv-tools/.appveyor.yml +++ b/3rdparty/spirv-tools/.appveyor.yml @@ -59,11 +59,11 @@ build: build_script: - mkdir build && cd build - - cmake -GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF .. + - cmake -GNinja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF .. - ninja install test_script: - - ctest -C %CONFIGURATION% --output-on-failure --timeout 300 + - ctest -C %CONFIGURATION% --output-on-failure --timeout 310 after_test: # Zip build artifacts for uploading and deploying diff --git a/3rdparty/spirv-tools/.gitignore b/3rdparty/spirv-tools/.gitignore index e097bab37..a965a99b5 100644 --- a/3rdparty/spirv-tools/.gitignore +++ b/3rdparty/spirv-tools/.gitignore @@ -9,6 +9,7 @@ compile_commands.json /external/spirv-headers /external/effcee /external/re2 +/external/protobuf /out /TAGS /third_party/llvm-build/ diff --git a/3rdparty/spirv-tools/Android.mk b/3rdparty/spirv-tools/Android.mk index a43142236..8e4437893 100644 --- a/3rdparty/spirv-tools/Android.mk +++ b/3rdparty/spirv-tools/Android.mk @@ -13,7 +13,6 @@ SPVTOOLS_SRC_FILES := \ source/ext_inst.cpp \ source/enum_string_mapping.cpp \ source/extensions.cpp \ - source/id_descriptor.cpp \ source/libspirv.cpp \ source/name_mapper.cpp \ source/opcode.cpp \ @@ -63,6 +62,7 @@ SPVTOOLS_SRC_FILES := \ source/val/validate_instruction.cpp \ source/val/validate_memory.cpp \ source/val/validate_memory_semantics.cpp \ + source/val/validate_misc.cpp \ source/val/validate_mode_setting.cpp \ source/val/validate_layout.cpp \ source/val/validate_literals.cpp \ diff --git a/3rdparty/spirv-tools/BUILD.gn b/3rdparty/spirv-tools/BUILD.gn index 5c6f311d2..fb9e8a4f0 100644 --- a/3rdparty/spirv-tools/BUILD.gn +++ b/3rdparty/spirv-tools/BUILD.gn @@ -422,6 +422,7 @@ static_library("spvtools_val") { "source/val/validate_logicals.cpp", "source/val/validate_memory.cpp", "source/val/validate_memory_semantics.cpp", + "source/val/validate_misc.cpp", "source/val/validate_mode_setting.cpp", "source/val/validate_non_uniform.cpp", "source/val/validate_primitives.cpp", diff --git a/3rdparty/spirv-tools/CMakeLists.txt b/3rdparty/spirv-tools/CMakeLists.txt index abe89d5b3..9f24e3863 100644 --- a/3rdparty/spirv-tools/CMakeLists.txt +++ b/3rdparty/spirv-tools/CMakeLists.txt @@ -69,6 +69,10 @@ if(NOT ${SKIP_SPIRV_TOOLS_INSTALL}) endif() option(SPIRV_BUILD_COMPRESSION "Build SPIR-V compressing codec" OFF) +if(SPIRV_BUILD_COMPRESSION) + message(FATAL_ERROR "SPIR-V compression codec has been removed from SPIR-V tools. " + "Please remove SPIRV_BUILD_COMPRESSION from your build options.") +endif(SPIRV_BUILD_COMPRESSION) option(SPIRV_WERROR "Enable error on warning" ON) if(("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") AND (NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))) @@ -257,9 +261,6 @@ endif() set(SPIRV_LIBRARIES "-lSPIRV-Tools -lSPIRV-Tools-link -lSPIRV-Tools-opt") set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools-shared") -if(SPIRV_BUILD_COMPRESSION) - set(SPIRV_LIBRARIES "${SPIRV_LIBRARIES} -lSPIRV-Tools-comp") -endif(SPIRV_BUILD_COMPRESSION) # Build pkg-config file # Use a first-class target so it's regenerated when relevant files are updated. diff --git a/3rdparty/spirv-tools/DEPS b/3rdparty/spirv-tools/DEPS index 3c5361fc2..9a8e92265 100644 --- a/3rdparty/spirv-tools/DEPS +++ b/3rdparty/spirv-tools/DEPS @@ -11,7 +11,7 @@ vars = { 'googletest_revision': '98a0d007d7092b72eea0e501bb9ad17908a1a036', 'testing_revision': '340252637e2e7c72c0901dcbeeacfff419e19b59', 're2_revision': '6cf8ccd82dbaab2668e9b13596c68183c9ecd13f', - 'spirv_headers_revision': 'e74c389f81915d0a48d6df1af83c3862c5ad85ab', + 'spirv_headers_revision': '8b911bd2ba37677037b38c9bd286c7c05701bcda', } deps = { diff --git a/3rdparty/spirv-tools/README.md b/3rdparty/spirv-tools/README.md index edc5ecaf6..9737f7e78 100644 --- a/3rdparty/spirv-tools/README.md +++ b/3rdparty/spirv-tools/README.md @@ -307,8 +307,6 @@ The following CMake options are supported: the command line tools. This will prevent the tests from being built. * `SPIRV_SKIP_EXECUTABLES={ON|OFF}`, default `OFF`- Build only the library, not the command line tools and tests. -* `SPIRV_BUILD_COMPRESSION={ON|OFF}`, default `OFF`- Build SPIR-V compressing - codec. * `SPIRV_USE_SANITIZER=`, default is no sanitizing - On UNIX platforms with an appropriate version of `clang` this option enables the use of the sanitizers documented [here][clang-sanitizers]. diff --git a/3rdparty/spirv-tools/external/CMakeLists.txt b/3rdparty/spirv-tools/external/CMakeLists.txt index d1251c248..3190f4b08 100644 --- a/3rdparty/spirv-tools/external/CMakeLists.txt +++ b/3rdparty/spirv-tools/external/CMakeLists.txt @@ -102,3 +102,15 @@ if (NOT ${SPIRV_SKIP_TESTS}) endif() endif() endif() + +if(SPIRV_BUILD_FUZZER) + set(PROTOBUF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/protobuf/cmake) + set(protobuf_BUILD_TESTS OFF CACHE BOOL "Disable protobuf tests") + set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Do not build protobuf static runtime") + if (IS_DIRECTORY ${PROTOBUF_DIR}) + add_subdirectory(${PROTOBUF_DIR} EXCLUDE_FROM_ALL) + else() + message(FATAL_ERROR + "protobuf not found - please checkout a copy under external/.") + endif() +endif(SPIRV_BUILD_FUZZER) diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index c4850ff7e..cde55e3a9 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-6-g47741f0" +"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-41-ga8ae579f" diff --git a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc index 3bddfb1f8..5dedd601d 100644 --- a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc @@ -6,6 +6,7 @@ static const SpvCapability pygen_variable_caps_CooperativeMatrixNV[] = {SpvCapab static const SpvCapability pygen_variable_caps_DerivativeControl[] = {SpvCapabilityDerivativeControl}; static const SpvCapability pygen_variable_caps_DeviceEnqueue[] = {SpvCapabilityDeviceEnqueue}; static const SpvCapability pygen_variable_caps_FragmentMaskAMD[] = {SpvCapabilityFragmentMaskAMD}; +static const SpvCapability pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT[] = {SpvCapabilityFragmentShaderSampleInterlockEXT, SpvCapabilityFragmentShaderPixelInterlockEXT, SpvCapabilityFragmentShaderShadingRateInterlockEXT}; static const SpvCapability pygen_variable_caps_Geometry[] = {SpvCapabilityGeometry}; static const SpvCapability pygen_variable_caps_GeometryStreams[] = {SpvCapabilityGeometryStreams}; static const SpvCapability pygen_variable_caps_GroupNonUniform[] = {SpvCapabilityGroupNonUniform}; @@ -44,6 +45,7 @@ static const SpvCapability pygen_variable_caps_SubgroupVoteKHR[] = {SpvCapabilit static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_ballot[] = {spvtools::Extension::kSPV_AMD_shader_ballot}; static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_fragment_mask[] = {spvtools::Extension::kSPV_AMD_shader_fragment_mask}; +static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_shader_interlock[] = {spvtools::Extension::kSPV_EXT_fragment_shader_interlock}; static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_decorate_stringSPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_decorate_string, spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1}; static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_shader_ballot[] = {spvtools::Extension::kSPV_KHR_shader_ballot}; @@ -429,6 +431,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"CooperativeMatrixStoreNV", SpvOpCooperativeMatrixStoreNV, 1, pygen_variable_caps_CooperativeMatrixNV, 5, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, 0xffffffffu, 0xffffffffu}, {"CooperativeMatrixMulAddNV", SpvOpCooperativeMatrixMulAddNV, 1, pygen_variable_caps_CooperativeMatrixNV, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, 0xffffffffu, 0xffffffffu}, {"CooperativeMatrixLengthNV", SpvOpCooperativeMatrixLengthNV, 1, pygen_variable_caps_CooperativeMatrixNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, 0xffffffffu, 0xffffffffu}, + {"BeginInvocationInterlockEXT", SpvOpBeginInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu}, + {"EndInvocationInterlockEXT", SpvOpEndInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu}, {"SubgroupShuffleINTEL", SpvOpSubgroupShuffleINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"SubgroupShuffleDownINTEL", SpvOpSubgroupShuffleDownINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"SubgroupShuffleUpINTEL", SpvOpSubgroupShuffleUpINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, diff --git a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc index 5669fadb4..4df39a324 100644 --- a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc +++ b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc @@ -26,6 +26,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_EXT_fragment_fully_covered"; case Extension::kSPV_EXT_fragment_invocation_density: return "SPV_EXT_fragment_invocation_density"; + case Extension::kSPV_EXT_fragment_shader_interlock: + return "SPV_EXT_fragment_shader_interlock"; case Extension::kSPV_EXT_physical_storage_buffer: return "SPV_EXT_physical_storage_buffer"; case Extension::kSPV_EXT_shader_stencil_export: @@ -90,6 +92,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_NV_sample_mask_override_coverage"; case Extension::kSPV_NV_shader_image_footprint: return "SPV_NV_shader_image_footprint"; + case Extension::kSPV_NV_shader_sm_builtins: + return "SPV_NV_shader_sm_builtins"; case Extension::kSPV_NV_shader_subgroup_partitioned: return "SPV_NV_shader_subgroup_partitioned"; case Extension::kSPV_NV_shading_rate: @@ -107,8 +111,8 @@ const char* ExtensionToString(Extension extension) { bool GetExtensionFromString(const char* str, Extension* extension) { - static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" }; - static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; + static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" }; + static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; const auto b = std::begin(known_ext_strs); const auto e = std::end(known_ext_strs); const auto found = std::equal_range( @@ -388,6 +392,14 @@ const char* CapabilityToString(SpvCapability capability) { return "PhysicalStorageBufferAddressesEXT"; case SpvCapabilityCooperativeMatrixNV: return "CooperativeMatrixNV"; + case SpvCapabilityFragmentShaderSampleInterlockEXT: + return "FragmentShaderSampleInterlockEXT"; + case SpvCapabilityFragmentShaderShadingRateInterlockEXT: + return "FragmentShaderShadingRateInterlockEXT"; + case SpvCapabilityFragmentShaderPixelInterlockEXT: + return "FragmentShaderPixelInterlockEXT"; + case SpvCapabilityShaderSMBuiltinsNV: + return "ShaderSMBuiltinsNV"; case SpvCapabilityMax: assert(0 && "Attempting to convert SpvCapabilityMax to string"); return ""; diff --git a/3rdparty/spirv-tools/include/generated/extension_enum.inc b/3rdparty/spirv-tools/include/generated/extension_enum.inc index c36e3a034..9ba66b0ee 100644 --- a/3rdparty/spirv-tools/include/generated/extension_enum.inc +++ b/3rdparty/spirv-tools/include/generated/extension_enum.inc @@ -11,6 +11,7 @@ kSPV_AMD_texture_gather_bias_lod, kSPV_EXT_descriptor_indexing, kSPV_EXT_fragment_fully_covered, kSPV_EXT_fragment_invocation_density, +kSPV_EXT_fragment_shader_interlock, kSPV_EXT_physical_storage_buffer, kSPV_EXT_shader_stencil_export, kSPV_EXT_shader_viewport_index_layer, @@ -43,6 +44,7 @@ kSPV_NV_mesh_shader, kSPV_NV_ray_tracing, kSPV_NV_sample_mask_override_coverage, kSPV_NV_shader_image_footprint, +kSPV_NV_shader_sm_builtins, kSPV_NV_shader_subgroup_partitioned, kSPV_NV_shading_rate, kSPV_NV_stereo_view_rendering, diff --git a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc index 7498a74ba..3608e8d47 100644 --- a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc @@ -13,6 +13,9 @@ static const SpvCapability pygen_variable_caps_DrawParametersMeshShadingNV[] = { static const SpvCapability pygen_variable_caps_FragmentBarycentricNV[] = {SpvCapabilityFragmentBarycentricNV}; static const SpvCapability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {SpvCapabilityFragmentDensityEXT, SpvCapabilityShadingRateNV}; static const SpvCapability pygen_variable_caps_FragmentFullyCoveredEXT[] = {SpvCapabilityFragmentFullyCoveredEXT}; +static const SpvCapability pygen_variable_caps_FragmentShaderPixelInterlockEXT[] = {SpvCapabilityFragmentShaderPixelInterlockEXT}; +static const SpvCapability pygen_variable_caps_FragmentShaderSampleInterlockEXT[] = {SpvCapabilityFragmentShaderSampleInterlockEXT}; +static const SpvCapability pygen_variable_caps_FragmentShaderShadingRateInterlockEXT[] = {SpvCapabilityFragmentShaderShadingRateInterlockEXT}; static const SpvCapability pygen_variable_caps_GenericPointer[] = {SpvCapabilityGenericPointer}; static const SpvCapability pygen_variable_caps_Geometry[] = {SpvCapabilityGeometry}; static const SpvCapability pygen_variable_caps_GeometryMeshShadingNV[] = {SpvCapabilityGeometry, SpvCapabilityMeshShadingNV}; @@ -63,6 +66,7 @@ static const SpvCapability pygen_variable_caps_ShaderImageCubeArray[] = {SpvCapa static const SpvCapability pygen_variable_caps_ShaderKernel[] = {SpvCapabilityShader, SpvCapabilityKernel}; static const SpvCapability pygen_variable_caps_ShaderKernelImageMSArray[] = {SpvCapabilityShader, SpvCapabilityKernel, SpvCapabilityImageMSArray}; static const SpvCapability pygen_variable_caps_ShaderNonUniformEXT[] = {SpvCapabilityShaderNonUniformEXT}; +static const SpvCapability pygen_variable_caps_ShaderSMBuiltinsNV[] = {SpvCapabilityShaderSMBuiltinsNV}; static const SpvCapability pygen_variable_caps_ShaderStereoViewNV[] = {SpvCapabilityShaderStereoViewNV}; static const SpvCapability pygen_variable_caps_ShaderViewportIndexLayerNV[] = {SpvCapabilityShaderViewportIndexLayerNV}; static const SpvCapability pygen_variable_caps_ShaderViewportMaskNV[] = {SpvCapabilityShaderViewportMaskNV}; @@ -89,6 +93,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_AMD_texture_gather_bias static const spvtools::Extension pygen_variable_exts_SPV_EXT_descriptor_indexing[] = {spvtools::Extension::kSPV_EXT_descriptor_indexing}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_fully_covered[] = {spvtools::Extension::kSPV_EXT_fragment_fully_covered}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate[] = {spvtools::Extension::kSPV_EXT_fragment_invocation_density, spvtools::Extension::kSPV_NV_shading_rate}; +static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_shader_interlock[] = {spvtools::Extension::kSPV_EXT_fragment_shader_interlock}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_physical_storage_buffer[] = {spvtools::Extension::kSPV_EXT_physical_storage_buffer}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_stencil_export[] = {spvtools::Extension::kSPV_EXT_shader_stencil_export}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_viewport_index_layer[] = {spvtools::Extension::kSPV_EXT_shader_viewport_index_layer}; @@ -123,6 +128,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spv static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing}; static const spvtools::Extension pygen_variable_exts_SPV_NV_sample_mask_override_coverage[] = {spvtools::Extension::kSPV_NV_sample_mask_override_coverage}; static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_image_footprint[] = {spvtools::Extension::kSPV_NV_shader_image_footprint}; +static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_sm_builtins[] = {spvtools::Extension::kSPV_NV_shader_sm_builtins}; static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_subgroup_partitioned[] = {spvtools::Extension::kSPV_NV_shader_subgroup_partitioned}; static const spvtools::Extension pygen_variable_exts_SPV_NV_shading_rateSPV_EXT_fragment_invocation_density[] = {spvtools::Extension::kSPV_NV_shading_rate, spvtools::Extension::kSPV_EXT_fragment_invocation_density}; static const spvtools::Extension pygen_variable_exts_SPV_NV_stereo_view_rendering[] = {spvtools::Extension::kSPV_NV_stereo_view_rendering}; @@ -307,7 +313,13 @@ static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = { {"OutputPrimitivesNV", 5270, 1, pygen_variable_caps_MeshShadingNV, 1, pygen_variable_exts_SPV_NV_mesh_shader, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}, {"DerivativeGroupQuadsNV", 5289, 1, pygen_variable_caps_ComputeDerivativeGroupQuadsNV, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, {"DerivativeGroupLinearNV", 5290, 1, pygen_variable_caps_ComputeDerivativeGroupLinearNV, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, - {"OutputTrianglesNV", 5298, 1, pygen_variable_caps_MeshShadingNV, 1, pygen_variable_exts_SPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu} + {"OutputTrianglesNV", 5298, 1, pygen_variable_caps_MeshShadingNV, 1, pygen_variable_exts_SPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu}, + {"PixelInterlockOrderedEXT", 5366, 1, pygen_variable_caps_FragmentShaderPixelInterlockEXT, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, + {"PixelInterlockUnorderedEXT", 5367, 1, pygen_variable_caps_FragmentShaderPixelInterlockEXT, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, + {"SampleInterlockOrderedEXT", 5368, 1, pygen_variable_caps_FragmentShaderSampleInterlockEXT, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, + {"SampleInterlockUnorderedEXT", 5369, 1, pygen_variable_caps_FragmentShaderSampleInterlockEXT, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, + {"ShadingRateInterlockOrderedEXT", 5370, 1, pygen_variable_caps_FragmentShaderShadingRateInterlockEXT, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, + {"ShadingRateInterlockUnorderedEXT", 5371, 1, pygen_variable_caps_FragmentShaderShadingRateInterlockEXT, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_StorageClassEntries[] = { @@ -637,7 +649,11 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = { {"WorldToObjectNV", 5331, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"HitKindNV", 5333, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"IncomingRayFlagsNV", 5351, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"IncomingRayFlagsNV", 5351, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, + {"WarpsPerSMNV", 5374, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, + {"SMCountNV", 5375, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, + {"WarpIDNV", 5376, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, + {"SMIDNV", 5377, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_ScopeEntries[] = { @@ -794,6 +810,10 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"PhysicalStorageBufferAddressesEXT", 5347, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu, 0xffffffffu}, {"ComputeDerivativeGroupLinearNV", 5350, 0, nullptr, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, {"CooperativeMatrixNV", 5357, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, {}, 0xffffffffu, 0xffffffffu}, + {"FragmentShaderSampleInterlockEXT", 5363, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, + {"FragmentShaderShadingRateInterlockEXT", 5372, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, + {"ShaderSMBuiltinsNV", 5373, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu}, + {"FragmentShaderPixelInterlockEXT", 5378, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, {"SubgroupShuffleINTEL", 5568, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu}, {"SubgroupBufferBlockIOINTEL", 5569, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu}, {"SubgroupImageBlockIOINTEL", 5570, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu}, diff --git a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp b/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp index 9711b9297..4d37e3f18 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp @@ -34,6 +34,11 @@ namespace spvtools { // generated by InstrumentPass::GenDebugStreamWrite. This method is utilized // by InstBindlessCheckPass. // +// kInst2* values support version 2 of the output record format. These should +// be used if available and version 2 is enabled. Version 1 is DEPRECATED. +// Specifically, version 1 uses two words for the stage-specific section of +// the output record; version 2 uses three words. +// // The first member of the debug output buffer contains the next available word // in the data stream to be written. Shaders will atomically read and update // this value so as not to overwrite each others records. This value must be @@ -70,38 +75,58 @@ static const int kInstCommonOutCnt = 4; // Stage-specific Stream Record Offsets // -// Each stage will contain different values in the next two words of the record -// used to identify which instantiation of the shader generated the validation -// error. +// Each stage will contain different values in the next set of words of the +// record used to identify which instantiation of the shader generated the +// validation error. // // Vertex Shader Output Record Offsets static const int kInstVertOutVertexIndex = kInstCommonOutCnt; static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1; +static const int kInstVertOutUnused = kInstCommonOutCnt + 2; // Frag Shader Output Record Offsets static const int kInstFragOutFragCoordX = kInstCommonOutCnt; static const int kInstFragOutFragCoordY = kInstCommonOutCnt + 1; +static const int kInstFragOutUnused = kInstCommonOutCnt + 2; // Compute Shader Output Record Offsets +static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt; +static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1; +static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2; + +// Compute Shader Output Record Offsets - Version 1 (DEPRECATED) static const int kInstCompOutGlobalInvocationId = kInstCommonOutCnt; static const int kInstCompOutUnused = kInstCommonOutCnt + 1; -// Tessellation Shader Output Record Offsets +// Tessellation Control Shader Output Record Offsets +static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt; +static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1; +static const int kInstTessCtlOutUnused = kInstCommonOutCnt + 2; + +// Tessellation Eval Shader Output Record Offsets +static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt; +static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1; +static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2; + +// Tessellation Shader Output Record Offsets - Version 1 (DEPRECATED) static const int kInstTessOutInvocationId = kInstCommonOutCnt; static const int kInstTessOutUnused = kInstCommonOutCnt + 1; // Geometry Shader Output Record Offsets static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt; static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1; +static const int kInstGeomOutUnused = kInstCommonOutCnt + 2; // Size of Common and Stage-specific Members static const int kInstStageOutCnt = kInstCommonOutCnt + 2; +static const int kInst2StageOutCnt = kInstCommonOutCnt + 3; -// Validation Error Code +// Validation Error Code Offset // // This identifies the validation error. It also helps to identify // how many words follow in the record and their meaning. static const int kInstValidationOutError = kInstStageOutCnt; +static const int kInst2ValidationOutError = kInst2StageOutCnt; // Validation-specific Output Record Offsets // @@ -114,11 +139,19 @@ static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 1; static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 2; static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 3; +static const int kInst2BindlessBoundsOutDescIndex = kInst2StageOutCnt + 1; +static const int kInst2BindlessBoundsOutDescBound = kInst2StageOutCnt + 2; +static const int kInst2BindlessBoundsOutCnt = kInst2StageOutCnt + 3; + // A bindless uninitialized error will output the index. static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 1; static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 2; static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 3; +static const int kInst2BindlessUninitOutDescIndex = kInst2StageOutCnt + 1; +static const int kInst2BindlessUninitOutUnused = kInst2StageOutCnt + 2; +static const int kInst2BindlessUninitOutCnt = kInst2StageOutCnt + 3; + // DEPRECATED static const int kInstBindlessOutDescIndex = kInstStageOutCnt + 1; static const int kInstBindlessOutDescBound = kInstStageOutCnt + 2; @@ -126,6 +159,7 @@ static const int kInstBindlessOutCnt = kInstStageOutCnt + 3; // Maximum Output Record Member Count static const int kInstMaxOutCnt = kInstStageOutCnt + 3; +static const int kInst2MaxOutCnt = kInst2StageOutCnt + 3; // Validation Error Codes // diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h index 5cea101ff..82717e910 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h @@ -370,6 +370,8 @@ typedef struct spv_optimizer_options_t spv_optimizer_options_t; typedef struct spv_reducer_options_t spv_reducer_options_t; +typedef struct spv_fuzzer_options_t spv_fuzzer_options_t; + // Type Definitions typedef spv_const_binary_t* spv_const_binary; @@ -385,6 +387,8 @@ typedef spv_optimizer_options_t* spv_optimizer_options; typedef const spv_optimizer_options_t* spv_const_optimizer_options; typedef spv_reducer_options_t* spv_reducer_options; typedef const spv_reducer_options_t* spv_const_reducer_options; +typedef spv_fuzzer_options_t* spv_fuzzer_options; +typedef const spv_fuzzer_options_t* spv_const_fuzzer_options; // Platform API @@ -590,6 +594,19 @@ SPIRV_TOOLS_EXPORT void spvReducerOptionsSetStepLimit( SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError( spv_reducer_options options, bool fail_on_validation_error); +// Creates a fuzzer options object with default options. Returns a valid +// options object. The object remains valid until it is passed into +// |spvFuzzerOptionsDestroy|. +SPIRV_TOOLS_EXPORT spv_fuzzer_options spvFuzzerOptionsCreate(); + +// Destroys the given fuzzer options object. +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsDestroy(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( + spv_fuzzer_options options, uint32_t seed); + // Encodes the given SPIR-V assembly text to its binary representation. The // length parameter specifies the number of bytes for text. Encoded binary will // be stored into *binary. Any error will be written into *diagnostic if diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp index da27404d6..b0fd4a2c2 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp @@ -191,6 +191,26 @@ class ReducerOptions { spv_reducer_options options_; }; +// A C++ wrapper around a fuzzer options object. +class FuzzerOptions { + public: + FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {} + ~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); } + + // Allow implicit conversion to the underlying object. + operator spv_fuzzer_options() const { // NOLINT(google-explicit-constructor) + return options_; + } + + // See spvFuzzerOptionsSetRandomSeed. + void set_random_seed(uint32_t seed) { + spvFuzzerOptionsSetRandomSeed(options_, seed); + } + + private: + spv_fuzzer_options options_; +}; + // C++ interface for SPIRV-Tools functionalities. It wraps the context // (including target environment and the corresponding SPIR-V grammar) and // provides methods for assembling, disassembling, and validating. diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index 313c9924d..1d8d6e04c 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -738,9 +738,10 @@ Optimizer::PassToken CreateCombineAccessChainsPass(); // |input_length_enable| controls instrumentation of runtime descriptor array // references, and |input_init_enable| controls instrumentation of descriptor // initialization checking, both of which require input buffer support. +// |version| specifies the buffer record format. Optimizer::PassToken CreateInstBindlessCheckPass( uint32_t desc_set, uint32_t shader_id, bool input_length_enable = false, - bool input_init_enable = false); + bool input_init_enable = false, uint32_t version = 1); // Create a pass to upgrade to the VulkanKHR memory model. // This pass upgrades the Logical GLSL450 memory model to Logical VulkanKHR. diff --git a/3rdparty/spirv-tools/source/CMakeLists.txt b/3rdparty/spirv-tools/source/CMakeLists.txt index 1f96018c6..bd4c465d9 100644 --- a/3rdparty/spirv-tools/source/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/CMakeLists.txt @@ -196,9 +196,9 @@ set_source_files_properties( ${CMAKE_CURRENT_SOURCE_DIR}/pch_source.cpp PROPERTIES OBJECT_DEPENDS "${PCH_DEPENDS}") -add_subdirectory(comp) add_subdirectory(opt) add_subdirectory(reduce) +add_subdirectory(fuzz) add_subdirectory(link) set(SPIRV_SOURCES @@ -221,7 +221,6 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.h ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.h ${CMAKE_CURRENT_SOURCE_DIR}/extensions.h - ${CMAKE_CURRENT_SOURCE_DIR}/id_descriptor.h ${CMAKE_CURRENT_SOURCE_DIR}/instruction.h ${CMAKE_CURRENT_SOURCE_DIR}/latest_version_glsl_std_450_header.h ${CMAKE_CURRENT_SOURCE_DIR}/latest_version_opencl_std_header.h @@ -235,6 +234,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/spirv_constant.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_definition.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.h + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_fuzzer_options.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_optimizer_options.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.h @@ -254,7 +254,6 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp ${CMAKE_CURRENT_SOURCE_DIR}/extensions.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/id_descriptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/libspirv.cpp ${CMAKE_CURRENT_SOURCE_DIR}/name_mapper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/opcode.cpp @@ -263,6 +262,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/print.cpp ${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_fuzzer_options.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_optimizer_options.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.cpp @@ -299,6 +299,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_logicals.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_memory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_memory_semantics.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_misc.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_mode_setting.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_non_uniform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_primitives.cpp diff --git a/3rdparty/spirv-tools/source/comp/CMakeLists.txt b/3rdparty/spirv-tools/source/comp/CMakeLists.txt deleted file mode 100644 index f65f9f670..000000000 --- a/3rdparty/spirv-tools/source/comp/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2017 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. - -if(SPIRV_BUILD_COMPRESSION) - add_library(SPIRV-Tools-comp - bit_stream.cpp - bit_stream.h - huffman_codec.h - markv_codec.cpp - markv_codec.h - markv.cpp - markv.h - markv_decoder.cpp - markv_decoder.h - markv_encoder.cpp - markv_encoder.h - markv_logger.h - move_to_front.h - move_to_front.cpp) - - spvtools_default_compile_options(SPIRV-Tools-comp) - target_include_directories(SPIRV-Tools-comp - PUBLIC ${spirv-tools_SOURCE_DIR}/include - PUBLIC ${SPIRV_HEADER_INCLUDE_DIR} - PRIVATE ${spirv-tools_BINARY_DIR} - ) - - target_link_libraries(SPIRV-Tools-comp - PUBLIC ${SPIRV_TOOLS}) - - set_property(TARGET SPIRV-Tools-comp PROPERTY FOLDER "SPIRV-Tools libraries") - spvtools_check_symbol_exports(SPIRV-Tools-comp) - - if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-comp - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif(ENABLE_SPIRV_TOOLS_INSTALL) - -endif(SPIRV_BUILD_COMPRESSION) diff --git a/3rdparty/spirv-tools/source/comp/bit_stream.cpp b/3rdparty/spirv-tools/source/comp/bit_stream.cpp deleted file mode 100644 index a5769e03e..000000000 --- a/3rdparty/spirv-tools/source/comp/bit_stream.cpp +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright (c) 2017 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 -#include -#include -#include -#include - -#include "source/comp/bit_stream.h" - -namespace spvtools { -namespace comp { -namespace { - -// Returns if the system is little-endian. Unfortunately only works during -// runtime. -bool IsLittleEndian() { - // This constant value allows the detection of the host machine's endianness. - // Accessing it as an array of bytes is valid due to C++11 section 3.10 - // paragraph 10. - static const uint16_t kFF00 = 0xff00; - return reinterpret_cast(&kFF00)[0] == 0; -} - -// Copies bytes from the given buffer to a uint64_t buffer. -// Motivation: casting uint64_t* to uint8_t* is ok. Casting in the other -// direction is only advisable if uint8_t* is aligned to 64-bit word boundary. -std::vector ToBuffer64(const void* buffer, size_t num_bytes) { - std::vector out; - out.resize((num_bytes + 7) / 8, 0); - memcpy(out.data(), buffer, num_bytes); - return out; -} - -// Copies uint8_t buffer to a uint64_t buffer. -std::vector ToBuffer64(const std::vector& in) { - return ToBuffer64(in.data(), in.size()); -} - -// Returns uint64_t containing the same bits as |val|. -// Type size must be less than 8 bytes. -template -uint64_t ToU64(T val) { - static_assert(sizeof(T) <= 8, "Type size too big"); - uint64_t val64 = 0; - std::memcpy(&val64, &val, sizeof(T)); - return val64; -} - -// Returns value of type T containing the same bits as |val64|. -// Type size must be less than 8 bytes. Upper (unused) bits of |val64| must be -// zero (irrelevant, but is checked with assertion). -template -T FromU64(uint64_t val64) { - assert(sizeof(T) == 8 || (val64 >> (sizeof(T) * 8)) == 0); - static_assert(sizeof(T) <= 8, "Type size too big"); - T val = 0; - std::memcpy(&val, &val64, sizeof(T)); - return val; -} - -// Writes bits from |val| to |writer| in chunks of size |chunk_length|. -// Signal bit is used to signal if the reader should expect another chunk: -// 0 - no more chunks to follow -// 1 - more chunks to follow -// If number of written bits reaches |max_payload| last chunk is truncated. -void WriteVariableWidthInternal(BitWriterInterface* writer, uint64_t val, - size_t chunk_length, size_t max_payload) { - assert(chunk_length > 0); - assert(chunk_length < max_payload); - assert(max_payload == 64 || (val >> max_payload) == 0); - - if (val == 0) { - // Split in two writes for more readable logging. - writer->WriteBits(0, chunk_length); - writer->WriteBits(0, 1); - return; - } - - size_t payload_written = 0; - - while (val) { - if (payload_written + chunk_length >= max_payload) { - // This has to be the last chunk. - // There is no need for the signal bit and the chunk can be truncated. - const size_t left_to_write = max_payload - payload_written; - assert((val >> left_to_write) == 0); - writer->WriteBits(val, left_to_write); - break; - } - - writer->WriteBits(val, chunk_length); - payload_written += chunk_length; - val = val >> chunk_length; - - // Write a single bit to signal if there is more to come. - writer->WriteBits(val ? 1 : 0, 1); - } -} - -// Reads data written with WriteVariableWidthInternal. |chunk_length| and -// |max_payload| should be identical to those used to write the data. -// Returns false if the stream ends prematurely. -bool ReadVariableWidthInternal(BitReaderInterface* reader, uint64_t* val, - size_t chunk_length, size_t max_payload) { - assert(chunk_length > 0); - assert(chunk_length <= max_payload); - size_t payload_read = 0; - - while (payload_read + chunk_length < max_payload) { - uint64_t bits = 0; - if (reader->ReadBits(&bits, chunk_length) != chunk_length) return false; - - *val |= bits << payload_read; - payload_read += chunk_length; - - uint64_t more_to_come = 0; - if (reader->ReadBits(&more_to_come, 1) != 1) return false; - - if (!more_to_come) { - return true; - } - } - - // Need to read the last chunk which may be truncated. No signal bit follows. - uint64_t bits = 0; - const size_t left_to_read = max_payload - payload_read; - if (reader->ReadBits(&bits, left_to_read) != left_to_read) return false; - - *val |= bits << payload_read; - return true; -} - -// Calls WriteVariableWidthInternal with the right max_payload argument. -template -void WriteVariableWidthUnsigned(BitWriterInterface* writer, T val, - size_t chunk_length) { - static_assert(std::is_unsigned::value, "Type must be unsigned"); - static_assert(std::is_integral::value, "Type must be integral"); - WriteVariableWidthInternal(writer, val, chunk_length, sizeof(T) * 8); -} - -// Calls ReadVariableWidthInternal with the right max_payload argument. -template -bool ReadVariableWidthUnsigned(BitReaderInterface* reader, T* val, - size_t chunk_length) { - static_assert(std::is_unsigned::value, "Type must be unsigned"); - static_assert(std::is_integral::value, "Type must be integral"); - uint64_t val64 = 0; - if (!ReadVariableWidthInternal(reader, &val64, chunk_length, sizeof(T) * 8)) - return false; - *val = static_cast(val64); - assert(*val == val64); - return true; -} - -// Encodes signed |val| to an unsigned value and calls -// WriteVariableWidthInternal with the right max_payload argument. -template -void WriteVariableWidthSigned(BitWriterInterface* writer, T val, - size_t chunk_length, size_t zigzag_exponent) { - static_assert(std::is_signed::value, "Type must be signed"); - static_assert(std::is_integral::value, "Type must be integral"); - WriteVariableWidthInternal(writer, EncodeZigZag(val, zigzag_exponent), - chunk_length, sizeof(T) * 8); -} - -// Calls ReadVariableWidthInternal with the right max_payload argument -// and decodes the value. -template -bool ReadVariableWidthSigned(BitReaderInterface* reader, T* val, - size_t chunk_length, size_t zigzag_exponent) { - static_assert(std::is_signed::value, "Type must be signed"); - static_assert(std::is_integral::value, "Type must be integral"); - uint64_t encoded = 0; - if (!ReadVariableWidthInternal(reader, &encoded, chunk_length, sizeof(T) * 8)) - return false; - - const int64_t decoded = DecodeZigZag(encoded, zigzag_exponent); - - *val = static_cast(decoded); - assert(*val == decoded); - return true; -} - -} // namespace - -void BitWriterInterface::WriteVariableWidthU64(uint64_t val, - size_t chunk_length) { - WriteVariableWidthUnsigned(this, val, chunk_length); -} - -void BitWriterInterface::WriteVariableWidthU32(uint32_t val, - size_t chunk_length) { - WriteVariableWidthUnsigned(this, val, chunk_length); -} - -void BitWriterInterface::WriteVariableWidthU16(uint16_t val, - size_t chunk_length) { - WriteVariableWidthUnsigned(this, val, chunk_length); -} - -void BitWriterInterface::WriteVariableWidthS64(int64_t val, size_t chunk_length, - size_t zigzag_exponent) { - WriteVariableWidthSigned(this, val, chunk_length, zigzag_exponent); -} - -BitWriterWord64::BitWriterWord64(size_t reserve_bits) : end_(0) { - buffer_.reserve(NumBitsToNumWords<64>(reserve_bits)); -} - -void BitWriterWord64::WriteBits(uint64_t bits, size_t num_bits) { - // Check that |bits| and |num_bits| are valid and consistent. - assert(num_bits <= 64); - const bool is_little_endian = IsLittleEndian(); - assert(is_little_endian && "Big-endian architecture support not implemented"); - if (!is_little_endian) return; - - if (num_bits == 0) return; - - bits = GetLowerBits(bits, num_bits); - - EmitSequence(bits, num_bits); - - // Offset from the start of the current word. - const size_t offset = end_ % 64; - - if (offset == 0) { - // If no offset, simply add |bits| as a new word to the buffer_. - buffer_.push_back(bits); - } else { - // Shift bits and add them to the current word after offset. - const uint64_t first_word = bits << offset; - buffer_.back() |= first_word; - - // If we don't overflow to the next word, there is nothing more to do. - - if (offset + num_bits > 64) { - // We overflow to the next word. - const uint64_t second_word = bits >> (64 - offset); - // Add remaining bits as a new word to buffer_. - buffer_.push_back(second_word); - } - } - - // Move end_ into position for next write. - end_ += num_bits; - assert(buffer_.size() * 64 >= end_); -} - -bool BitReaderInterface::ReadVariableWidthU64(uint64_t* val, - size_t chunk_length) { - return ReadVariableWidthUnsigned(this, val, chunk_length); -} - -bool BitReaderInterface::ReadVariableWidthU32(uint32_t* val, - size_t chunk_length) { - return ReadVariableWidthUnsigned(this, val, chunk_length); -} - -bool BitReaderInterface::ReadVariableWidthU16(uint16_t* val, - size_t chunk_length) { - return ReadVariableWidthUnsigned(this, val, chunk_length); -} - -bool BitReaderInterface::ReadVariableWidthS64(int64_t* val, size_t chunk_length, - size_t zigzag_exponent) { - return ReadVariableWidthSigned(this, val, chunk_length, zigzag_exponent); -} - -BitReaderWord64::BitReaderWord64(std::vector&& buffer) - : buffer_(std::move(buffer)), pos_(0) {} - -BitReaderWord64::BitReaderWord64(const std::vector& buffer) - : buffer_(ToBuffer64(buffer)), pos_(0) {} - -BitReaderWord64::BitReaderWord64(const void* buffer, size_t num_bytes) - : buffer_(ToBuffer64(buffer, num_bytes)), pos_(0) {} - -size_t BitReaderWord64::ReadBits(uint64_t* bits, size_t num_bits) { - assert(num_bits <= 64); - const bool is_little_endian = IsLittleEndian(); - assert(is_little_endian && "Big-endian architecture support not implemented"); - if (!is_little_endian) return 0; - - if (ReachedEnd()) return 0; - - // Index of the current word. - const size_t index = pos_ / 64; - - // Bit position in the current word where we start reading. - const size_t offset = pos_ % 64; - - // Read all bits from the current word (it might be too much, but - // excessive bits will be removed later). - *bits = buffer_[index] >> offset; - - const size_t num_read_from_first_word = std::min(64 - offset, num_bits); - pos_ += num_read_from_first_word; - - if (pos_ >= buffer_.size() * 64) { - // Reached end of buffer_. - EmitSequence(*bits, num_read_from_first_word); - return num_read_from_first_word; - } - - if (offset + num_bits > 64) { - // Requested |num_bits| overflows to next word. - // Write all bits from the beginning of next word to *bits after offset. - *bits |= buffer_[index + 1] << (64 - offset); - pos_ += offset + num_bits - 64; - } - - // We likely have written more bits than requested. Clear excessive bits. - *bits = GetLowerBits(*bits, num_bits); - EmitSequence(*bits, num_bits); - return num_bits; -} - -bool BitReaderWord64::ReachedEnd() const { return pos_ >= buffer_.size() * 64; } - -bool BitReaderWord64::OnlyZeroesLeft() const { - if (ReachedEnd()) return true; - - const size_t index = pos_ / 64; - if (index < buffer_.size() - 1) return false; - - assert(index == buffer_.size() - 1); - - const size_t offset = pos_ % 64; - const uint64_t remaining_bits = buffer_[index] >> offset; - return !remaining_bits; -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/comp/bit_stream.h b/3rdparty/spirv-tools/source/comp/bit_stream.h deleted file mode 100644 index 5f82344d6..000000000 --- a/3rdparty/spirv-tools/source/comp/bit_stream.h +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (c) 2017 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. - -// Contains utils for reading, writing and debug printing bit streams. - -#ifndef SOURCE_COMP_BIT_STREAM_H_ -#define SOURCE_COMP_BIT_STREAM_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -// Terminology: -// Bits - usually used for a uint64 word, first bit is the lowest. -// Stream - std::string of '0' and '1', read left-to-right, -// i.e. first bit is at the front and not at the end as in -// std::bitset::to_string(). -// Bitset - std::bitset corresponding to uint64 bits and to reverse(stream). - -// Converts number of bits to a respective number of chunks of size N. -// For example NumBitsToNumWords<8> returns how many bytes are needed to store -// |num_bits|. -template -inline size_t NumBitsToNumWords(size_t num_bits) { - return (num_bits + (N - 1)) / N; -} - -// Returns value of the same type as |in|, where all but the first |num_bits| -// are set to zero. -template -inline T GetLowerBits(T in, size_t num_bits) { - return sizeof(T) * 8 == num_bits ? in : in & T((T(1) << num_bits) - T(1)); -} - -// Encodes signed integer as unsigned. This is a generalized version of -// EncodeZigZag, designed to favor small positive numbers. -// Values are transformed in blocks of 2^|block_exponent|. -// If |block_exponent| is zero, then this degenerates into normal EncodeZigZag. -// Example when |block_exponent| is 1 (return value is the index): -// 0, 1, -1, -2, 2, 3, -3, -4, 4, 5, -5, -6, 6, 7, -7, -8 -// Example when |block_exponent| is 2: -// 0, 1, 2, 3, -1, -2, -3, -4, 4, 5, 6, 7, -5, -6, -7, -8 -inline uint64_t EncodeZigZag(int64_t val, size_t block_exponent) { - assert(block_exponent < 64); - const uint64_t uval = static_cast(val >= 0 ? val : -val - 1); - const uint64_t block_num = - ((uval >> block_exponent) << 1) + (val >= 0 ? 0 : 1); - const uint64_t pos = GetLowerBits(uval, block_exponent); - return (block_num << block_exponent) + pos; -} - -// Decodes signed integer encoded with EncodeZigZag. |block_exponent| must be -// the same. -inline int64_t DecodeZigZag(uint64_t val, size_t block_exponent) { - assert(block_exponent < 64); - const uint64_t block_num = val >> block_exponent; - const uint64_t pos = GetLowerBits(val, block_exponent); - if (block_num & 1) { - // Negative. - return -1LL - ((block_num >> 1) << block_exponent) - pos; - } else { - // Positive. - return ((block_num >> 1) << block_exponent) + pos; - } -} - -// Converts first |num_bits| stored in uint64 to a left-to-right stream of bits. -inline std::string BitsToStream(uint64_t bits, size_t num_bits = 64) { - std::bitset<64> bitset(bits); - std::string str = bitset.to_string().substr(64 - num_bits); - std::reverse(str.begin(), str.end()); - return str; -} - -// Base class for writing sequences of bits. -class BitWriterInterface { - public: - BitWriterInterface() = default; - virtual ~BitWriterInterface() = default; - - // Writes lower |num_bits| in |bits| to the stream. - // |num_bits| must be no greater than 64. - virtual void WriteBits(uint64_t bits, size_t num_bits) = 0; - - // Writes bits from value of type |T| to the stream. No encoding is done. - // Always writes 8 * sizeof(T) bits. - template - void WriteUnencoded(T val) { - static_assert(sizeof(T) <= 64, "Type size too large"); - uint64_t bits = 0; - memcpy(&bits, &val, sizeof(T)); - WriteBits(bits, sizeof(T) * 8); - } - - // Writes |val| in chunks of size |chunk_length| followed by a signal bit: - // 0 - no more chunks to follow - // 1 - more chunks to follow - // for example 255 is encoded into 1111 1 1111 0 for chunk length 4. - // The last chunk can be truncated and signal bit omitted, if the entire - // payload (for example 16 bit for uint16_t has already been written). - void WriteVariableWidthU64(uint64_t val, size_t chunk_length); - void WriteVariableWidthU32(uint32_t val, size_t chunk_length); - void WriteVariableWidthU16(uint16_t val, size_t chunk_length); - void WriteVariableWidthS64(int64_t val, size_t chunk_length, - size_t zigzag_exponent); - - // Returns number of bits written. - virtual size_t GetNumBits() const = 0; - - // Provides direct access to the buffer data if implemented. - virtual const uint8_t* GetData() const { return nullptr; } - - // Returns buffer size in bytes. - size_t GetDataSizeBytes() const { return NumBitsToNumWords<8>(GetNumBits()); } - - // Generates and returns byte array containing written bits. - virtual std::vector GetDataCopy() const = 0; - - BitWriterInterface(const BitWriterInterface&) = delete; - BitWriterInterface& operator=(const BitWriterInterface&) = delete; -}; - -// This class is an implementation of BitWriterInterface, using -// std::vector to store written bits. -class BitWriterWord64 : public BitWriterInterface { - public: - explicit BitWriterWord64(size_t reserve_bits = 64); - - void WriteBits(uint64_t bits, size_t num_bits) override; - - size_t GetNumBits() const override { return end_; } - - const uint8_t* GetData() const override { - return reinterpret_cast(buffer_.data()); - } - - std::vector GetDataCopy() const override { - return std::vector(GetData(), GetData() + GetDataSizeBytes()); - } - - // Sets callback to emit bit sequences after every write. - void SetCallback(std::function callback) { - callback_ = callback; - } - - protected: - // Sends string generated from arguments to callback_ if defined. - void EmitSequence(uint64_t bits, size_t num_bits) const { - if (callback_) callback_(BitsToStream(bits, num_bits)); - } - - private: - std::vector buffer_; - // Total number of bits written so far. Named 'end' as analogy to std::end(). - size_t end_; - - // If not null, the writer will use the callback to emit the written bit - // sequence as a string of '0' and '1'. - std::function callback_; -}; - -// Base class for reading sequences of bits. -class BitReaderInterface { - public: - BitReaderInterface() {} - virtual ~BitReaderInterface() {} - - // Reads |num_bits| from the stream, stores them in |bits|. - // Returns number of read bits. |num_bits| must be no greater than 64. - virtual size_t ReadBits(uint64_t* bits, size_t num_bits) = 0; - - // Reads 8 * sizeof(T) bits and stores them in |val|. - template - bool ReadUnencoded(T* val) { - static_assert(sizeof(T) <= 64, "Type size too large"); - uint64_t bits = 0; - const size_t num_read = ReadBits(&bits, sizeof(T) * 8); - if (num_read != sizeof(T) * 8) return false; - memcpy(val, &bits, sizeof(T)); - return true; - } - - // Returns number of bits already read. - virtual size_t GetNumReadBits() const = 0; - - // These two functions define 'hard' and 'soft' EOF. - // - // Returns true if the end of the buffer was reached. - virtual bool ReachedEnd() const = 0; - // Returns true if we reached the end of the buffer or are nearing it and only - // zero bits are left to read. Implementations of this function are allowed to - // commit a "false negative" error if the end of the buffer was not reached, - // i.e. it can return false even if indeed only zeroes are left. - // It is assumed that the consumer expects that - // the buffer stream ends with padding zeroes, and would accept this as a - // 'soft' EOF. Implementations of this class do not necessarily need to - // implement this, default behavior can simply delegate to ReachedEnd(). - virtual bool OnlyZeroesLeft() const { return ReachedEnd(); } - - // Reads value encoded with WriteVariableWidthXXX (see BitWriterInterface). - // Reader and writer must use the same |chunk_length| and variable type. - // Returns true on success, false if the bit stream ends prematurely. - bool ReadVariableWidthU64(uint64_t* val, size_t chunk_length); - bool ReadVariableWidthU32(uint32_t* val, size_t chunk_length); - bool ReadVariableWidthU16(uint16_t* val, size_t chunk_length); - bool ReadVariableWidthS64(int64_t* val, size_t chunk_length, - size_t zigzag_exponent); - - BitReaderInterface(const BitReaderInterface&) = delete; - BitReaderInterface& operator=(const BitReaderInterface&) = delete; -}; - -// This class is an implementation of BitReaderInterface which accepts both -// uint8_t and uint64_t buffers as input. uint64_t buffers are consumed and -// owned. uint8_t buffers are copied. -class BitReaderWord64 : public BitReaderInterface { - public: - // Consumes and owns the buffer. - explicit BitReaderWord64(std::vector&& buffer); - - // Copies the buffer and casts it to uint64. - // Consuming the original buffer and casting it to uint64 is difficult, - // as it would potentially cause data misalignment and poor performance. - explicit BitReaderWord64(const std::vector& buffer); - BitReaderWord64(const void* buffer, size_t num_bytes); - - size_t ReadBits(uint64_t* bits, size_t num_bits) override; - - size_t GetNumReadBits() const override { return pos_; } - - bool ReachedEnd() const override; - bool OnlyZeroesLeft() const override; - - BitReaderWord64() = delete; - - // Sets callback to emit bit sequences after every read. - void SetCallback(std::function callback) { - callback_ = callback; - } - - protected: - // Sends string generated from arguments to callback_ if defined. - void EmitSequence(uint64_t bits, size_t num_bits) const { - if (callback_) callback_(BitsToStream(bits, num_bits)); - } - - private: - const std::vector buffer_; - size_t pos_; - - // If not null, the reader will use the callback to emit the read bit - // sequence as a string of '0' and '1'. - std::function callback_; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_BIT_STREAM_H_ diff --git a/3rdparty/spirv-tools/source/comp/huffman_codec.h b/3rdparty/spirv-tools/source/comp/huffman_codec.h deleted file mode 100644 index 166021614..000000000 --- a/3rdparty/spirv-tools/source/comp/huffman_codec.h +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright (c) 2017 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. - -// Contains utils for reading, writing and debug printing bit streams. - -#ifndef SOURCE_COMP_HUFFMAN_CODEC_H_ -#define SOURCE_COMP_HUFFMAN_CODEC_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -// Used to generate and apply a Huffman coding scheme. -// |Val| is the type of variable being encoded (for example a string or a -// literal). -template -class HuffmanCodec { - public: - // Huffman tree node. - struct Node { - Node() {} - - // Creates Node from serialization leaving weight and id undefined. - Node(const Val& in_value, uint32_t in_left, uint32_t in_right) - : value(in_value), left(in_left), right(in_right) {} - - Val value = Val(); - uint32_t weight = 0; - // Ids are issued sequentially starting from 1. Ids are used as an ordering - // tie-breaker, to make sure that the ordering (and resulting coding scheme) - // are consistent accross multiple platforms. - uint32_t id = 0; - // Handles of children. - uint32_t left = 0; - uint32_t right = 0; - }; - - // Creates Huffman codec from a histogramm. - // Histogramm counts must not be zero. - explicit HuffmanCodec(const std::map& hist) { - if (hist.empty()) return; - - // Heuristic estimate. - nodes_.reserve(3 * hist.size()); - - // Create NIL. - CreateNode(); - - // The queue is sorted in ascending order by weight (or by node id if - // weights are equal). - std::vector queue_vector; - queue_vector.reserve(hist.size()); - std::priority_queue, - std::function> - queue(std::bind(&HuffmanCodec::LeftIsBigger, this, - std::placeholders::_1, std::placeholders::_2), - std::move(queue_vector)); - - // Put all leaves in the queue. - for (const auto& pair : hist) { - const uint32_t node = CreateNode(); - MutableValueOf(node) = pair.first; - MutableWeightOf(node) = pair.second; - assert(WeightOf(node)); - queue.push(node); - } - - // Form the tree by combining two subtrees with the least weight, - // and pushing the root of the new tree in the queue. - while (true) { - // We push a node at the end of each iteration, so the queue is never - // supposed to be empty at this point, unless there are no leaves, but - // that case was already handled. - assert(!queue.empty()); - const uint32_t right = queue.top(); - queue.pop(); - - // If the queue is empty at this point, then the last node is - // the root of the complete Huffman tree. - if (queue.empty()) { - root_ = right; - break; - } - - const uint32_t left = queue.top(); - queue.pop(); - - // Combine left and right into a new tree and push it into the queue. - const uint32_t parent = CreateNode(); - MutableWeightOf(parent) = WeightOf(right) + WeightOf(left); - MutableLeftOf(parent) = left; - MutableRightOf(parent) = right; - queue.push(parent); - } - - // Traverse the tree and form encoding table. - CreateEncodingTable(); - } - - // Creates Huffman codec from saved tree structure. - // |nodes| is the list of nodes of the tree, nodes[0] being NIL. - // |root_handle| is the index of the root node. - HuffmanCodec(uint32_t root_handle, std::vector&& nodes) { - nodes_ = std::move(nodes); - assert(!nodes_.empty()); - assert(root_handle > 0 && root_handle < nodes_.size()); - assert(!LeftOf(0) && !RightOf(0)); - - root_ = root_handle; - - // Traverse the tree and form encoding table. - CreateEncodingTable(); - } - - // Serializes the codec in the following text format: - // (, { - // {0, 0, 0}, - // {val1, left1, right1}, - // {val2, left2, right2}, - // ... - // }) - std::string SerializeToText(int indent_num_whitespaces) const { - const bool value_is_text = std::is_same::value; - - const std::string indent1 = std::string(indent_num_whitespaces, ' '); - const std::string indent2 = std::string(indent_num_whitespaces + 2, ' '); - - std::stringstream code; - code << "(" << root_ << ", {\n"; - - for (const Node& node : nodes_) { - code << indent2 << "{"; - if (value_is_text) code << "\""; - code << node.value; - if (value_is_text) code << "\""; - code << ", " << node.left << ", " << node.right << "},\n"; - } - - code << indent1 << "})"; - - return code.str(); - } - - // Prints the Huffman tree in the following format: - // w------w------'x' - // w------'y' - // Where w stands for the weight of the node. - // Right tree branches appear above left branches. Taking the right path - // adds 1 to the code, taking the left adds 0. - void PrintTree(std::ostream& out) const { PrintTreeInternal(out, root_, 0); } - - // Traverses the tree and prints the Huffman table: value, code - // and optionally node weight for every leaf. - void PrintTable(std::ostream& out, bool print_weights = true) { - std::queue> queue; - queue.emplace(root_, ""); - - while (!queue.empty()) { - const uint32_t node = queue.front().first; - const std::string code = queue.front().second; - queue.pop(); - if (!RightOf(node) && !LeftOf(node)) { - out << ValueOf(node); - if (print_weights) out << " " << WeightOf(node); - out << " " << code << std::endl; - } else { - if (LeftOf(node)) queue.emplace(LeftOf(node), code + "0"); - - if (RightOf(node)) queue.emplace(RightOf(node), code + "1"); - } - } - } - - // Returns the Huffman table. The table was built at at construction time, - // this function just returns a const reference. - const std::unordered_map>& GetEncodingTable() - const { - return encoding_table_; - } - - // Encodes |val| and stores its Huffman code in the lower |num_bits| of - // |bits|. Returns false of |val| is not in the Huffman table. - bool Encode(const Val& val, uint64_t* bits, size_t* num_bits) const { - auto it = encoding_table_.find(val); - if (it == encoding_table_.end()) return false; - *bits = it->second.first; - *num_bits = it->second.second; - return true; - } - - // Reads bits one-by-one using callback |read_bit| until a match is found. - // Matching value is stored in |val|. Returns false if |read_bit| terminates - // before a code was mathced. - // |read_bit| has type bool func(bool* bit). When called, the next bit is - // stored in |bit|. |read_bit| returns false if the stream terminates - // prematurely. - bool DecodeFromStream(const std::function& read_bit, - Val* val) const { - uint32_t node = root_; - while (true) { - assert(node); - - if (!RightOf(node) && !LeftOf(node)) { - *val = ValueOf(node); - return true; - } - - bool go_right; - if (!read_bit(&go_right)) return false; - - if (go_right) - node = RightOf(node); - else - node = LeftOf(node); - } - - assert(0); - return false; - } - - private: - // Returns value of the node referenced by |handle|. - Val ValueOf(uint32_t node) const { return nodes_.at(node).value; } - - // Returns left child of |node|. - uint32_t LeftOf(uint32_t node) const { return nodes_.at(node).left; } - - // Returns right child of |node|. - uint32_t RightOf(uint32_t node) const { return nodes_.at(node).right; } - - // Returns weight of |node|. - uint32_t WeightOf(uint32_t node) const { return nodes_.at(node).weight; } - - // Returns id of |node|. - uint32_t IdOf(uint32_t node) const { return nodes_.at(node).id; } - - // Returns mutable reference to value of |node|. - Val& MutableValueOf(uint32_t node) { - assert(node); - return nodes_.at(node).value; - } - - // Returns mutable reference to handle of left child of |node|. - uint32_t& MutableLeftOf(uint32_t node) { - assert(node); - return nodes_.at(node).left; - } - - // Returns mutable reference to handle of right child of |node|. - uint32_t& MutableRightOf(uint32_t node) { - assert(node); - return nodes_.at(node).right; - } - - // Returns mutable reference to weight of |node|. - uint32_t& MutableWeightOf(uint32_t node) { return nodes_.at(node).weight; } - - // Returns mutable reference to id of |node|. - uint32_t& MutableIdOf(uint32_t node) { return nodes_.at(node).id; } - - // Returns true if |left| has bigger weight than |right|. Node ids are - // used as tie-breaker. - bool LeftIsBigger(uint32_t left, uint32_t right) const { - if (WeightOf(left) == WeightOf(right)) { - assert(IdOf(left) != IdOf(right)); - return IdOf(left) > IdOf(right); - } - return WeightOf(left) > WeightOf(right); - } - - // Prints subtree (helper function used by PrintTree). - void PrintTreeInternal(std::ostream& out, uint32_t node, size_t depth) const { - if (!node) return; - - const size_t kTextFieldWidth = 7; - - if (!RightOf(node) && !LeftOf(node)) { - out << ValueOf(node) << std::endl; - } else { - if (RightOf(node)) { - std::stringstream label; - label << std::setfill('-') << std::left << std::setw(kTextFieldWidth) - << WeightOf(RightOf(node)); - out << label.str(); - PrintTreeInternal(out, RightOf(node), depth + 1); - } - - if (LeftOf(node)) { - out << std::string(depth * kTextFieldWidth, ' '); - std::stringstream label; - label << std::setfill('-') << std::left << std::setw(kTextFieldWidth) - << WeightOf(LeftOf(node)); - out << label.str(); - PrintTreeInternal(out, LeftOf(node), depth + 1); - } - } - } - - // Traverses the Huffman tree and saves paths to the leaves as bit - // sequences to encoding_table_. - void CreateEncodingTable() { - struct Context { - Context(uint32_t in_node, uint64_t in_bits, size_t in_depth) - : node(in_node), bits(in_bits), depth(in_depth) {} - uint32_t node; - // Huffman tree depth cannot exceed 64 as histogramm counts are expected - // to be positive and limited by numeric_limits::max(). - // For practical applications tree depth would be much smaller than 64. - uint64_t bits; - size_t depth; - }; - - std::queue queue; - queue.emplace(root_, 0, 0); - - while (!queue.empty()) { - const Context& context = queue.front(); - const uint32_t node = context.node; - const uint64_t bits = context.bits; - const size_t depth = context.depth; - queue.pop(); - - if (!RightOf(node) && !LeftOf(node)) { - auto insertion_result = encoding_table_.emplace( - ValueOf(node), std::pair(bits, depth)); - assert(insertion_result.second); - (void)insertion_result; - } else { - if (LeftOf(node)) queue.emplace(LeftOf(node), bits, depth + 1); - - if (RightOf(node)) - queue.emplace(RightOf(node), bits | (1ULL << depth), depth + 1); - } - } - } - - // Creates new Huffman tree node and stores it in the deleter array. - uint32_t CreateNode() { - const uint32_t handle = static_cast(nodes_.size()); - nodes_.emplace_back(Node()); - nodes_.back().id = next_node_id_++; - return handle; - } - - // Huffman tree root handle. - uint32_t root_ = 0; - - // Huffman tree deleter. - std::vector nodes_; - - // Encoding table value -> {bits, num_bits}. - // Huffman codes are expected to never exceed 64 bit length (this is in fact - // impossible if frequencies are stored as uint32_t). - std::unordered_map> encoding_table_; - - // Next node id issued by CreateNode(); - uint32_t next_node_id_ = 1; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_HUFFMAN_CODEC_H_ diff --git a/3rdparty/spirv-tools/source/comp/markv.cpp b/3rdparty/spirv-tools/source/comp/markv.cpp deleted file mode 100644 index 736bc51ba..000000000 --- a/3rdparty/spirv-tools/source/comp/markv.cpp +++ /dev/null @@ -1,112 +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/comp/markv.h" - -#include "source/comp/markv_decoder.h" -#include "source/comp/markv_encoder.h" - -namespace spvtools { -namespace comp { -namespace { - -spv_result_t EncodeHeader(void* user_data, spv_endianness_t endian, - uint32_t magic, uint32_t version, uint32_t generator, - uint32_t id_bound, uint32_t schema) { - MarkvEncoder* encoder = reinterpret_cast(user_data); - return encoder->EncodeHeader(endian, magic, version, generator, id_bound, - schema); -} - -spv_result_t EncodeInstruction(void* user_data, - const spv_parsed_instruction_t* inst) { - MarkvEncoder* encoder = reinterpret_cast(user_data); - return encoder->EncodeInstruction(*inst); -} - -} // namespace - -spv_result_t SpirvToMarkv( - spv_const_context context, const std::vector& spirv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* markv) { - spv_context_t hijack_context = *context; - SetContextMessageConsumer(&hijack_context, message_consumer); - - spv_validator_options validator_options = - MarkvDecoder::GetValidatorOptions(options); - if (validator_options) { - spv_const_binary_t spirv_binary = {spirv.data(), spirv.size()}; - const spv_result_t result = spvValidateWithOptions( - &hijack_context, validator_options, &spirv_binary, nullptr); - if (result != SPV_SUCCESS) return result; - } - - MarkvEncoder encoder(&hijack_context, options, &markv_model); - - spv_position_t position = {}; - if (log_consumer || debug_consumer) { - encoder.CreateLogger(log_consumer, debug_consumer); - - spv_text text = nullptr; - if (spvBinaryToText(&hijack_context, spirv.data(), spirv.size(), - SPV_BINARY_TO_TEXT_OPTION_NO_HEADER, &text, - nullptr) != SPV_SUCCESS) { - return DiagnosticStream(position, hijack_context.consumer, "", - SPV_ERROR_INVALID_BINARY) - << "Failed to disassemble SPIR-V binary."; - } - assert(text); - encoder.SetDisassembly(std::string(text->str, text->length)); - spvTextDestroy(text); - } - - if (spvBinaryParse(&hijack_context, &encoder, spirv.data(), spirv.size(), - EncodeHeader, EncodeInstruction, nullptr) != SPV_SUCCESS) { - return DiagnosticStream(position, hijack_context.consumer, "", - SPV_ERROR_INVALID_BINARY) - << "Unable to encode to MARK-V."; - } - - *markv = encoder.GetMarkvBinary(); - return SPV_SUCCESS; -} - -spv_result_t MarkvToSpirv( - spv_const_context context, const std::vector& markv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* spirv) { - spv_position_t position = {}; - spv_context_t hijack_context = *context; - SetContextMessageConsumer(&hijack_context, message_consumer); - - MarkvDecoder decoder(&hijack_context, markv, options, &markv_model); - - if (log_consumer || debug_consumer) - decoder.CreateLogger(log_consumer, debug_consumer); - - if (decoder.DecodeModule(spirv) != SPV_SUCCESS) { - return DiagnosticStream(position, hijack_context.consumer, "", - SPV_ERROR_INVALID_BINARY) - << "Unable to decode MARK-V."; - } - - assert(!spirv->empty()); - return SPV_SUCCESS; -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/comp/markv.h b/3rdparty/spirv-tools/source/comp/markv.h deleted file mode 100644 index 587086f91..000000000 --- a/3rdparty/spirv-tools/source/comp/markv.h +++ /dev/null @@ -1,74 +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. - -// MARK-V is a compression format for SPIR-V binaries. It strips away -// non-essential information (such as result ids which can be regenerated) and -// uses various bit reduction techiniques to reduce the size of the binary and -// make it more similar to other compressed SPIR-V files to further improve -// compression of the dataset. - -#ifndef SOURCE_COMP_MARKV_H_ -#define SOURCE_COMP_MARKV_H_ - -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { - -class MarkvModel; - -struct MarkvCodecOptions { - bool validate_spirv_binary = false; -}; - -// Debug callback. Called once per instruction. -// |words| is instruction SPIR-V words. -// |bits| is a textual representation of the MARK-V bit sequence used to encode -// the instruction (char '0' for 0, char '1' for 1). -// |comment| contains all logs generated while processing the instruction. -using MarkvDebugConsumer = - std::function& words, - const std::string& bits, const std::string& comment)>; - -// Logging callback. Called often (if decoder reads a single bit, the log -// consumer will receive 1 character string with that bit). -// This callback is more suitable for continous output than MarkvDebugConsumer, -// for example if the codec crashes it would allow to pinpoint on which operand -// or bit the crash happened. -// |snippet| could be any atomic fragment of text logged by the codec. It can -// contain a paragraph of text with newlines, or can be just one character. -using MarkvLogConsumer = std::function; - -// Encodes the given SPIR-V binary to MARK-V binary. -// |log_consumer| is optional (pass MarkvLogConsumer() to disable). -// |debug_consumer| is optional (pass MarkvDebugConsumer() to disable). -spv_result_t SpirvToMarkv( - spv_const_context context, const std::vector& spirv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* markv); - -// Decodes a SPIR-V binary from the given MARK-V binary. -// |log_consumer| is optional (pass MarkvLogConsumer() to disable). -// |debug_consumer| is optional (pass MarkvDebugConsumer() to disable). -spv_result_t MarkvToSpirv( - spv_const_context context, const std::vector& markv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* spirv); - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_H_ diff --git a/3rdparty/spirv-tools/source/comp/markv_codec.cpp b/3rdparty/spirv-tools/source/comp/markv_codec.cpp deleted file mode 100644 index ae3ce79f2..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_codec.cpp +++ /dev/null @@ -1,793 +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. - -// MARK-V is a compression format for SPIR-V binaries. It strips away -// non-essential information (such as result IDs which can be regenerated) and -// uses various bit reduction techniques to reduce the size of the binary. - -#include "source/comp/markv_codec.h" - -#include "source/comp/markv_logger.h" -#include "source/latest_version_glsl_std_450_header.h" -#include "source/latest_version_opencl_std_header.h" -#include "source/opcode.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace comp { -namespace { - -// Custom hash function used to produce short descriptors. -uint32_t ShortHashU32Array(const std::vector& words) { - // The hash function is a sum of hashes of each word seeded by word index. - // Knuth's multiplicative hash is used to hash the words. - const uint32_t kKnuthMulHash = 2654435761; - uint32_t val = 0; - for (uint32_t i = 0; i < words.size(); ++i) { - val += (words[i] + i + 123) * kKnuthMulHash; - } - return 1 + val % ((1 << MarkvCodec::kShortDescriptorNumBits) - 1); -} - -// Returns a set of mtf rank codecs based on a plausible hand-coded -// distribution. -std::map>> -GetMtfHuffmanCodecs() { - std::map>> codecs; - - std::unique_ptr> codec; - - codec = MakeUnique>(std::map({ - {0, 5}, - {1, 40}, - {2, 10}, - {3, 5}, - {4, 5}, - {5, 5}, - {6, 3}, - {7, 3}, - {8, 3}, - {9, 3}, - {MarkvCodec::kMtfRankEncodedByValueSignal, 10}, - })); - codecs.emplace(kMtfAll, std::move(codec)); - - codec = MakeUnique>(std::map({ - {1, 50}, - {2, 20}, - {3, 5}, - {4, 5}, - {5, 2}, - {6, 1}, - {7, 1}, - {8, 1}, - {9, 1}, - {MarkvCodec::kMtfRankEncodedByValueSignal, 10}, - })); - codecs.emplace(kMtfGenericNonZeroRank, std::move(codec)); - - return codecs; -} - -} // namespace - -const uint32_t MarkvCodec::kMarkvMagicNumber = 0x07230303; - -const uint32_t MarkvCodec::kMtfSmallestRankEncodedByValue = 10; - -const uint32_t MarkvCodec::kMtfRankEncodedByValueSignal = - std::numeric_limits::max(); - -const uint32_t MarkvCodec::kShortDescriptorNumBits = 8; - -const size_t MarkvCodec::kByteBreakAfterInstIfLessThanUntilNextByte = 8; - -MarkvCodec::MarkvCodec(spv_const_context context, - spv_validator_options validator_options, - const MarkvModel* model) - : validator_options_(validator_options), - grammar_(context), - model_(model), - short_id_descriptors_(ShortHashU32Array), - mtf_huffman_codecs_(GetMtfHuffmanCodecs()), - context_(context) {} - -MarkvCodec::~MarkvCodec() { spvValidatorOptionsDestroy(validator_options_); } - -MarkvCodec::MarkvHeader::MarkvHeader() - : magic_number(MarkvCodec::kMarkvMagicNumber), - markv_version(MarkvCodec::GetMarkvVersion()) {} - -// Defines and returns current MARK-V version. -// static -uint32_t MarkvCodec::GetMarkvVersion() { - const uint32_t kVersionMajor = 1; - const uint32_t kVersionMinor = 4; - return kVersionMinor | (kVersionMajor << 16); -} - -size_t MarkvCodec::GetNumBitsToNextByte(size_t bit_pos) const { - return (8 - (bit_pos % 8)) % 8; -} - -// Returns true if the opcode has a fixed number of operands. May return a -// false negative. -bool MarkvCodec::OpcodeHasFixedNumberOfOperands(SpvOp opcode) const { - switch (opcode) { - // TODO(atgoo@github.com) This is not a complete list. - case SpvOpNop: - case SpvOpName: - case SpvOpUndef: - case SpvOpSizeOf: - case SpvOpLine: - case SpvOpNoLine: - case SpvOpDecorationGroup: - case SpvOpExtension: - case SpvOpExtInstImport: - case SpvOpMemoryModel: - case SpvOpCapability: - case SpvOpTypeVoid: - case SpvOpTypeBool: - case SpvOpTypeInt: - case SpvOpTypeFloat: - case SpvOpTypeVector: - case SpvOpTypeMatrix: - case SpvOpTypeSampler: - case SpvOpTypeSampledImage: - case SpvOpTypeArray: - case SpvOpTypePointer: - case SpvOpConstantTrue: - case SpvOpConstantFalse: - case SpvOpLabel: - case SpvOpBranch: - case SpvOpFunction: - case SpvOpFunctionParameter: - case SpvOpFunctionEnd: - case SpvOpBitcast: - case SpvOpCopyObject: - case SpvOpTranspose: - 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: - return true; - default: - break; - } - return false; -} - -void MarkvCodec::ProcessCurInstruction() { - instructions_.emplace_back(new val::Instruction(&inst_)); - - const SpvOp opcode = SpvOp(inst_.opcode); - - if (inst_.result_id) { - id_to_def_instruction_.emplace(inst_.result_id, instructions_.back().get()); - - // Collect ids local to the current function. - if (cur_function_id_) { - ids_local_to_cur_function_.push_back(inst_.result_id); - } - - // Starting new function. - if (opcode == SpvOpFunction) { - cur_function_id_ = inst_.result_id; - cur_function_return_type_ = inst_.type_id; - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - multi_mtf_.Insert(GetMtfFunctionWithReturnType(inst_.type_id), - inst_.result_id); - } - - // Store function parameter types in a queue, so that we know which types - // to expect in the following OpFunctionParameter instructions. - const val::Instruction* def_inst = FindDef(inst_.words[4]); - assert(def_inst); - assert(def_inst->opcode() == SpvOpTypeFunction); - for (uint32_t i = 3; i < def_inst->words().size(); ++i) { - remaining_function_parameter_types_.push_back(def_inst->word(i)); - } - } - } - - // Remove local ids from MTFs if function end. - if (opcode == SpvOpFunctionEnd) { - cur_function_id_ = 0; - for (uint32_t id : ids_local_to_cur_function_) multi_mtf_.RemoveFromAll(id); - ids_local_to_cur_function_.clear(); - assert(remaining_function_parameter_types_.empty()); - } - - if (!inst_.result_id) return; - - { - // Save the result ID to type ID mapping. - // In the grammar, type ID always appears before result ID. - // A regular value maps to its type. Some instructions (e.g. OpLabel) - // have no type Id, and will map to 0. The result Id for a - // type-generating instruction (e.g. OpTypeInt) maps to itself. - auto insertion_result = id_to_type_id_.emplace( - inst_.result_id, spvOpcodeGeneratesType(SpvOp(inst_.opcode)) - ? inst_.result_id - : inst_.type_id); - (void)insertion_result; - assert(insertion_result.second); - } - - // Add result_id to MTFs. - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - switch (opcode) { - case SpvOpTypeFloat: - case SpvOpTypeInt: - case SpvOpTypeBool: - case SpvOpTypeVector: - case SpvOpTypePointer: - case SpvOpExtInstImport: - case SpvOpTypeSampledImage: - case SpvOpTypeImage: - case SpvOpTypeSampler: - multi_mtf_.Insert(GetMtfIdGeneratedByOpcode(opcode), inst_.result_id); - break; - default: - break; - } - - if (spvOpcodeIsComposite(opcode)) { - multi_mtf_.Insert(kMtfTypeComposite, inst_.result_id); - } - - if (opcode == SpvOpLabel) { - multi_mtf_.InsertOrPromote(kMtfLabel, inst_.result_id); - } - - if (opcode == SpvOpTypeInt) { - multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); - multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); - } - - if (opcode == SpvOpTypeFloat) { - multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); - multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); - } - - if (opcode == SpvOpTypeBool) { - multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); - multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); - } - - if (opcode == SpvOpTypeVector) { - const uint32_t component_type_id = inst_.words[2]; - const uint32_t size = inst_.words[3]; - if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeFloat), - component_type_id)) { - multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); - } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeInt), - component_type_id)) { - multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); - } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeBool), - component_type_id)) { - multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); - } - multi_mtf_.Insert(GetMtfTypeVectorOfSize(size), inst_.result_id); - } - - if (inst_.opcode == SpvOpTypeFunction) { - const uint32_t return_type = inst_.words[2]; - multi_mtf_.Insert(kMtfTypeReturnedByFunction, return_type); - multi_mtf_.Insert(GetMtfFunctionTypeWithReturnType(return_type), - inst_.result_id); - } - - if (inst_.type_id) { - const val::Instruction* type_inst = FindDef(inst_.type_id); - assert(type_inst); - - multi_mtf_.Insert(kMtfObject, inst_.result_id); - - multi_mtf_.Insert(GetMtfIdOfType(inst_.type_id), inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, inst_.type_id)) { - multi_mtf_.Insert(kMtfFloatScalarOrVector, inst_.result_id); - } - - if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, inst_.type_id)) - multi_mtf_.Insert(kMtfIntScalarOrVector, inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, inst_.type_id)) - multi_mtf_.Insert(kMtfBoolScalarOrVector, inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeComposite, inst_.type_id)) - multi_mtf_.Insert(kMtfComposite, inst_.result_id); - - switch (type_inst->opcode()) { - case SpvOpTypeInt: - case SpvOpTypeBool: - case SpvOpTypePointer: - case SpvOpTypeVector: - case SpvOpTypeImage: - case SpvOpTypeSampledImage: - case SpvOpTypeSampler: - multi_mtf_.Insert( - GetMtfIdWithTypeGeneratedByOpcode(type_inst->opcode()), - inst_.result_id); - break; - default: - break; - } - - if (type_inst->opcode() == SpvOpTypeVector) { - const uint32_t component_type = type_inst->word(2); - multi_mtf_.Insert(GetMtfVectorOfComponentType(component_type), - inst_.result_id); - } - - if (type_inst->opcode() == SpvOpTypePointer) { - assert(type_inst->operands().size() > 2); - assert(type_inst->words().size() > type_inst->operands()[2].offset); - const uint32_t data_type = - type_inst->word(type_inst->operands()[2].offset); - multi_mtf_.Insert(GetMtfPointerToType(data_type), inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeComposite, data_type)) - multi_mtf_.Insert(kMtfTypePointerToComposite, inst_.result_id); - } - } - - if (spvOpcodeGeneratesType(opcode)) { - if (opcode != SpvOpTypeFunction) { - multi_mtf_.Insert(kMtfTypeNonFunction, inst_.result_id); - } - } - } - - if (model_->AnyDescriptorHasCodingScheme()) { - const uint32_t long_descriptor = - long_id_descriptors_.ProcessInstruction(inst_); - if (model_->DescriptorHasCodingScheme(long_descriptor)) - multi_mtf_.Insert(GetMtfLongIdDescriptor(long_descriptor), - inst_.result_id); - } - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - const uint32_t short_descriptor = - short_id_descriptors_.ProcessInstruction(inst_); - multi_mtf_.Insert(GetMtfShortIdDescriptor(short_descriptor), - inst_.result_id); - } -} - -uint64_t MarkvCodec::GetRuleBasedMtf() { - // This function is only called for id operands (but not result ids). - assert(spvIsIdType(operand_.type) || - operand_.type == SPV_OPERAND_TYPE_OPTIONAL_ID); - assert(operand_.type != SPV_OPERAND_TYPE_RESULT_ID); - - const SpvOp opcode = static_cast(inst_.opcode); - - // All operand slots which expect label id. - if ((inst_.opcode == SpvOpLoopMerge && operand_index_ <= 1) || - (inst_.opcode == SpvOpSelectionMerge && operand_index_ == 0) || - (inst_.opcode == SpvOpBranch && operand_index_ == 0) || - (inst_.opcode == SpvOpBranchConditional && - (operand_index_ == 1 || operand_index_ == 2)) || - (inst_.opcode == SpvOpPhi && operand_index_ >= 3 && - operand_index_ % 2 == 1) || - (inst_.opcode == SpvOpSwitch && operand_index_ > 0)) { - return kMtfLabel; - } - - switch (opcode) { - case SpvOpFAdd: - case SpvOpFSub: - case SpvOpFMul: - case SpvOpFDiv: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpFNegate: { - if (operand_index_ == 0) return kMtfTypeFloatScalarOrVector; - return GetMtfIdOfType(inst_.type_id); - } - - case SpvOpISub: - case SpvOpIAdd: - case SpvOpIMul: - case SpvOpSDiv: - case SpvOpUDiv: - case SpvOpSMod: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSNegate: { - if (operand_index_ == 0) return kMtfTypeIntScalarOrVector; - - return kMtfIntScalarOrVector; - } - - // TODO(atgoo@github.com) Add OpConvertFToU and other opcodes. - - case SpvOpFOrdEqual: - case SpvOpFUnordEqual: - case SpvOpFOrdNotEqual: - case SpvOpFUnordNotEqual: - case SpvOpFOrdLessThan: - case SpvOpFUnordLessThan: - case SpvOpFOrdGreaterThan: - case SpvOpFUnordGreaterThan: - case SpvOpFOrdLessThanEqual: - case SpvOpFUnordLessThanEqual: - case SpvOpFOrdGreaterThanEqual: - case SpvOpFUnordGreaterThanEqual: { - if (operand_index_ == 0) return kMtfTypeBoolScalarOrVector; - if (operand_index_ == 2) return kMtfFloatScalarOrVector; - if (operand_index_ == 3) { - const uint32_t first_operand_id = GetInstWords()[3]; - const uint32_t first_operand_type = id_to_type_id_.at(first_operand_id); - return GetMtfIdOfType(first_operand_type); - } - break; - } - - case SpvOpVectorShuffle: { - if (operand_index_ == 0) { - assert(inst_.num_operands > 4); - return GetMtfTypeVectorOfSize(inst_.num_operands - 4); - } - - assert(inst_.type_id); - if (operand_index_ == 2 || operand_index_ == 3) - return GetMtfVectorOfComponentType( - GetVectorComponentType(inst_.type_id)); - break; - } - - case SpvOpVectorTimesScalar: { - if (operand_index_ == 0) { - // TODO(atgoo@github.com) Could be narrowed to vector of floats. - return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); - } - - assert(inst_.type_id); - if (operand_index_ == 2) return GetMtfIdOfType(inst_.type_id); - if (operand_index_ == 3) - return GetMtfIdOfType(GetVectorComponentType(inst_.type_id)); - break; - } - - case SpvOpDot: { - if (operand_index_ == 0) return GetMtfIdGeneratedByOpcode(SpvOpTypeFloat); - - assert(inst_.type_id); - if (operand_index_ == 2) - return GetMtfVectorOfComponentType(inst_.type_id); - if (operand_index_ == 3) { - const uint32_t vector_id = GetInstWords()[3]; - const uint32_t vector_type = id_to_type_id_.at(vector_id); - return GetMtfIdOfType(vector_type); - } - break; - } - - case SpvOpTypeVector: { - if (operand_index_ == 1) { - return kMtfTypeScalar; - } - break; - } - - case SpvOpTypeMatrix: { - if (operand_index_ == 1) { - return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); - } - break; - } - - case SpvOpTypePointer: { - if (operand_index_ == 2) { - return kMtfTypeNonFunction; - } - break; - } - - case SpvOpTypeStruct: { - if (operand_index_ >= 1) { - return kMtfTypeNonFunction; - } - break; - } - - case SpvOpTypeFunction: { - if (operand_index_ == 1) { - return kMtfTypeNonFunction; - } - - if (operand_index_ >= 2) { - return kMtfTypeNonFunction; - } - break; - } - - case SpvOpLoad: { - if (operand_index_ == 0) return kMtfTypeNonFunction; - - if (operand_index_ == 2) { - assert(inst_.type_id); - return GetMtfPointerToType(inst_.type_id); - } - break; - } - - case SpvOpStore: { - if (operand_index_ == 0) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypePointer); - if (operand_index_ == 1) { - const uint32_t pointer_id = GetInstWords()[1]; - const uint32_t pointer_type = id_to_type_id_.at(pointer_id); - const val::Instruction* pointer_inst = FindDef(pointer_type); - assert(pointer_inst); - assert(pointer_inst->opcode() == SpvOpTypePointer); - const uint32_t data_type = - pointer_inst->word(pointer_inst->operands()[2].offset); - return GetMtfIdOfType(data_type); - } - break; - } - - case SpvOpVariable: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); - break; - } - - case SpvOpAccessChain: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); - if (operand_index_ == 2) return kMtfTypePointerToComposite; - if (operand_index_ >= 3) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeInt); - break; - } - - case SpvOpCompositeConstruct: { - if (operand_index_ == 0) return kMtfTypeComposite; - if (operand_index_ >= 2) { - const uint32_t composite_type = GetInstWords()[1]; - if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, composite_type)) - return kMtfFloatScalarOrVector; - if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, composite_type)) - return kMtfIntScalarOrVector; - if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, composite_type)) - return kMtfBoolScalarOrVector; - } - break; - } - - case SpvOpCompositeExtract: { - if (operand_index_ == 2) return kMtfComposite; - break; - } - - case SpvOpConstantComposite: { - if (operand_index_ == 0) return kMtfTypeComposite; - if (operand_index_ >= 2) { - const val::Instruction* composite_type_inst = FindDef(inst_.type_id); - assert(composite_type_inst); - if (composite_type_inst->opcode() == SpvOpTypeVector) { - return GetMtfIdOfType(composite_type_inst->word(2)); - } - } - break; - } - - case SpvOpExtInst: { - if (operand_index_ == 2) - return GetMtfIdGeneratedByOpcode(SpvOpExtInstImport); - if (operand_index_ >= 4) { - const uint32_t return_type = GetInstWords()[1]; - const uint32_t ext_inst_type = inst_.ext_inst_type; - const uint32_t ext_inst_index = GetInstWords()[4]; - // TODO(atgoo@github.com) The list of extended instructions is - // incomplete. Only common instructions and low-hanging fruits listed. - if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) { - switch (ext_inst_index) { - case GLSLstd450FAbs: - case GLSLstd450FClamp: - case GLSLstd450FMax: - case GLSLstd450FMin: - case GLSLstd450FMix: - case GLSLstd450Step: - case GLSLstd450SmoothStep: - case GLSLstd450Fma: - case GLSLstd450Pow: - case GLSLstd450Exp: - case GLSLstd450Exp2: - case GLSLstd450Log: - case GLSLstd450Log2: - case GLSLstd450Sqrt: - case GLSLstd450InverseSqrt: - case GLSLstd450Fract: - case GLSLstd450Floor: - case GLSLstd450Ceil: - case GLSLstd450Radians: - case GLSLstd450Degrees: - case GLSLstd450Sin: - case GLSLstd450Cos: - case GLSLstd450Tan: - case GLSLstd450Sinh: - case GLSLstd450Cosh: - case GLSLstd450Tanh: - case GLSLstd450Asin: - case GLSLstd450Acos: - case GLSLstd450Atan: - case GLSLstd450Atan2: - case GLSLstd450Asinh: - case GLSLstd450Acosh: - case GLSLstd450Atanh: - case GLSLstd450MatrixInverse: - case GLSLstd450Cross: - case GLSLstd450Normalize: - case GLSLstd450Reflect: - case GLSLstd450FaceForward: - return GetMtfIdOfType(return_type); - case GLSLstd450Length: - case GLSLstd450Distance: - case GLSLstd450Refract: - return kMtfFloatScalarOrVector; - default: - break; - } - } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) { - switch (ext_inst_index) { - case OpenCLLIB::Fabs: - case OpenCLLIB::FClamp: - case OpenCLLIB::Fmax: - case OpenCLLIB::Fmin: - case OpenCLLIB::Step: - case OpenCLLIB::Smoothstep: - case OpenCLLIB::Fma: - case OpenCLLIB::Pow: - case OpenCLLIB::Exp: - case OpenCLLIB::Exp2: - case OpenCLLIB::Log: - case OpenCLLIB::Log2: - case OpenCLLIB::Sqrt: - case OpenCLLIB::Rsqrt: - case OpenCLLIB::Fract: - case OpenCLLIB::Floor: - case OpenCLLIB::Ceil: - case OpenCLLIB::Radians: - case OpenCLLIB::Degrees: - case OpenCLLIB::Sin: - case OpenCLLIB::Cos: - case OpenCLLIB::Tan: - case OpenCLLIB::Sinh: - case OpenCLLIB::Cosh: - case OpenCLLIB::Tanh: - case OpenCLLIB::Asin: - case OpenCLLIB::Acos: - case OpenCLLIB::Atan: - case OpenCLLIB::Atan2: - case OpenCLLIB::Asinh: - case OpenCLLIB::Acosh: - case OpenCLLIB::Atanh: - case OpenCLLIB::Cross: - case OpenCLLIB::Normalize: - return GetMtfIdOfType(return_type); - case OpenCLLIB::Length: - case OpenCLLIB::Distance: - return kMtfFloatScalarOrVector; - default: - break; - } - } - } - break; - } - - case SpvOpFunction: { - if (operand_index_ == 0) return kMtfTypeReturnedByFunction; - - if (operand_index_ == 3) { - const uint32_t return_type = GetInstWords()[1]; - return GetMtfFunctionTypeWithReturnType(return_type); - } - break; - } - - case SpvOpFunctionCall: { - if (operand_index_ == 0) return kMtfTypeReturnedByFunction; - - if (operand_index_ == 2) { - const uint32_t return_type = GetInstWords()[1]; - return GetMtfFunctionWithReturnType(return_type); - } - - if (operand_index_ >= 3) { - const uint32_t function_id = GetInstWords()[3]; - const val::Instruction* function_inst = FindDef(function_id); - if (!function_inst) return kMtfObject; - - assert(function_inst->opcode() == SpvOpFunction); - - const uint32_t function_type_id = function_inst->word(4); - const val::Instruction* function_type_inst = FindDef(function_type_id); - assert(function_type_inst); - assert(function_type_inst->opcode() == SpvOpTypeFunction); - - const uint32_t argument_type = function_type_inst->word(operand_index_); - return GetMtfIdOfType(argument_type); - } - break; - } - - case SpvOpReturnValue: { - if (operand_index_ == 0) return GetMtfIdOfType(cur_function_return_type_); - break; - } - - case SpvOpBranchConditional: { - if (operand_index_ == 0) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeBool); - break; - } - - case SpvOpSampledImage: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypeSampledImage); - if (operand_index_ == 2) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeImage); - if (operand_index_ == 3) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampler); - break; - } - - case SpvOpImageSampleImplicitLod: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); - if (operand_index_ == 2) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampledImage); - if (operand_index_ == 3) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeVector); - break; - } - - default: - break; - } - - return kMtfNone; -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/comp/markv_codec.h b/3rdparty/spirv-tools/source/comp/markv_codec.h deleted file mode 100644 index f313d6178..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_codec.h +++ /dev/null @@ -1,337 +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_COMP_MARKV_CODEC_H_ -#define SOURCE_COMP_MARKV_CODEC_H_ - -#include -#include -#include -#include - -#include "source/assembly_grammar.h" -#include "source/comp/huffman_codec.h" -#include "source/comp/markv_model.h" -#include "source/comp/move_to_front.h" -#include "source/diagnostic.h" -#include "source/id_descriptor.h" - -#include "source/val/instruction.h" - -// Base class for MARK-V encoder and decoder. Contains common functionality -// such as: -// - Validator connection and validation state. -// - SPIR-V grammar and helper functions. - -namespace spvtools { -namespace comp { - -class MarkvLogger; - -// Handles for move-to-front sequences. Enums which end with "Begin" define -// handle spaces which start at that value and span 16 or 32 bit wide. -enum : uint64_t { - kMtfNone = 0, - // All ids. - kMtfAll, - // All forward declared ids. - kMtfForwardDeclared, - // All type ids except for generated by OpTypeFunction. - kMtfTypeNonFunction, - // All labels. - kMtfLabel, - // All ids created by instructions which had type_id. - kMtfObject, - // All types generated by OpTypeFloat, OpTypeInt, OpTypeBool. - kMtfTypeScalar, - // All composite types. - kMtfTypeComposite, - // Boolean type or any vector type of it. - kMtfTypeBoolScalarOrVector, - // All float types or any vector floats type. - kMtfTypeFloatScalarOrVector, - // All int types or any vector int type. - kMtfTypeIntScalarOrVector, - // All types declared as return types in OpTypeFunction. - kMtfTypeReturnedByFunction, - // All composite objects. - kMtfComposite, - // All bool objects or vectors of bools. - kMtfBoolScalarOrVector, - // All float objects or vectors of float. - kMtfFloatScalarOrVector, - // All int objects or vectors of int. - kMtfIntScalarOrVector, - // All pointer types which point to composited. - kMtfTypePointerToComposite, - // Used by EncodeMtfRankHuffman. - kMtfGenericNonZeroRank, - // Handle space for ids of specific type. - kMtfIdOfTypeBegin = 0x10000, - // Handle space for ids generated by specific opcode. - kMtfIdGeneratedByOpcode = 0x20000, - // Handle space for ids of objects with type generated by specific opcode. - kMtfIdWithTypeGeneratedByOpcodeBegin = 0x30000, - // All vectors of specific component type. - kMtfVectorOfComponentTypeBegin = 0x40000, - // All vector types of specific size. - kMtfTypeVectorOfSizeBegin = 0x50000, - // All pointer types to specific type. - kMtfPointerToTypeBegin = 0x60000, - // All function types which return specific type. - kMtfFunctionTypeWithReturnTypeBegin = 0x70000, - // All function objects which return specific type. - kMtfFunctionWithReturnTypeBegin = 0x80000, - // Short id descriptor space (max 16-bit). - kMtfShortIdDescriptorSpaceBegin = 0x90000, - // Long id descriptor space (32-bit). - kMtfLongIdDescriptorSpaceBegin = 0x100000000, -}; - -class MarkvCodec { - public: - static const uint32_t kMarkvMagicNumber; - - // Mtf ranks smaller than this are encoded with Huffman coding. - static const uint32_t kMtfSmallestRankEncodedByValue; - - // Signals that the mtf rank is too large to be encoded with Huffman. - static const uint32_t kMtfRankEncodedByValueSignal; - - static const uint32_t kShortDescriptorNumBits; - - static const size_t kByteBreakAfterInstIfLessThanUntilNextByte; - - static uint32_t GetMarkvVersion(); - - virtual ~MarkvCodec(); - - protected: - struct MarkvHeader { - MarkvHeader(); - - uint32_t magic_number; - uint32_t markv_version; - // Magic number to identify or verify MarkvModel used for encoding. - uint32_t markv_model = 0; - uint32_t markv_length_in_bits = 0; - uint32_t spirv_version = 0; - uint32_t spirv_generator = 0; - }; - - // |model| is owned by the caller, must be not null and valid during the - // lifetime of the codec. - MarkvCodec(spv_const_context context, spv_validator_options validator_options, - const MarkvModel* model); - - // Returns instruction which created |id| or nullptr if such instruction was - // not registered. - const val::Instruction* FindDef(uint32_t id) const { - const auto it = id_to_def_instruction_.find(id); - if (it == id_to_def_instruction_.end()) return nullptr; - return it->second; - } - - size_t GetNumBitsToNextByte(size_t bit_pos) const; - bool OpcodeHasFixedNumberOfOperands(SpvOp opcode) const; - - // Returns type id of vector type component. - uint32_t GetVectorComponentType(uint32_t vector_type_id) const { - const val::Instruction* type_inst = FindDef(vector_type_id); - assert(type_inst); - assert(type_inst->opcode() == SpvOpTypeVector); - - const uint32_t component_type = - type_inst->word(type_inst->operands()[1].offset); - return component_type; - } - - // Returns mtf handle for ids of given type. - uint64_t GetMtfIdOfType(uint32_t type_id) const { - return kMtfIdOfTypeBegin + type_id; - } - - // Returns mtf handle for ids generated by given opcode. - uint64_t GetMtfIdGeneratedByOpcode(SpvOp opcode) const { - return kMtfIdGeneratedByOpcode + opcode; - } - - // Returns mtf handle for ids of type generated by given opcode. - uint64_t GetMtfIdWithTypeGeneratedByOpcode(SpvOp opcode) const { - return kMtfIdWithTypeGeneratedByOpcodeBegin + opcode; - } - - // Returns mtf handle for vectors of specific component type. - uint64_t GetMtfVectorOfComponentType(uint32_t type_id) const { - return kMtfVectorOfComponentTypeBegin + type_id; - } - - // Returns mtf handle for vector type of specific size. - uint64_t GetMtfTypeVectorOfSize(uint32_t size) const { - return kMtfTypeVectorOfSizeBegin + size; - } - - // Returns mtf handle for pointers to specific size. - uint64_t GetMtfPointerToType(uint32_t type_id) const { - return kMtfPointerToTypeBegin + type_id; - } - - // Returns mtf handle for function types with given return type. - uint64_t GetMtfFunctionTypeWithReturnType(uint32_t type_id) const { - return kMtfFunctionTypeWithReturnTypeBegin + type_id; - } - - // Returns mtf handle for functions with given return type. - uint64_t GetMtfFunctionWithReturnType(uint32_t type_id) const { - return kMtfFunctionWithReturnTypeBegin + type_id; - } - - // Returns mtf handle for the given long id descriptor. - uint64_t GetMtfLongIdDescriptor(uint32_t descriptor) const { - return kMtfLongIdDescriptorSpaceBegin + descriptor; - } - - // Returns mtf handle for the given short id descriptor. - uint64_t GetMtfShortIdDescriptor(uint32_t descriptor) const { - return kMtfShortIdDescriptorSpaceBegin + descriptor; - } - - // Process data from the current instruction. This would update MTFs and - // other data containers. - void ProcessCurInstruction(); - - // Returns move-to-front handle to be used for the current operand slot. - // Mtf handle is chosen based on a set of rules defined by SPIR-V grammar. - uint64_t GetRuleBasedMtf(); - - // Returns words of the current instruction. Decoder has a different - // implementation and the array is valid only until the previously decoded - // word. - virtual const uint32_t* GetInstWords() const { return inst_.words; } - - // Returns the opcode of the previous instruction. - SpvOp GetPrevOpcode() const { - if (instructions_.empty()) return SpvOpNop; - - return instructions_.back()->opcode(); - } - - // Returns diagnostic stream, position index is set to instruction number. - DiagnosticStream Diag(spv_result_t error_code) const { - return DiagnosticStream({0, 0, instructions_.size()}, context_->consumer, - "", error_code); - } - - // Returns current id bound. - uint32_t GetIdBound() const { return id_bound_; } - - // Sets current id bound, expected to be no lower than the previous one. - void SetIdBound(uint32_t id_bound) { - assert(id_bound >= id_bound_); - id_bound_ = id_bound; - } - - // Returns Huffman codec for ranks of the mtf with given |handle|. - // Different mtfs can use different rank distributions. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetMtfHuffmanCodec(uint64_t handle) const { - const auto it = mtf_huffman_codecs_.find(handle); - if (it == mtf_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Promotes id in all move-to-front sequences if ids can be shared by multiple - // sequences. - void PromoteIfNeeded(uint32_t id) { - if (!model_->AnyDescriptorHasCodingScheme() && - model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - // Move-to-front sequences do not share ids. Nothing to do. - return; - } - multi_mtf_.Promote(id); - } - - spv_validator_options validator_options_ = nullptr; - const AssemblyGrammar grammar_; - MarkvHeader header_; - - // MARK-V model, not owned. - const MarkvModel* model_ = nullptr; - - // Current instruction, current operand and current operand index. - spv_parsed_instruction_t inst_; - spv_parsed_operand_t operand_; - uint32_t operand_index_; - - // Maps a result ID to its type ID. By convention: - // - a result ID that is a type definition maps to itself. - // - a result ID without a type maps to 0. (E.g. for OpLabel) - std::unordered_map id_to_type_id_; - - // Container for all move-to-front sequences. - MultiMoveToFront multi_mtf_; - - // Id of the current function or zero if outside of function. - uint32_t cur_function_id_ = 0; - - // Return type of the current function. - uint32_t cur_function_return_type_ = 0; - - // Remaining function parameter types. This container is filled on OpFunction, - // and drained on OpFunctionParameter. - std::list remaining_function_parameter_types_; - - // List of ids local to the current function. - std::vector ids_local_to_cur_function_; - - // List of instructions in the order they are given in the module. - std::vector> instructions_; - - // Container/computer for long (32-bit) id descriptors. - IdDescriptorCollection long_id_descriptors_; - - // Container/computer for short id descriptors. - // Short descriptors are stored in uint32_t, but their actual bit width is - // defined with kShortDescriptorNumBits. - // It doesn't seem logical to have a different computer for short id - // descriptors, since one could actually map/truncate long descriptors. - // But as short descriptors have collisions, the efficiency of - // compression depends on the collision pattern, and short descriptors - // produced by function ShortHashU32Array have been empirically proven to - // produce better results. - IdDescriptorCollection short_id_descriptors_; - - // Huffman codecs for move-to-front ranks. The map key is mtf handle. Doesn't - // need to contain a different codec for every handle as most use one and the - // same. - std::map>> - mtf_huffman_codecs_; - - // If not nullptr, codec will log comments on the compression process. - std::unique_ptr logger_; - - spv_const_context context_ = nullptr; - - private: - // Maps result id to the instruction which defined it. - std::unordered_map id_to_def_instruction_; - - uint32_t id_bound_ = 1; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_CODEC_H_ diff --git a/3rdparty/spirv-tools/source/comp/markv_decoder.cpp b/3rdparty/spirv-tools/source/comp/markv_decoder.cpp deleted file mode 100644 index 22115831d..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_decoder.cpp +++ /dev/null @@ -1,925 +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/comp/markv_decoder.h" - -#include -#include -#include - -#include "source/ext_inst.h" -#include "source/opcode.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { - -spv_result_t MarkvDecoder::DecodeNonIdWord(uint32_t* word) { - auto* codec = model_->GetNonIdWordHuffmanCodec(inst_.opcode, operand_index_); - - if (codec) { - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to decode non-id word with Huffman"; - - if (decoded_value != MarkvModel::GetMarkvNoneOfTheAbove()) { - // The word decoded successfully. - *word = uint32_t(decoded_value); - assert(*word == decoded_value); - return SPV_SUCCESS; - } - - // Received kMarkvNoneOfTheAbove signal, use fallback decoding. - } - - const size_t chunk_length = - model_->GetOperandVariableWidthChunkLength(operand_.type); - if (chunk_length) { - if (!reader_.ReadVariableWidthU32(word, chunk_length)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to decode non-id word with varint"; - } else { - if (!reader_.ReadUnencoded(word)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read unencoded non-id word"; - } - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeOpcodeAndNumberOfOperands( - uint32_t* opcode, uint32_t* num_operands) { - // First try to use the Markov chain codec. - auto* codec = - model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(GetPrevOpcode()); - if (codec) { - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode opcode_and_num_operands, previous opcode is " - << spvOpcodeString(GetPrevOpcode()); - - if (decoded_value != MarkvModel::GetMarkvNoneOfTheAbove()) { - // The word was successfully decoded. - *opcode = uint32_t(decoded_value & 0xFFFF); - *num_operands = uint32_t(decoded_value >> 16); - return SPV_SUCCESS; - } - - // Received kMarkvNoneOfTheAbove signal, use fallback decoding. - } - - // Fallback to base-rate codec. - codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(SpvOpNop); - assert(codec); - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode opcode_and_num_operands with global codec"; - - if (decoded_value == MarkvModel::GetMarkvNoneOfTheAbove()) { - // Received kMarkvNoneOfTheAbove signal, fallback further. - return SPV_UNSUPPORTED; - } - - *opcode = uint32_t(decoded_value & 0xFFFF); - *num_operands = uint32_t(decoded_value >> 16); - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeMtfRankHuffman(uint64_t mtf, - uint32_t fallback_method, - uint32_t* rank) { - const auto* codec = GetMtfHuffmanCodec(mtf); - if (!codec) { - assert(fallback_method != kMtfNone); - codec = GetMtfHuffmanCodec(fallback_method); - } - - if (!codec) return Diag(SPV_ERROR_INTERNAL) << "No codec to decode MTF rank"; - - uint32_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) << "Failed to decode MTF rank with Huffman"; - - if (decoded_value == kMtfRankEncodedByValueSignal) { - // Decode by value. - if (!reader_.ReadVariableWidthU32(rank, model_->mtf_rank_chunk_length())) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode MTF rank with varint"; - *rank += MarkvCodec::kMtfSmallestRankEncodedByValue; - } else { - // Decode using Huffman coding. - assert(decoded_value < MarkvCodec::kMtfSmallestRankEncodedByValue); - *rank = decoded_value; - } - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeIdWithDescriptor(uint32_t* id) { - auto* codec = - model_->GetIdDescriptorHuffmanCodec(inst_.opcode, operand_index_); - - uint64_t mtf = kMtfNone; - if (codec) { - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode descriptor with Huffman"; - - if (decoded_value != MarkvModel::GetMarkvNoneOfTheAbove()) { - const uint32_t long_descriptor = uint32_t(decoded_value); - mtf = GetMtfLongIdDescriptor(long_descriptor); - } - } - - if (mtf == kMtfNone) { - if (model_->id_fallback_strategy() != - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - return SPV_UNSUPPORTED; - } - - uint64_t decoded_value = 0; - if (!reader_.ReadBits(&decoded_value, MarkvCodec::kShortDescriptorNumBits)) - return Diag(SPV_ERROR_INTERNAL) << "Failed to read short descriptor"; - const uint32_t short_descriptor = uint32_t(decoded_value); - if (short_descriptor == 0) { - // Forward declared id. - return SPV_UNSUPPORTED; - } - mtf = GetMtfShortIdDescriptor(short_descriptor); - } - - return DecodeExistingId(mtf, id); -} - -spv_result_t MarkvDecoder::DecodeExistingId(uint64_t mtf, uint32_t* id) { - assert(multi_mtf_.GetSize(mtf) > 0); - *id = 0; - - uint32_t rank = 0; - - if (multi_mtf_.GetSize(mtf) == 1) { - rank = 1; - } else { - const spv_result_t result = - DecodeMtfRankHuffman(mtf, kMtfGenericNonZeroRank, &rank); - if (result != SPV_SUCCESS) return result; - } - - assert(rank); - if (!multi_mtf_.ValueFromRank(mtf, rank, id)) - return Diag(SPV_ERROR_INTERNAL) << "MTF rank is out of bounds"; - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeRefId(uint32_t* id) { - { - const spv_result_t result = DecodeIdWithDescriptor(id); - if (result != SPV_UNSUPPORTED) return result; - } - - const bool can_forward_declare = spvOperandCanBeForwardDeclaredFunction( - SpvOp(inst_.opcode))(operand_index_); - uint32_t rank = 0; - *id = 0; - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - uint64_t mtf = GetRuleBasedMtf(); - if (mtf != kMtfNone && !can_forward_declare) { - return DecodeExistingId(mtf, id); - } - - if (mtf == kMtfNone) mtf = kMtfAll; - { - const spv_result_t result = DecodeMtfRankHuffman(mtf, kMtfAll, &rank); - if (result != SPV_SUCCESS) return result; - } - - if (rank == 0) { - // This is the first occurrence of a forward declared id. - *id = GetIdBound(); - SetIdBound(*id + 1); - multi_mtf_.Insert(kMtfAll, *id); - multi_mtf_.Insert(kMtfForwardDeclared, *id); - if (mtf != kMtfAll) multi_mtf_.Insert(mtf, *id); - } else { - if (!multi_mtf_.ValueFromRank(mtf, rank, id)) - return Diag(SPV_ERROR_INTERNAL) << "MTF rank out of bounds"; - } - } else { - assert(can_forward_declare); - - if (!reader_.ReadVariableWidthU32(&rank, model_->mtf_rank_chunk_length())) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode MTF rank with varint"; - - if (rank == 0) { - // This is the first occurrence of a forward declared id. - *id = GetIdBound(); - SetIdBound(*id + 1); - multi_mtf_.Insert(kMtfForwardDeclared, *id); - } else { - if (!multi_mtf_.ValueFromRank(kMtfForwardDeclared, rank, id)) - return Diag(SPV_ERROR_INTERNAL) << "MTF rank out of bounds"; - } - } - assert(*id); - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeTypeId() { - if (inst_.opcode == SpvOpFunctionParameter) { - assert(!remaining_function_parameter_types_.empty()); - inst_.type_id = remaining_function_parameter_types_.front(); - remaining_function_parameter_types_.pop_front(); - return SPV_SUCCESS; - } - - { - const spv_result_t result = DecodeIdWithDescriptor(&inst_.type_id); - if (result != SPV_UNSUPPORTED) return result; - } - - assert(model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased); - - uint64_t mtf = GetRuleBasedMtf(); - assert(!spvOperandCanBeForwardDeclaredFunction(SpvOp(inst_.opcode))( - operand_index_)); - - if (mtf == kMtfNone) { - mtf = kMtfTypeNonFunction; - // Function types should have been handled by GetRuleBasedMtf. - assert(inst_.opcode != SpvOpFunction); - } - - return DecodeExistingId(mtf, &inst_.type_id); -} - -spv_result_t MarkvDecoder::DecodeResultId() { - uint32_t rank = 0; - - const uint64_t num_still_forward_declared = - multi_mtf_.GetSize(kMtfForwardDeclared); - - if (num_still_forward_declared) { - // Some ids were forward declared. Check if this id is one of them. - uint64_t id_was_forward_declared; - if (!reader_.ReadBits(&id_was_forward_declared, 1)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read id_was_forward_declared flag"; - - if (id_was_forward_declared) { - if (!reader_.ReadVariableWidthU32(&rank, model_->mtf_rank_chunk_length())) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read MTF rank of forward declared id"; - - if (rank) { - // The id was forward declared, recover it from kMtfForwardDeclared. - if (!multi_mtf_.ValueFromRank(kMtfForwardDeclared, rank, - &inst_.result_id)) - return Diag(SPV_ERROR_INTERNAL) - << "Forward declared MTF rank is out of bounds"; - - // We can now remove the id from kMtfForwardDeclared. - if (!multi_mtf_.Remove(kMtfForwardDeclared, inst_.result_id)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to remove id from kMtfForwardDeclared"; - } - } - } - - if (inst_.result_id == 0) { - // The id was not forward declared, issue a new id. - inst_.result_id = GetIdBound(); - SetIdBound(inst_.result_id + 1); - } - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - if (!rank) { - multi_mtf_.Insert(kMtfAll, inst_.result_id); - } - } - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeLiteralNumber( - const spv_parsed_operand_t& operand) { - if (operand.number_bit_width <= 32) { - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - inst_words_.push_back(word); - } else { - assert(operand.number_bit_width <= 64); - uint64_t word = 0; - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - if (!reader_.ReadVariableWidthU64(&word, model_->u64_chunk_length())) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal U64"; - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int64_t val = 0; - if (!reader_.ReadVariableWidthS64(&val, model_->s64_chunk_length(), - model_->s64_block_exponent())) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal S64"; - std::memcpy(&word, &val, 8); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - if (!reader_.ReadUnencoded(&word)) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal F64"; - } else { - return Diag(SPV_ERROR_INTERNAL) << "Unsupported bit length"; - } - inst_words_.push_back(static_cast(word)); - inst_words_.push_back(static_cast(word >> 32)); - } - return SPV_SUCCESS; -} - -bool MarkvDecoder::ReadToByteBreak(size_t byte_break_if_less_than) { - const size_t num_bits_to_next_byte = - GetNumBitsToNextByte(reader_.GetNumReadBits()); - if (num_bits_to_next_byte == 0 || - num_bits_to_next_byte > byte_break_if_less_than) - return true; - - uint64_t bits = 0; - if (!reader_.ReadBits(&bits, num_bits_to_next_byte)) return false; - - assert(bits == 0); - if (bits != 0) return false; - - return true; -} - -spv_result_t MarkvDecoder::DecodeModule(std::vector* spirv_binary) { - const bool header_read_success = - reader_.ReadUnencoded(&header_.magic_number) && - reader_.ReadUnencoded(&header_.markv_version) && - reader_.ReadUnencoded(&header_.markv_model) && - reader_.ReadUnencoded(&header_.markv_length_in_bits) && - reader_.ReadUnencoded(&header_.spirv_version) && - reader_.ReadUnencoded(&header_.spirv_generator); - - if (!header_read_success) - return Diag(SPV_ERROR_INVALID_BINARY) << "Unable to read MARK-V header"; - - if (header_.markv_length_in_bits == 0) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Header markv_length_in_bits field is zero"; - - if (header_.magic_number != MarkvCodec::kMarkvMagicNumber) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary has incorrect magic number"; - - // TODO(atgoo@github.com): Print version strings. - if (header_.markv_version != MarkvCodec::GetMarkvVersion()) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary and the codec have different versions"; - - const uint32_t model_type = header_.markv_model >> 16; - const uint32_t model_version = header_.markv_model & 0xFFFF; - if (model_type != model_->model_type()) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary and the codec use different MARK-V models"; - - if (model_version != model_->model_version()) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary and the codec use different versions if the same " - << "MARK-V model"; - - spirv_.reserve(header_.markv_length_in_bits / 2); // Heuristic. - spirv_.resize(5, 0); - spirv_[0] = SpvMagicNumber; - spirv_[1] = header_.spirv_version; - spirv_[2] = header_.spirv_generator; - - if (logger_) { - reader_.SetCallback( - [this](const std::string& str) { logger_->AppendBitSequence(str); }); - } - - while (reader_.GetNumReadBits() < header_.markv_length_in_bits) { - inst_ = {}; - const spv_result_t decode_result = DecodeInstruction(); - if (decode_result != SPV_SUCCESS) return decode_result; - } - - if (validator_options_) { - spv_const_binary_t validation_binary = {spirv_.data(), spirv_.size()}; - const spv_result_t result = spvValidateWithOptions( - context_, validator_options_, &validation_binary, nullptr); - if (result != SPV_SUCCESS) return result; - } - - // Validate the decode binary - if (reader_.GetNumReadBits() != header_.markv_length_in_bits || - !reader_.OnlyZeroesLeft()) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary has wrong stated bit length " - << reader_.GetNumReadBits() << " " << header_.markv_length_in_bits; - } - - // Decoding of the module is finished, validation state should have correct - // id bound. - spirv_[3] = GetIdBound(); - - *spirv_binary = std::move(spirv_); - return SPV_SUCCESS; -} - -// TODO(atgoo@github.com): The implementation borrows heavily from -// Parser::parseOperand. -// Consider coupling them together in some way once MARK-V codec is more mature. -// For now it's better to keep the code independent for experimentation -// purposes. -spv_result_t MarkvDecoder::DecodeOperand( - size_t operand_offset, const spv_operand_type_t type, - spv_operand_pattern_t* expected_operands) { - const SpvOp opcode = static_cast(inst_.opcode); - - memset(&operand_, 0, sizeof(operand_)); - - assert((operand_offset >> 16) == 0); - operand_.offset = static_cast(operand_offset); - operand_.type = type; - - // Set default values, may be updated later. - operand_.number_kind = SPV_NUMBER_NONE; - operand_.number_bit_width = 0; - - const size_t first_word_index = inst_words_.size(); - - switch (type) { - case SPV_OPERAND_TYPE_RESULT_ID: { - const spv_result_t result = DecodeResultId(); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(inst_.result_id); - SetIdBound(std::max(GetIdBound(), inst_.result_id + 1)); - PromoteIfNeeded(inst_.result_id); - break; - } - - case SPV_OPERAND_TYPE_TYPE_ID: { - const spv_result_t result = DecodeTypeId(); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(inst_.type_id); - SetIdBound(std::max(GetIdBound(), inst_.type_id + 1)); - PromoteIfNeeded(inst_.type_id); - break; - } - - case SPV_OPERAND_TYPE_ID: - case SPV_OPERAND_TYPE_OPTIONAL_ID: - case SPV_OPERAND_TYPE_SCOPE_ID: - case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: { - uint32_t id = 0; - const spv_result_t result = DecodeRefId(&id); - if (result != SPV_SUCCESS) return result; - - if (id == 0) return Diag(SPV_ERROR_INVALID_BINARY) << "Decoded id is 0"; - - if (type == SPV_OPERAND_TYPE_ID || type == SPV_OPERAND_TYPE_OPTIONAL_ID) { - operand_.type = SPV_OPERAND_TYPE_ID; - - if (opcode == SpvOpExtInst && operand_.offset == 3) { - // The current word is the extended instruction set id. - // Set the extended instruction set type for the current - // instruction. - auto ext_inst_type_iter = import_id_to_ext_inst_type_.find(id); - if (ext_inst_type_iter == import_id_to_ext_inst_type_.end()) { - return Diag(SPV_ERROR_INVALID_ID) - << "OpExtInst set id " << id - << " does not reference an OpExtInstImport result Id"; - } - inst_.ext_inst_type = ext_inst_type_iter->second; - } - } - - inst_words_.push_back(id); - SetIdBound(std::max(GetIdBound(), id + 1)); - PromoteIfNeeded(id); - break; - } - - case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - - assert(SpvOpExtInst == opcode); - assert(inst_.ext_inst_type != SPV_EXT_INST_TYPE_NONE); - spv_ext_inst_desc ext_inst; - if (grammar_.lookupExtInst(inst_.ext_inst_type, word, &ext_inst)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid extended instruction number: " << word; - spvPushOperandTypes(ext_inst->operandTypes, expected_operands); - break; - } - - case SPV_OPERAND_TYPE_LITERAL_INTEGER: - case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: { - // These are regular single-word literal integer operands. - // Post-parsing validation should check the range of the parsed value. - operand_.type = SPV_OPERAND_TYPE_LITERAL_INTEGER; - // It turns out they are always unsigned integers! - operand_.number_kind = SPV_NUMBER_UNSIGNED_INT; - operand_.number_bit_width = 32; - - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - break; - } - - case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: - case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: { - operand_.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER; - if (opcode == SpvOpSwitch) { - // The literal operands have the same type as the value - // referenced by the selector Id. - const uint32_t selector_id = inst_words_.at(1); - const auto type_id_iter = id_to_type_id_.find(selector_id); - if (type_id_iter == id_to_type_id_.end() || type_id_iter->second == 0) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid OpSwitch: selector id " << selector_id - << " has no type"; - } - uint32_t type_id = type_id_iter->second; - - if (selector_id == type_id) { - // Recall that by convention, a result ID that is a type definition - // maps to itself. - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid OpSwitch: selector id " << selector_id - << " is a type, not a value"; - } - if (auto error = SetNumericTypeInfoForType(&operand_, type_id)) - return error; - if (operand_.number_kind != SPV_NUMBER_UNSIGNED_INT && - operand_.number_kind != SPV_NUMBER_SIGNED_INT) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid OpSwitch: selector id " << selector_id - << " is not a scalar integer"; - } - } else { - assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant); - // The literal number type is determined by the type Id for the - // constant. - assert(inst_.type_id); - if (auto error = SetNumericTypeInfoForType(&operand_, inst_.type_id)) - return error; - } - - if (auto error = DecodeLiteralNumber(operand_)) return error; - - break; - } - - case SPV_OPERAND_TYPE_LITERAL_STRING: - case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: { - operand_.type = SPV_OPERAND_TYPE_LITERAL_STRING; - std::vector str; - auto* codec = model_->GetLiteralStringHuffmanCodec(inst_.opcode); - - if (codec) { - std::string decoded_string; - const bool huffman_result = - codec->DecodeFromStream(GetReadBitCallback(), &decoded_string); - assert(huffman_result); - if (!huffman_result) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal string"; - - if (decoded_string != "kMarkvNoneOfTheAbove") { - std::copy(decoded_string.begin(), decoded_string.end(), - std::back_inserter(str)); - str.push_back('\0'); - } - } - - // The loop is expected to terminate once we encounter '\0' or exhaust - // the bit stream. - if (str.empty()) { - while (true) { - char ch = 0; - if (!reader_.ReadUnencoded(&ch)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal string"; - - str.push_back(ch); - - if (ch == '\0') break; - } - } - - while (str.size() % 4 != 0) str.push_back('\0'); - - inst_words_.resize(inst_words_.size() + str.size() / 4); - std::memcpy(&inst_words_[first_word_index], str.data(), str.size()); - - if (SpvOpExtInstImport == opcode) { - // Record the extended instruction type for the ID for this import. - // There is only one string literal argument to OpExtInstImport, - // so it's sufficient to guard this just on the opcode. - const spv_ext_inst_type_t ext_inst_type = - spvExtInstImportTypeGet(str.data()); - if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid extended instruction import '" << str.data() - << "'"; - } - // We must have parsed a valid result ID. It's a condition - // of the grammar, and we only accept non-zero result Ids. - assert(inst_.result_id); - const bool inserted = - import_id_to_ext_inst_type_.emplace(inst_.result_id, ext_inst_type) - .second; - (void)inserted; - assert(inserted); - } - break; - } - - case SPV_OPERAND_TYPE_CAPABILITY: - case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: - case SPV_OPERAND_TYPE_EXECUTION_MODEL: - case SPV_OPERAND_TYPE_ADDRESSING_MODEL: - case SPV_OPERAND_TYPE_MEMORY_MODEL: - case SPV_OPERAND_TYPE_EXECUTION_MODE: - case SPV_OPERAND_TYPE_STORAGE_CLASS: - case SPV_OPERAND_TYPE_DIMENSIONALITY: - case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE: - case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE: - case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT: - case SPV_OPERAND_TYPE_FP_ROUNDING_MODE: - case SPV_OPERAND_TYPE_LINKAGE_TYPE: - case SPV_OPERAND_TYPE_ACCESS_QUALIFIER: - case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER: - case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE: - case SPV_OPERAND_TYPE_DECORATION: - case SPV_OPERAND_TYPE_BUILT_IN: - case SPV_OPERAND_TYPE_GROUP_OPERATION: - case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: - case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: { - // A single word that is a plain enum value. - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - - // Map an optional operand type to its corresponding concrete type. - if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER) - operand_.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER; - - spv_operand_desc entry; - if (grammar_.lookupOperand(type, word, &entry)) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid " << spvOperandTypeStr(operand_.type) - << " operand: " << word; - } - - // Prepare to accept operands to this operand, if needed. - spvPushOperandTypes(entry->operandTypes, expected_operands); - break; - } - - case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: - case SPV_OPERAND_TYPE_FUNCTION_CONTROL: - case SPV_OPERAND_TYPE_LOOP_CONTROL: - case SPV_OPERAND_TYPE_IMAGE: - case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: - case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: - case SPV_OPERAND_TYPE_SELECTION_CONTROL: { - // This operand is a mask. - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - - // Map an optional operand type to its corresponding concrete type. - if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE) - operand_.type = SPV_OPERAND_TYPE_IMAGE; - else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS) - operand_.type = SPV_OPERAND_TYPE_MEMORY_ACCESS; - - // Check validity of set mask bits. Also prepare for operands for those - // masks if they have any. To get operand order correct, scan from - // MSB to LSB since we can only prepend operands to a pattern. - // The only case in the grammar where you have more than one mask bit - // having an operand is for image operands. See SPIR-V 3.14 Image - // Operands. - uint32_t remaining_word = word; - for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) { - if (remaining_word & mask) { - spv_operand_desc entry; - if (grammar_.lookupOperand(type, mask, &entry)) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid " << spvOperandTypeStr(operand_.type) - << " operand: " << word << " has invalid mask component " - << mask; - } - remaining_word ^= mask; - spvPushOperandTypes(entry->operandTypes, expected_operands); - } - } - if (word == 0) { - // An all-zeroes mask *might* also be valid. - spv_operand_desc entry; - if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) { - // Prepare for its operands, if any. - spvPushOperandTypes(entry->operandTypes, expected_operands); - } - } - break; - } - default: - return Diag(SPV_ERROR_INVALID_BINARY) - << "Internal error: Unhandled operand type: " << type; - } - - operand_.num_words = uint16_t(inst_words_.size() - first_word_index); - - assert(spvOperandIsConcrete(operand_.type)); - - parsed_operands_.push_back(operand_); - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeInstruction() { - parsed_operands_.clear(); - inst_words_.clear(); - - // Opcode/num_words placeholder, the word will be filled in later. - inst_words_.push_back(0); - - bool num_operands_still_unknown = true; - { - uint32_t opcode = 0; - uint32_t num_operands = 0; - - const spv_result_t opcode_decoding_result = - DecodeOpcodeAndNumberOfOperands(&opcode, &num_operands); - if (opcode_decoding_result < 0) return opcode_decoding_result; - - if (opcode_decoding_result == SPV_SUCCESS) { - inst_.num_operands = static_cast(num_operands); - num_operands_still_unknown = false; - } else { - if (!reader_.ReadVariableWidthU32(&opcode, - model_->opcode_chunk_length())) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read opcode of instruction"; - } - } - - inst_.opcode = static_cast(opcode); - } - - const SpvOp opcode = static_cast(inst_.opcode); - - spv_opcode_desc opcode_desc; - if (grammar_.lookupOpcode(opcode, &opcode_desc) != SPV_SUCCESS) { - return Diag(SPV_ERROR_INVALID_BINARY) << "Invalid opcode"; - } - - spv_operand_pattern_t expected_operands; - expected_operands.reserve(opcode_desc->numTypes); - for (auto i = 0; i < opcode_desc->numTypes; i++) { - expected_operands.push_back( - opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]); - } - - if (num_operands_still_unknown) { - if (!OpcodeHasFixedNumberOfOperands(opcode)) { - if (!reader_.ReadVariableWidthU16(&inst_.num_operands, - model_->num_operands_chunk_length())) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read num_operands of instruction"; - } else { - inst_.num_operands = static_cast(expected_operands.size()); - } - } - - for (operand_index_ = 0; - operand_index_ < static_cast(inst_.num_operands); - ++operand_index_) { - assert(!expected_operands.empty()); - const spv_operand_type_t type = - spvTakeFirstMatchableOperand(&expected_operands); - - const size_t operand_offset = inst_words_.size(); - - const spv_result_t decode_result = - DecodeOperand(operand_offset, type, &expected_operands); - - if (decode_result != SPV_SUCCESS) return decode_result; - } - - assert(inst_.num_operands == parsed_operands_.size()); - - // Only valid while inst_words_ and parsed_operands_ remain unchanged (until - // next DecodeInstruction call). - inst_.words = inst_words_.data(); - inst_.operands = parsed_operands_.empty() ? nullptr : parsed_operands_.data(); - inst_.num_words = static_cast(inst_words_.size()); - inst_words_[0] = spvOpcodeMake(inst_.num_words, SpvOp(inst_.opcode)); - - std::copy(inst_words_.begin(), inst_words_.end(), std::back_inserter(spirv_)); - - assert(inst_.num_words == - std::accumulate( - parsed_operands_.begin(), parsed_operands_.end(), 1, - [](int num_words, const spv_parsed_operand_t& operand) { - return num_words += operand.num_words; - }) && - "num_words in instruction doesn't correspond to the sum of num_words" - "in the operands"); - - RecordNumberType(); - ProcessCurInstruction(); - - if (!ReadToByteBreak(MarkvCodec::kByteBreakAfterInstIfLessThanUntilNextByte)) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read to byte break"; - - if (logger_) { - logger_->NewLine(); - std::stringstream ss; - ss << spvOpcodeString(opcode) << " "; - for (size_t index = 1; index < inst_words_.size(); ++index) - ss << inst_words_[index] << " "; - logger_->AppendText(ss.str()); - logger_->NewLine(); - logger_->NewLine(); - if (!logger_->DebugInstruction(inst_)) return SPV_REQUESTED_TERMINATION; - } - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::SetNumericTypeInfoForType( - spv_parsed_operand_t* parsed_operand, uint32_t type_id) { - assert(type_id != 0); - auto type_info_iter = type_id_to_number_type_info_.find(type_id); - if (type_info_iter == type_id_to_number_type_info_.end()) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Type Id " << type_id << " is not a type"; - } - - const NumberType& info = type_info_iter->second; - if (info.type == SPV_NUMBER_NONE) { - // This is a valid type, but for something other than a scalar number. - return Diag(SPV_ERROR_INVALID_BINARY) - << "Type Id " << type_id << " is not a scalar numeric type"; - } - - parsed_operand->number_kind = info.type; - parsed_operand->number_bit_width = info.bit_width; - // Round up the word count. - parsed_operand->num_words = static_cast((info.bit_width + 31) / 32); - return SPV_SUCCESS; -} - -void MarkvDecoder::RecordNumberType() { - const SpvOp opcode = static_cast(inst_.opcode); - if (spvOpcodeGeneratesType(opcode)) { - NumberType info = {SPV_NUMBER_NONE, 0}; - if (SpvOpTypeInt == opcode) { - info.bit_width = inst_.words[inst_.operands[1].offset]; - info.type = inst_.words[inst_.operands[2].offset] - ? SPV_NUMBER_SIGNED_INT - : SPV_NUMBER_UNSIGNED_INT; - } else if (SpvOpTypeFloat == opcode) { - info.bit_width = inst_.words[inst_.operands[1].offset]; - info.type = SPV_NUMBER_FLOATING; - } - // The *result* Id of a type generating instruction is the type Id. - type_id_to_number_type_info_[inst_.result_id] = info; - } -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/comp/markv_decoder.h b/3rdparty/spirv-tools/source/comp/markv_decoder.h deleted file mode 100644 index 4d8402b44..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_decoder.h +++ /dev/null @@ -1,175 +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/comp/bit_stream.h" -#include "source/comp/markv.h" -#include "source/comp/markv_codec.h" -#include "source/comp/markv_logger.h" -#include "source/util/make_unique.h" - -#ifndef SOURCE_COMP_MARKV_DECODER_H_ -#define SOURCE_COMP_MARKV_DECODER_H_ - -namespace spvtools { -namespace comp { - -class MarkvLogger; - -// Decodes MARK-V buffers written by MarkvEncoder. -class MarkvDecoder : public MarkvCodec { - public: - // |model| is owned by the caller, must be not null and valid during the - // lifetime of MarkvEncoder. - MarkvDecoder(spv_const_context context, const std::vector& markv, - const MarkvCodecOptions& options, const MarkvModel* model) - : MarkvCodec(context, GetValidatorOptions(options), model), - options_(options), - reader_(markv) { - SetIdBound(1); - parsed_operands_.reserve(25); - inst_words_.reserve(25); - } - ~MarkvDecoder() = default; - - // Creates an internal logger which writes comments on the decoding process. - void CreateLogger(MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer) { - logger_ = MakeUnique(log_consumer, debug_consumer); - } - - // Decodes SPIR-V from MARK-V and stores the words in |spirv_binary|. - // Can be called only once. Fails if data of wrong format or ends prematurely, - // of if validation fails. - spv_result_t DecodeModule(std::vector* spirv_binary); - - // Creates and returns validator options. Returned value owned by the caller. - static spv_validator_options GetValidatorOptions( - const MarkvCodecOptions& options) { - return options.validate_spirv_binary ? spvValidatorOptionsCreate() - : nullptr; - } - - private: - // Describes the format of a typed literal number. - struct NumberType { - spv_number_kind_t type; - uint32_t bit_width; - }; - - // Reads a single bit from reader_. The read bit is stored in |bit|. - // Returns false iff reader_ fails. - bool ReadBit(bool* bit) { - uint64_t bits = 0; - const bool result = reader_.ReadBits(&bits, 1); - if (result) *bit = bits ? true : false; - return result; - }; - - // Returns ReadBit bound to the class object. - std::function GetReadBitCallback() { - return std::bind(&MarkvDecoder::ReadBit, this, std::placeholders::_1); - } - - // Reads a single non-id word from bit stream. operand_.type determines if - // the word needs to be decoded and how. - spv_result_t DecodeNonIdWord(uint32_t* word); - - // Reads and decodes both opcode and num_operands as a single code. - // Returns SPV_UNSUPPORTED iff no suitable codec was found. - spv_result_t DecodeOpcodeAndNumberOfOperands(uint32_t* opcode, - uint32_t* num_operands); - - // Reads mtf rank from bit stream. |mtf| is used to determine the codec - // scheme. |fallback_method| is used if no codec defined for |mtf|. - spv_result_t DecodeMtfRankHuffman(uint64_t mtf, uint32_t fallback_method, - uint32_t* rank); - - // Reads id using coding based on mtf associated with the id descriptor. - // Returns SPV_UNSUPPORTED iff fallback method needs to be used. - spv_result_t DecodeIdWithDescriptor(uint32_t* id); - - // Reads id using coding based on the given |mtf|, which is expected to - // contain the needed |id|. - spv_result_t DecodeExistingId(uint64_t mtf, uint32_t* id); - - // Reads type id of the current instruction if can't be inferred. - spv_result_t DecodeTypeId(); - - // Reads result id of the current instruction if can't be inferred. - spv_result_t DecodeResultId(); - - // Reads id which is neither type nor result id. - spv_result_t DecodeRefId(uint32_t* id); - - // Reads and discards bits until the beginning of the next byte if the - // number of bits until the next byte is less than |byte_break_if_less_than|. - bool ReadToByteBreak(size_t byte_break_if_less_than); - - // Returns instruction words decoded up to this point. - const uint32_t* GetInstWords() const override { return inst_words_.data(); } - - // Reads a literal number as it is described in |operand| from the bit stream, - // decodes and writes it to spirv_. - spv_result_t DecodeLiteralNumber(const spv_parsed_operand_t& operand); - - // Reads instruction from bit stream, decodes and validates it. - // Decoded instruction is valid until the next call of DecodeInstruction(). - spv_result_t DecodeInstruction(); - - // Read operand from the stream decodes and validates it. - spv_result_t DecodeOperand(size_t operand_offset, - const spv_operand_type_t type, - spv_operand_pattern_t* expected_operands); - - // Records the numeric type for an operand according to the type information - // associated with the given non-zero type Id. This can fail if the type Id - // is not a type Id, or if the type Id does not reference a scalar numeric - // type. On success, return SPV_SUCCESS and populates the num_words, - // number_kind, and number_bit_width fields of parsed_operand. - spv_result_t SetNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand, - uint32_t type_id); - - // Records the number type for the current instruction, if it generates a - // type. For types that aren't scalar numbers, record something with number - // kind SPV_NUMBER_NONE. - void RecordNumberType(); - - MarkvCodecOptions options_; - - // Temporary sink where decoded SPIR-V words are written. Once it contains the - // entire module, the container is moved and returned. - std::vector spirv_; - - // Bit stream containing encoded data. - BitReaderWord64 reader_; - - // Temporary storage for operands of the currently parsed instruction. - // Valid until next DecodeInstruction call. - std::vector parsed_operands_; - - // Temporary storage for current instruction words. - // Valid until next DecodeInstruction call. - std::vector inst_words_; - - // Maps a type ID to its number type description. - std::unordered_map type_id_to_number_type_info_; - - // Maps an ExtInstImport id to the extended instruction type. - std::unordered_map import_id_to_ext_inst_type_; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_DECODER_H_ diff --git a/3rdparty/spirv-tools/source/comp/markv_encoder.cpp b/3rdparty/spirv-tools/source/comp/markv_encoder.cpp deleted file mode 100644 index 1abd58646..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_encoder.cpp +++ /dev/null @@ -1,486 +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/comp/markv_encoder.h" - -#include "source/binary.h" -#include "source/opcode.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { -namespace { - -const size_t kCommentNumWhitespaces = 2; - -} // namespace - -spv_result_t MarkvEncoder::EncodeNonIdWord(uint32_t word) { - auto* codec = model_->GetNonIdWordHuffmanCodec(inst_.opcode, operand_index_); - - if (codec) { - uint64_t bits = 0; - size_t num_bits = 0; - if (codec->Encode(word, &bits, &num_bits)) { - // Encoding successful. - writer_.WriteBits(bits, num_bits); - return SPV_SUCCESS; - } else { - // Encoding failed, write kMarkvNoneOfTheAbove flag. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Non-id word Huffman table for " - << spvOpcodeString(SpvOp(inst_.opcode)) << " operand index " - << operand_index_ << " is missing kMarkvNoneOfTheAbove"; - writer_.WriteBits(bits, num_bits); - } - } - - // Fallback encoding. - const size_t chunk_length = - model_->GetOperandVariableWidthChunkLength(operand_.type); - if (chunk_length) { - writer_.WriteVariableWidthU32(word, chunk_length); - } else { - writer_.WriteUnencoded(word); - } - return SPV_SUCCESS; -} - -spv_result_t MarkvEncoder::EncodeOpcodeAndNumOperands(uint32_t opcode, - uint32_t num_operands) { - uint64_t bits = 0; - size_t num_bits = 0; - - const uint32_t word = opcode | (num_operands << 16); - - // First try to use the Markov chain codec. - auto* codec = - model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(GetPrevOpcode()); - if (codec) { - if (codec->Encode(word, &bits, &num_bits)) { - // The word was successfully encoded into bits/num_bits. - writer_.WriteBits(bits, num_bits); - return SPV_SUCCESS; - } else { - // The word is not in the Huffman table. Write kMarkvNoneOfTheAbove - // and use fallback encoding. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "opcode_and_num_operands Huffman table for " - << spvOpcodeString(GetPrevOpcode()) - << "is missing kMarkvNoneOfTheAbove"; - writer_.WriteBits(bits, num_bits); - } - } - - // Fallback to base-rate codec. - codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(SpvOpNop); - assert(codec); - if (codec->Encode(word, &bits, &num_bits)) { - // The word was successfully encoded into bits/num_bits. - writer_.WriteBits(bits, num_bits); - return SPV_SUCCESS; - } else { - // The word is not in the Huffman table. Write kMarkvNoneOfTheAbove - // and return false. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Global opcode_and_num_operands Huffman table is missing " - << "kMarkvNoneOfTheAbove"; - writer_.WriteBits(bits, num_bits); - return SPV_UNSUPPORTED; - } -} - -spv_result_t MarkvEncoder::EncodeMtfRankHuffman(uint32_t rank, uint64_t mtf, - uint64_t fallback_method) { - const auto* codec = GetMtfHuffmanCodec(mtf); - if (!codec) { - assert(fallback_method != kMtfNone); - codec = GetMtfHuffmanCodec(fallback_method); - } - - if (!codec) return Diag(SPV_ERROR_INTERNAL) << "No codec to encode MTF rank"; - - uint64_t bits = 0; - size_t num_bits = 0; - if (rank < MarkvCodec::kMtfSmallestRankEncodedByValue) { - // Encode using Huffman coding. - if (!codec->Encode(rank, &bits, &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to encode MTF rank with Huffman"; - - writer_.WriteBits(bits, num_bits); - } else { - // Encode by value. - if (!codec->Encode(MarkvCodec::kMtfRankEncodedByValueSignal, &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to encode kMtfRankEncodedByValueSignal"; - - writer_.WriteBits(bits, num_bits); - writer_.WriteVariableWidthU32( - rank - MarkvCodec::kMtfSmallestRankEncodedByValue, - model_->mtf_rank_chunk_length()); - } - return SPV_SUCCESS; -} - -spv_result_t MarkvEncoder::EncodeIdWithDescriptor(uint32_t id) { - // Get the descriptor for id. - const uint32_t long_descriptor = long_id_descriptors_.GetDescriptor(id); - auto* codec = - model_->GetIdDescriptorHuffmanCodec(inst_.opcode, operand_index_); - uint64_t bits = 0; - size_t num_bits = 0; - uint64_t mtf = kMtfNone; - if (long_descriptor && codec && - codec->Encode(long_descriptor, &bits, &num_bits)) { - // If the descriptor exists and is in the table, write the descriptor and - // proceed to encoding the rank. - writer_.WriteBits(bits, num_bits); - mtf = GetMtfLongIdDescriptor(long_descriptor); - } else { - if (codec) { - // The descriptor doesn't exist or we have no coding for it. Write - // kMarkvNoneOfTheAbove and go to fallback method. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Descriptor Huffman table for " - << spvOpcodeString(SpvOp(inst_.opcode)) << " operand index " - << operand_index_ << " is missing kMarkvNoneOfTheAbove"; - - writer_.WriteBits(bits, num_bits); - } - - if (model_->id_fallback_strategy() != - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - return SPV_UNSUPPORTED; - } - - const uint32_t short_descriptor = short_id_descriptors_.GetDescriptor(id); - writer_.WriteBits(short_descriptor, MarkvCodec::kShortDescriptorNumBits); - - if (short_descriptor == 0) { - // Forward declared id. - return SPV_UNSUPPORTED; - } - - mtf = GetMtfShortIdDescriptor(short_descriptor); - } - - // Descriptor has been encoded. Now encode the rank of the id in the - // associated mtf sequence. - return EncodeExistingId(mtf, id); -} - -spv_result_t MarkvEncoder::EncodeExistingId(uint64_t mtf, uint32_t id) { - assert(multi_mtf_.GetSize(mtf) > 0); - if (multi_mtf_.GetSize(mtf) == 1) { - // If the sequence has only one element no need to write rank, the decoder - // would make the same decision. - return SPV_SUCCESS; - } - - uint32_t rank = 0; - if (!multi_mtf_.RankFromValue(mtf, id, &rank)) - return Diag(SPV_ERROR_INTERNAL) << "Id is not in the MTF sequence"; - - return EncodeMtfRankHuffman(rank, mtf, kMtfGenericNonZeroRank); -} - -spv_result_t MarkvEncoder::EncodeRefId(uint32_t id) { - { - // Try to encode using id descriptor mtfs. - const spv_result_t result = EncodeIdWithDescriptor(id); - if (result != SPV_UNSUPPORTED) return result; - // If can't be done continue with other methods. - } - - const bool can_forward_declare = spvOperandCanBeForwardDeclaredFunction( - SpvOp(inst_.opcode))(operand_index_); - uint32_t rank = 0; - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - // Encode using rule-based mtf. - uint64_t mtf = GetRuleBasedMtf(); - - if (mtf != kMtfNone && !can_forward_declare) { - assert(multi_mtf_.HasValue(kMtfAll, id)); - return EncodeExistingId(mtf, id); - } - - if (mtf == kMtfNone) mtf = kMtfAll; - - if (!multi_mtf_.RankFromValue(mtf, id, &rank)) { - // This is the first occurrence of a forward declared id. - multi_mtf_.Insert(kMtfAll, id); - multi_mtf_.Insert(kMtfForwardDeclared, id); - if (mtf != kMtfAll) multi_mtf_.Insert(mtf, id); - rank = 0; - } - - return EncodeMtfRankHuffman(rank, mtf, kMtfAll); - } else { - assert(can_forward_declare); - - if (!multi_mtf_.RankFromValue(kMtfForwardDeclared, id, &rank)) { - // This is the first occurrence of a forward declared id. - multi_mtf_.Insert(kMtfForwardDeclared, id); - rank = 0; - } - - writer_.WriteVariableWidthU32(rank, model_->mtf_rank_chunk_length()); - return SPV_SUCCESS; - } -} - -spv_result_t MarkvEncoder::EncodeTypeId() { - if (inst_.opcode == SpvOpFunctionParameter) { - assert(!remaining_function_parameter_types_.empty()); - assert(inst_.type_id == remaining_function_parameter_types_.front()); - remaining_function_parameter_types_.pop_front(); - return SPV_SUCCESS; - } - - { - // Try to encode using id descriptor mtfs. - const spv_result_t result = EncodeIdWithDescriptor(inst_.type_id); - if (result != SPV_UNSUPPORTED) return result; - // If can't be done continue with other methods. - } - - assert(model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased); - - uint64_t mtf = GetRuleBasedMtf(); - assert(!spvOperandCanBeForwardDeclaredFunction(SpvOp(inst_.opcode))( - operand_index_)); - - if (mtf == kMtfNone) { - mtf = kMtfTypeNonFunction; - // Function types should have been handled by GetRuleBasedMtf. - assert(inst_.opcode != SpvOpFunction); - } - - return EncodeExistingId(mtf, inst_.type_id); -} - -spv_result_t MarkvEncoder::EncodeResultId() { - uint32_t rank = 0; - - const uint64_t num_still_forward_declared = - multi_mtf_.GetSize(kMtfForwardDeclared); - - if (num_still_forward_declared) { - // We write the rank only if kMtfForwardDeclared is not empty. If it is - // empty the decoder knows that there are no forward declared ids to expect. - if (multi_mtf_.RankFromValue(kMtfForwardDeclared, inst_.result_id, &rank)) { - // This is a definition of a forward declared id. We can remove the id - // from kMtfForwardDeclared. - if (!multi_mtf_.Remove(kMtfForwardDeclared, inst_.result_id)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to remove id from kMtfForwardDeclared"; - writer_.WriteBits(1, 1); - writer_.WriteVariableWidthU32(rank, model_->mtf_rank_chunk_length()); - } else { - rank = 0; - writer_.WriteBits(0, 1); - } - } - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - if (!rank) { - multi_mtf_.Insert(kMtfAll, inst_.result_id); - } - } - - return SPV_SUCCESS; -} - -spv_result_t MarkvEncoder::EncodeLiteralNumber( - const spv_parsed_operand_t& operand) { - if (operand.number_bit_width <= 32) { - const uint32_t word = inst_.words[operand.offset]; - return EncodeNonIdWord(word); - } else { - assert(operand.number_bit_width <= 64); - const uint64_t word = uint64_t(inst_.words[operand.offset]) | - (uint64_t(inst_.words[operand.offset + 1]) << 32); - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - writer_.WriteVariableWidthU64(word, model_->u64_chunk_length()); - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int64_t val = 0; - std::memcpy(&val, &word, 8); - writer_.WriteVariableWidthS64(val, model_->s64_chunk_length(), - model_->s64_block_exponent()); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - writer_.WriteUnencoded(word); - } else { - return Diag(SPV_ERROR_INTERNAL) << "Unsupported bit length"; - } - } - return SPV_SUCCESS; -} - -void MarkvEncoder::AddByteBreak(size_t byte_break_if_less_than) { - const size_t num_bits_to_next_byte = - GetNumBitsToNextByte(writer_.GetNumBits()); - if (num_bits_to_next_byte == 0 || - num_bits_to_next_byte > byte_break_if_less_than) - return; - - if (logger_) { - logger_->AppendWhitespaces(kCommentNumWhitespaces); - logger_->AppendText(""); - } - - writer_.WriteBits(0, num_bits_to_next_byte); -} - -spv_result_t MarkvEncoder::EncodeInstruction( - const spv_parsed_instruction_t& inst) { - SpvOp opcode = SpvOp(inst.opcode); - inst_ = inst; - - LogDisassemblyInstruction(); - - const spv_result_t opcode_encodig_result = - EncodeOpcodeAndNumOperands(opcode, inst.num_operands); - if (opcode_encodig_result < 0) return opcode_encodig_result; - - if (opcode_encodig_result != SPV_SUCCESS) { - // Fallback encoding for opcode and num_operands. - writer_.WriteVariableWidthU32(opcode, model_->opcode_chunk_length()); - - if (!OpcodeHasFixedNumberOfOperands(opcode)) { - // If the opcode has a variable number of operands, encode the number of - // operands with the instruction. - - if (logger_) logger_->AppendWhitespaces(kCommentNumWhitespaces); - - writer_.WriteVariableWidthU16(inst.num_operands, - model_->num_operands_chunk_length()); - } - } - - // Write operands. - const uint32_t num_operands = inst_.num_operands; - for (operand_index_ = 0; operand_index_ < num_operands; ++operand_index_) { - operand_ = inst_.operands[operand_index_]; - - if (logger_) { - logger_->AppendWhitespaces(kCommentNumWhitespaces); - logger_->AppendText("<"); - logger_->AppendText(spvOperandTypeStr(operand_.type)); - logger_->AppendText(">"); - } - - switch (operand_.type) { - case SPV_OPERAND_TYPE_RESULT_ID: - case SPV_OPERAND_TYPE_TYPE_ID: - case SPV_OPERAND_TYPE_ID: - case SPV_OPERAND_TYPE_OPTIONAL_ID: - case SPV_OPERAND_TYPE_SCOPE_ID: - case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: { - const uint32_t id = inst_.words[operand_.offset]; - if (operand_.type == SPV_OPERAND_TYPE_TYPE_ID) { - const spv_result_t result = EncodeTypeId(); - if (result != SPV_SUCCESS) return result; - } else if (operand_.type == SPV_OPERAND_TYPE_RESULT_ID) { - const spv_result_t result = EncodeResultId(); - if (result != SPV_SUCCESS) return result; - } else { - const spv_result_t result = EncodeRefId(id); - if (result != SPV_SUCCESS) return result; - } - - PromoteIfNeeded(id); - break; - } - - case SPV_OPERAND_TYPE_LITERAL_INTEGER: { - const spv_result_t result = - EncodeNonIdWord(inst_.words[operand_.offset]); - if (result != SPV_SUCCESS) return result; - break; - } - - case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: { - const spv_result_t result = EncodeLiteralNumber(operand_); - if (result != SPV_SUCCESS) return result; - break; - } - - case SPV_OPERAND_TYPE_LITERAL_STRING: { - const char* src = - reinterpret_cast(&inst_.words[operand_.offset]); - - auto* codec = model_->GetLiteralStringHuffmanCodec(opcode); - if (codec) { - uint64_t bits = 0; - size_t num_bits = 0; - const std::string str = src; - if (codec->Encode(str, &bits, &num_bits)) { - writer_.WriteBits(bits, num_bits); - break; - } else { - bool result = - codec->Encode("kMarkvNoneOfTheAbove", &bits, &num_bits); - (void)result; - assert(result); - writer_.WriteBits(bits, num_bits); - } - } - - const size_t length = spv_strnlen_s(src, operand_.num_words * 4); - if (length == operand_.num_words * 4) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to find terminal character of literal string"; - for (size_t i = 0; i < length + 1; ++i) writer_.WriteUnencoded(src[i]); - break; - } - - default: { - for (int i = 0; i < operand_.num_words; ++i) { - const uint32_t word = inst_.words[operand_.offset + i]; - const spv_result_t result = EncodeNonIdWord(word); - if (result != SPV_SUCCESS) return result; - } - break; - } - } - } - - AddByteBreak(MarkvCodec::kByteBreakAfterInstIfLessThanUntilNextByte); - - if (logger_) { - logger_->NewLine(); - logger_->NewLine(); - if (!logger_->DebugInstruction(inst_)) return SPV_REQUESTED_TERMINATION; - } - - ProcessCurInstruction(); - - return SPV_SUCCESS; -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/comp/markv_encoder.h b/3rdparty/spirv-tools/source/comp/markv_encoder.h deleted file mode 100644 index 21843123f..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_encoder.h +++ /dev/null @@ -1,167 +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/comp/bit_stream.h" -#include "source/comp/markv.h" -#include "source/comp/markv_codec.h" -#include "source/comp/markv_logger.h" -#include "source/util/make_unique.h" - -#ifndef SOURCE_COMP_MARKV_ENCODER_H_ -#define SOURCE_COMP_MARKV_ENCODER_H_ - -#include - -namespace spvtools { -namespace comp { - -// SPIR-V to MARK-V encoder. Exposes functions EncodeHeader and -// EncodeInstruction which can be used as callback by spvBinaryParse. -// Encoded binary is written to an internally maintained bitstream. -// After the last instruction is encoded, the resulting MARK-V binary can be -// acquired by calling GetMarkvBinary(). -// -// The encoder uses SPIR-V validator to keep internal state, therefore -// SPIR-V binary needs to be able to pass validator checks. -// CreateCommentsLogger() can be used to enable the encoder to write comments -// on how encoding was done, which can later be accessed with GetComments(). -class MarkvEncoder : public MarkvCodec { - public: - // |model| is owned by the caller, must be not null and valid during the - // lifetime of MarkvEncoder. - MarkvEncoder(spv_const_context context, const MarkvCodecOptions& options, - const MarkvModel* model) - : MarkvCodec(context, GetValidatorOptions(options), model), - options_(options) {} - ~MarkvEncoder() override = default; - - // Writes data from SPIR-V header to MARK-V header. - spv_result_t EncodeHeader(spv_endianness_t /* endian */, uint32_t /* magic */, - uint32_t version, uint32_t generator, - uint32_t id_bound, uint32_t /* schema */) { - SetIdBound(id_bound); - header_.spirv_version = version; - header_.spirv_generator = generator; - return SPV_SUCCESS; - } - - // Creates an internal logger which writes comments on the encoding process. - void CreateLogger(MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer) { - logger_ = MakeUnique(log_consumer, debug_consumer); - writer_.SetCallback( - [this](const std::string& str) { logger_->AppendBitSequence(str); }); - } - - // Encodes SPIR-V instruction to MARK-V and writes to bit stream. - // Operation can fail if the instruction fails to pass the validator or if - // the encoder stubmles on something unexpected. - spv_result_t EncodeInstruction(const spv_parsed_instruction_t& inst); - - // Concatenates MARK-V header and the bit stream with encoded instructions - // into a single buffer and returns it as spv_markv_binary. The returned - // value is owned by the caller and needs to be destroyed with - // spvMarkvBinaryDestroy(). - std::vector GetMarkvBinary() { - header_.markv_length_in_bits = - static_cast(sizeof(header_) * 8 + writer_.GetNumBits()); - header_.markv_model = - (model_->model_type() << 16) | model_->model_version(); - - const size_t num_bytes = sizeof(header_) + writer_.GetDataSizeBytes(); - std::vector markv(num_bytes); - - assert(writer_.GetData()); - std::memcpy(markv.data(), &header_, sizeof(header_)); - std::memcpy(markv.data() + sizeof(header_), writer_.GetData(), - writer_.GetDataSizeBytes()); - return markv; - } - - // Optionally adds disassembly to the comments. - // Disassembly should contain all instructions in the module separated by - // \n, and no header. - void SetDisassembly(std::string&& disassembly) { - disassembly_ = MakeUnique(std::move(disassembly)); - } - - // Extracts the next instruction line from the disassembly and logs it. - void LogDisassemblyInstruction() { - if (logger_ && disassembly_) { - std::string line; - std::getline(*disassembly_, line, '\n'); - logger_->AppendTextNewLine(line); - } - } - - private: - // Creates and returns validator options. Returned value owned by the caller. - static spv_validator_options GetValidatorOptions( - const MarkvCodecOptions& options) { - return options.validate_spirv_binary ? spvValidatorOptionsCreate() - : nullptr; - } - - // Writes a single word to bit stream. operand_.type determines if the word is - // encoded and how. - spv_result_t EncodeNonIdWord(uint32_t word); - - // Writes both opcode and num_operands as a single code. - // Returns SPV_UNSUPPORTED iff no suitable codec was found. - spv_result_t EncodeOpcodeAndNumOperands(uint32_t opcode, - uint32_t num_operands); - - // Writes mtf rank to bit stream. |mtf| is used to determine the codec - // scheme. |fallback_method| is used if no codec defined for |mtf|. - spv_result_t EncodeMtfRankHuffman(uint32_t rank, uint64_t mtf, - uint64_t fallback_method); - - // Writes id using coding based on mtf associated with the id descriptor. - // Returns SPV_UNSUPPORTED iff fallback method needs to be used. - spv_result_t EncodeIdWithDescriptor(uint32_t id); - - // Writes id using coding based on the given |mtf|, which is expected to - // contain the given |id|. - spv_result_t EncodeExistingId(uint64_t mtf, uint32_t id); - - // Writes type id of the current instruction if can't be inferred. - spv_result_t EncodeTypeId(); - - // Writes result id of the current instruction if can't be inferred. - spv_result_t EncodeResultId(); - - // Writes ids which are neither type nor result ids. - spv_result_t EncodeRefId(uint32_t id); - - // Writes bits to the stream until the beginning of the next byte if the - // number of bits until the next byte is less than |byte_break_if_less_than|. - void AddByteBreak(size_t byte_break_if_less_than); - - // Encodes a literal number operand and writes it to the bit stream. - spv_result_t EncodeLiteralNumber(const spv_parsed_operand_t& operand); - - MarkvCodecOptions options_; - - // Bit stream where encoded instructions are written. - BitWriterWord64 writer_; - - // If not nullptr, disassembled instruction lines will be written to comments. - // Format: \n separated instruction lines, no header. - std::unique_ptr disassembly_; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_ENCODER_H_ diff --git a/3rdparty/spirv-tools/source/comp/markv_logger.h b/3rdparty/spirv-tools/source/comp/markv_logger.h deleted file mode 100644 index c07fe97b7..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_logger.h +++ /dev/null @@ -1,93 +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_COMP_MARKV_LOGGER_H_ -#define SOURCE_COMP_MARKV_LOGGER_H_ - -#include "source/comp/markv.h" - -namespace spvtools { -namespace comp { - -class MarkvLogger { - public: - MarkvLogger(MarkvLogConsumer log_consumer, MarkvDebugConsumer debug_consumer) - : log_consumer_(log_consumer), debug_consumer_(debug_consumer) {} - - void AppendText(const std::string& str) { - Append(str); - use_delimiter_ = false; - } - - void AppendTextNewLine(const std::string& str) { - Append(str); - Append("\n"); - use_delimiter_ = false; - } - - void AppendBitSequence(const std::string& str) { - if (debug_consumer_) instruction_bits_ << str; - if (use_delimiter_) Append("-"); - Append(str); - use_delimiter_ = true; - } - - void AppendWhitespaces(size_t num) { - Append(std::string(num, ' ')); - use_delimiter_ = false; - } - - void NewLine() { - Append("\n"); - use_delimiter_ = false; - } - - bool DebugInstruction(const spv_parsed_instruction_t& inst) { - bool result = true; - if (debug_consumer_) { - result = debug_consumer_( - std::vector(inst.words, inst.words + inst.num_words), - instruction_bits_.str(), instruction_comment_.str()); - instruction_bits_.str(std::string()); - instruction_comment_.str(std::string()); - } - return result; - } - - private: - MarkvLogger(const MarkvLogger&) = delete; - MarkvLogger(MarkvLogger&&) = delete; - MarkvLogger& operator=(const MarkvLogger&) = delete; - MarkvLogger& operator=(MarkvLogger&&) = delete; - - void Append(const std::string& str) { - if (log_consumer_) log_consumer_(str); - if (debug_consumer_) instruction_comment_ << str; - } - - MarkvLogConsumer log_consumer_; - MarkvDebugConsumer debug_consumer_; - - std::stringstream instruction_bits_; - std::stringstream instruction_comment_; - - // If true a delimiter will be appended before the next bit sequence. - // Used to generate outputs like: 1100-0 1110-1-1100-1-1111-0 110-0. - bool use_delimiter_ = false; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_LOGGER_H_ diff --git a/3rdparty/spirv-tools/source/comp/markv_model.h b/3rdparty/spirv-tools/source/comp/markv_model.h deleted file mode 100644 index d03df02df..000000000 --- a/3rdparty/spirv-tools/source/comp/markv_model.h +++ /dev/null @@ -1,232 +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_COMP_MARKV_MODEL_H_ -#define SOURCE_COMP_MARKV_MODEL_H_ - -#include - -#include "source/comp/huffman_codec.h" -#include "source/latest_version_spirv_header.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { - -// Base class for MARK-V models. -// The class contains encoding/decoding model with various constants and -// codecs used by the compression algorithm. -class MarkvModel { - public: - MarkvModel() - : operand_chunk_lengths_( - static_cast(SPV_OPERAND_TYPE_NUM_OPERAND_TYPES), 0) { - // Set default values. - operand_chunk_lengths_[SPV_OPERAND_TYPE_TYPE_ID] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_RESULT_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SCOPE_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_LITERAL_INTEGER] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_CAPABILITY] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SOURCE_LANGUAGE] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_EXECUTION_MODEL] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_ADDRESSING_MODEL] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_MEMORY_MODEL] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_EXECUTION_MODE] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_STORAGE_CLASS] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_DIMENSIONALITY] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FP_ROUNDING_MODE] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_LINKAGE_TYPE] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_ACCESS_QUALIFIER] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_DECORATION] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_BUILT_IN] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_GROUP_OPERATION] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FP_FAST_MATH_MODE] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FUNCTION_CONTROL] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_LOOP_CONTROL] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_IMAGE] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_IMAGE] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SELECTION_CONTROL] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER] = 6; - } - - uint32_t model_type() const { return model_type_; } - uint32_t model_version() const { return model_version_; } - - uint32_t opcode_chunk_length() const { return opcode_chunk_length_; } - uint32_t num_operands_chunk_length() const { - return num_operands_chunk_length_; - } - uint32_t mtf_rank_chunk_length() const { return mtf_rank_chunk_length_; } - - uint32_t u64_chunk_length() const { return u64_chunk_length_; } - uint32_t s64_chunk_length() const { return s64_chunk_length_; } - uint32_t s64_block_exponent() const { return s64_block_exponent_; } - - enum class IdFallbackStrategy { - kRuleBased = 0, - kShortDescriptor, - }; - - IdFallbackStrategy id_fallback_strategy() const { - return id_fallback_strategy_; - } - - // Returns a codec for common opcode_and_num_operands words for the given - // previous opcode. May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetOpcodeAndNumOperandsMarkovHuffmanCodec( - uint32_t prev_opcode) const { - if (prev_opcode == SpvOpNop) - return opcode_and_num_operands_huffman_codec_.get(); - - const auto it = - opcode_and_num_operands_markov_huffman_codecs_.find(prev_opcode); - if (it == opcode_and_num_operands_markov_huffman_codecs_.end()) - return nullptr; - return it->second.get(); - } - - // Returns a codec for common non-id words used for given operand slot. - // Operand slot is defined by the opcode and the operand index. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetNonIdWordHuffmanCodec( - uint32_t opcode, uint32_t operand_index) const { - const auto it = non_id_word_huffman_codecs_.find( - std::pair(opcode, operand_index)); - if (it == non_id_word_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Returns a codec for common id descriptos used for given operand slot. - // Operand slot is defined by the opcode and the operand index. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetIdDescriptorHuffmanCodec( - uint32_t opcode, uint32_t operand_index) const { - const auto it = id_descriptor_huffman_codecs_.find( - std::pair(opcode, operand_index)); - if (it == id_descriptor_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Returns a codec for common strings used by the given opcode. - // Operand slot is defined by the opcode and the operand index. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetLiteralStringHuffmanCodec( - uint32_t opcode) const { - const auto it = literal_string_huffman_codecs_.find(opcode); - if (it == literal_string_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Checks if |descriptor| has a coding scheme in any of - // id_descriptor_huffman_codecs_. - bool DescriptorHasCodingScheme(uint32_t descriptor) const { - return descriptors_with_coding_scheme_.count(descriptor); - } - - // Checks if any descriptor has a coding scheme. - bool AnyDescriptorHasCodingScheme() const { - return !descriptors_with_coding_scheme_.empty(); - } - - // Returns chunk length used for variable length encoding of spirv operand - // words. - uint32_t GetOperandVariableWidthChunkLength(spv_operand_type_t type) const { - return operand_chunk_lengths_.at(static_cast(type)); - } - - // Sets model type. - void SetModelType(uint32_t in_model_type) { model_type_ = in_model_type; } - - // Sets model version. - void SetModelVersion(uint32_t in_model_version) { - model_version_ = in_model_version; - } - - // Returns value used by Huffman codecs as a signal that a value is not in the - // coding table. - static uint64_t GetMarkvNoneOfTheAbove() { - // Magic number. - return 1111111111111111111; - } - - MarkvModel(const MarkvModel&) = delete; - const MarkvModel& operator=(const MarkvModel&) = delete; - - protected: - // Huffman codec for base-rate of opcode_and_num_operands. - std::unique_ptr> - opcode_and_num_operands_huffman_codec_; - - // Huffman codecs for opcode_and_num_operands. The map key is previous opcode. - std::map>> - opcode_and_num_operands_markov_huffman_codecs_; - - // Huffman codecs for non-id single-word operand values. - // The map key is pair . - std::map, - std::unique_ptr>> - non_id_word_huffman_codecs_; - - // Huffman codecs for id descriptors. The map key is pair - // . - std::map, - std::unique_ptr>> - id_descriptor_huffman_codecs_; - - // Set of all descriptors which have a coding scheme in any of - // id_descriptor_huffman_codecs_. - std::unordered_set descriptors_with_coding_scheme_; - - // Huffman codecs for literal strings. The map key is the opcode of the - // current instruction. This assumes, that there is no more than one literal - // string operand per instruction, but would still work even if this is not - // the case. Names and debug information strings are not collected. - std::map>> - literal_string_huffman_codecs_; - - // Chunk lengths used for variable width encoding of operands (index is - // spv_operand_type of the operand). - std::vector operand_chunk_lengths_; - - uint32_t opcode_chunk_length_ = 7; - uint32_t num_operands_chunk_length_ = 3; - uint32_t mtf_rank_chunk_length_ = 5; - - uint32_t u64_chunk_length_ = 8; - uint32_t s64_chunk_length_ = 8; - uint32_t s64_block_exponent_ = 10; - - IdFallbackStrategy id_fallback_strategy_ = - IdFallbackStrategy::kShortDescriptor; - - uint32_t model_type_ = 0; - uint32_t model_version_ = 0; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_MODEL_H_ diff --git a/3rdparty/spirv-tools/source/comp/move_to_front.cpp b/3rdparty/spirv-tools/source/comp/move_to_front.cpp deleted file mode 100644 index 9d35a3f5b..000000000 --- a/3rdparty/spirv-tools/source/comp/move_to_front.cpp +++ /dev/null @@ -1,456 +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/comp/move_to_front.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -bool MoveToFront::Insert(uint32_t value) { - auto it = value_to_node_.find(value); - if (it != value_to_node_.end() && IsInTree(it->second)) return false; - - const uint32_t old_size = GetSize(); - (void)old_size; - - InsertNode(CreateNode(next_timestamp_++, value)); - - last_accessed_value_ = value; - last_accessed_value_valid_ = true; - - assert(value_to_node_.count(value)); - assert(old_size + 1 == GetSize()); - return true; -} - -bool MoveToFront::Remove(uint32_t value) { - auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) return false; - - if (!IsInTree(it->second)) return false; - - if (last_accessed_value_ == value) last_accessed_value_valid_ = false; - - const uint32_t orphan = RemoveNode(it->second); - (void)orphan; - // The node of |value| is still alive but it's orphaned now. Can still be - // reused later. - assert(!IsInTree(orphan)); - assert(ValueOf(orphan) == value); - return true; -} - -bool MoveToFront::RankFromValue(uint32_t value, uint32_t* rank) { - if (last_accessed_value_valid_ && last_accessed_value_ == value) { - *rank = 1; - return true; - } - - const uint32_t old_size = GetSize(); - if (old_size == 1) { - if (ValueOf(root_) == value) { - *rank = 1; - return true; - } else { - return false; - } - } - - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) { - return false; - } - - uint32_t target = it->second; - - if (!IsInTree(target)) { - return false; - } - - uint32_t node = target; - *rank = 1 + SizeOf(LeftOf(node)); - while (node) { - if (IsRightChild(node)) *rank += 1 + SizeOf(LeftOf(ParentOf(node))); - node = ParentOf(node); - } - - // Don't update timestamp if the node has rank 1. - if (*rank != 1) { - // Update timestamp and reposition the node. - target = RemoveNode(target); - assert(ValueOf(target) == value); - assert(old_size == GetSize() + 1); - MutableTimestampOf(target) = next_timestamp_++; - InsertNode(target); - assert(old_size == GetSize()); - } - - last_accessed_value_ = value; - last_accessed_value_valid_ = true; - return true; -} - -bool MoveToFront::HasValue(uint32_t value) const { - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) { - return false; - } - - return IsInTree(it->second); -} - -bool MoveToFront::Promote(uint32_t value) { - if (last_accessed_value_valid_ && last_accessed_value_ == value) { - return true; - } - - const uint32_t old_size = GetSize(); - if (old_size == 1) return ValueOf(root_) == value; - - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) { - return false; - } - - uint32_t target = it->second; - - if (!IsInTree(target)) { - return false; - } - - // Update timestamp and reposition the node. - target = RemoveNode(target); - assert(ValueOf(target) == value); - assert(old_size == GetSize() + 1); - - MutableTimestampOf(target) = next_timestamp_++; - InsertNode(target); - assert(old_size == GetSize()); - - last_accessed_value_ = value; - last_accessed_value_valid_ = true; - return true; -} - -bool MoveToFront::ValueFromRank(uint32_t rank, uint32_t* value) { - if (last_accessed_value_valid_ && rank == 1) { - *value = last_accessed_value_; - return true; - } - - const uint32_t old_size = GetSize(); - if (rank <= 0 || rank > old_size) { - return false; - } - - if (old_size == 1) { - *value = ValueOf(root_); - return true; - } - - const bool update_timestamp = (rank != 1); - - uint32_t node = root_; - while (node) { - const uint32_t left_subtree_num_nodes = SizeOf(LeftOf(node)); - if (rank == left_subtree_num_nodes + 1) { - // This is the node we are looking for. - // Don't update timestamp if the node has rank 1. - if (update_timestamp) { - node = RemoveNode(node); - assert(old_size == GetSize() + 1); - MutableTimestampOf(node) = next_timestamp_++; - InsertNode(node); - assert(old_size == GetSize()); - } - *value = ValueOf(node); - last_accessed_value_ = *value; - last_accessed_value_valid_ = true; - return true; - } - - if (rank < left_subtree_num_nodes + 1) { - // Descend into the left subtree. The rank is still valid. - node = LeftOf(node); - } else { - // Descend into the right subtree. We leave behind the left subtree and - // the current node, adjust the |rank| accordingly. - rank -= left_subtree_num_nodes + 1; - node = RightOf(node); - } - } - - assert(0); - return false; -} - -uint32_t MoveToFront::CreateNode(uint32_t timestamp, uint32_t value) { - uint32_t handle = static_cast(nodes_.size()); - const auto result = value_to_node_.emplace(value, handle); - if (result.second) { - // Create new node. - nodes_.emplace_back(Node()); - Node& node = nodes_.back(); - node.timestamp = timestamp; - node.value = value; - node.size = 1; - // Non-NIL nodes start with height 1 because their NIL children are - // leaves. - node.height = 1; - } else { - // Reuse old node. - handle = result.first->second; - assert(!IsInTree(handle)); - assert(ValueOf(handle) == value); - assert(SizeOf(handle) == 1); - assert(HeightOf(handle) == 1); - MutableTimestampOf(handle) = timestamp; - } - - return handle; -} - -void MoveToFront::InsertNode(uint32_t node) { - assert(!IsInTree(node)); - assert(SizeOf(node) == 1); - assert(HeightOf(node) == 1); - assert(TimestampOf(node)); - - if (!root_) { - root_ = node; - return; - } - - uint32_t iter = root_; - uint32_t parent = 0; - - // Will determine if |node| will become the right or left child after - // insertion (but before balancing). - bool right_child = true; - - // Find the node which will become |node|'s parent after insertion - // (but before balancing). - while (iter) { - parent = iter; - assert(TimestampOf(iter) != TimestampOf(node)); - right_child = TimestampOf(iter) > TimestampOf(node); - iter = right_child ? RightOf(iter) : LeftOf(iter); - } - - assert(parent); - - // Connect node and parent. - MutableParentOf(node) = parent; - if (right_child) - MutableRightOf(parent) = node; - else - MutableLeftOf(parent) = node; - - // Insertion is finished. Start the balancing process. - bool needs_rebalancing = true; - parent = ParentOf(node); - - while (parent) { - UpdateNode(parent); - - if (needs_rebalancing) { - const int parent_balance = BalanceOf(parent); - - if (RightOf(parent) == node) { - // Added node to the right subtree. - if (parent_balance > 1) { - // Parent is right heavy, rotate left. - if (BalanceOf(node) < 0) RotateRight(node); - parent = RotateLeft(parent); - } else if (parent_balance == 0 || parent_balance == -1) { - // Parent is balanced or left heavy, no need to balance further. - needs_rebalancing = false; - } - } else { - // Added node to the left subtree. - if (parent_balance < -1) { - // Parent is left heavy, rotate right. - if (BalanceOf(node) > 0) RotateLeft(node); - parent = RotateRight(parent); - } else if (parent_balance == 0 || parent_balance == 1) { - // Parent is balanced or right heavy, no need to balance further. - needs_rebalancing = false; - } - } - } - - assert(BalanceOf(parent) >= -1 && (BalanceOf(parent) <= 1)); - - node = parent; - parent = ParentOf(parent); - } -} - -uint32_t MoveToFront::RemoveNode(uint32_t node) { - if (LeftOf(node) && RightOf(node)) { - // If |node| has two children, then use another node as scapegoat and swap - // their contents. We pick the scapegoat on the side of the tree which has - // more nodes. - const uint32_t scapegoat = SizeOf(LeftOf(node)) >= SizeOf(RightOf(node)) - ? RightestDescendantOf(LeftOf(node)) - : LeftestDescendantOf(RightOf(node)); - assert(scapegoat); - std::swap(MutableValueOf(node), MutableValueOf(scapegoat)); - std::swap(MutableTimestampOf(node), MutableTimestampOf(scapegoat)); - value_to_node_[ValueOf(node)] = node; - value_to_node_[ValueOf(scapegoat)] = scapegoat; - node = scapegoat; - } - - // |node| may have only one child at this point. - assert(!RightOf(node) || !LeftOf(node)); - - uint32_t parent = ParentOf(node); - uint32_t child = RightOf(node) ? RightOf(node) : LeftOf(node); - - // Orphan |node| and reconnect parent and child. - if (child) MutableParentOf(child) = parent; - - if (parent) { - if (LeftOf(parent) == node) - MutableLeftOf(parent) = child; - else - MutableRightOf(parent) = child; - } - - MutableParentOf(node) = 0; - MutableLeftOf(node) = 0; - MutableRightOf(node) = 0; - UpdateNode(node); - const uint32_t orphan = node; - - if (root_ == node) root_ = child; - - // Removal is finished. Start the balancing process. - bool needs_rebalancing = true; - node = child; - - while (parent) { - UpdateNode(parent); - - if (needs_rebalancing) { - const int parent_balance = BalanceOf(parent); - - if (parent_balance == 1 || parent_balance == -1) { - // The height of the subtree was not changed. - needs_rebalancing = false; - } else { - if (RightOf(parent) == node) { - // Removed node from the right subtree. - if (parent_balance < -1) { - // Parent is left heavy, rotate right. - const uint32_t sibling = LeftOf(parent); - if (BalanceOf(sibling) > 0) RotateLeft(sibling); - parent = RotateRight(parent); - } - } else { - // Removed node from the left subtree. - if (parent_balance > 1) { - // Parent is right heavy, rotate left. - const uint32_t sibling = RightOf(parent); - if (BalanceOf(sibling) < 0) RotateRight(sibling); - parent = RotateLeft(parent); - } - } - } - } - - assert(BalanceOf(parent) >= -1 && (BalanceOf(parent) <= 1)); - - node = parent; - parent = ParentOf(parent); - } - - return orphan; -} - -uint32_t MoveToFront::RotateLeft(const uint32_t node) { - const uint32_t pivot = RightOf(node); - assert(pivot); - - // LeftOf(pivot) gets attached to node in place of pivot. - MutableRightOf(node) = LeftOf(pivot); - if (RightOf(node)) MutableParentOf(RightOf(node)) = node; - - // Pivot gets attached to ParentOf(node) in place of node. - MutableParentOf(pivot) = ParentOf(node); - if (!ParentOf(node)) - root_ = pivot; - else if (IsLeftChild(node)) - MutableLeftOf(ParentOf(node)) = pivot; - else - MutableRightOf(ParentOf(node)) = pivot; - - // Node is child of pivot. - MutableLeftOf(pivot) = node; - MutableParentOf(node) = pivot; - - // Update both node and pivot. Pivot is the new parent of node, so node should - // be updated first. - UpdateNode(node); - UpdateNode(pivot); - - return pivot; -} - -uint32_t MoveToFront::RotateRight(const uint32_t node) { - const uint32_t pivot = LeftOf(node); - assert(pivot); - - // RightOf(pivot) gets attached to node in place of pivot. - MutableLeftOf(node) = RightOf(pivot); - if (LeftOf(node)) MutableParentOf(LeftOf(node)) = node; - - // Pivot gets attached to ParentOf(node) in place of node. - MutableParentOf(pivot) = ParentOf(node); - if (!ParentOf(node)) - root_ = pivot; - else if (IsLeftChild(node)) - MutableLeftOf(ParentOf(node)) = pivot; - else - MutableRightOf(ParentOf(node)) = pivot; - - // Node is child of pivot. - MutableRightOf(pivot) = node; - MutableParentOf(node) = pivot; - - // Update both node and pivot. Pivot is the new parent of node, so node should - // be updated first. - UpdateNode(node); - UpdateNode(pivot); - - return pivot; -} - -void MoveToFront::UpdateNode(uint32_t node) { - MutableSizeOf(node) = 1 + SizeOf(LeftOf(node)) + SizeOf(RightOf(node)); - MutableHeightOf(node) = - 1 + std::max(HeightOf(LeftOf(node)), HeightOf(RightOf(node))); -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/comp/move_to_front.h b/3rdparty/spirv-tools/source/comp/move_to_front.h deleted file mode 100644 index 8752194ec..000000000 --- a/3rdparty/spirv-tools/source/comp/move_to_front.h +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_COMP_MOVE_TO_FRONT_H_ -#define SOURCE_COMP_MOVE_TO_FRONT_H_ - -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -// Log(n) move-to-front implementation. Implements the following functions: -// Insert - pushes value to the front of the mtf sequence -// (only unique values allowed). -// Remove - remove value from the sequence. -// ValueFromRank - access value by its 1-indexed rank in the sequence. -// RankFromValue - get the rank of the given value in the sequence. -// Accessing a value with ValueFromRank or RankFromValue moves the value to the -// front of the sequence (rank of 1). -// -// The implementation is based on an AVL-based order statistic tree. The tree -// is ordered by timestamps issued when values are inserted or accessed (recent -// values go to the left side of the tree, old values are gradually rotated to -// the right side). -// -// Terminology -// rank: 1-indexed rank showing how recently the value was inserted or accessed. -// node: handle used internally to access node data. -// size: size of the subtree of a node (including the node). -// height: distance from a node to the farthest leaf. -class MoveToFront { - public: - explicit MoveToFront(size_t reserve_capacity = 4) { - nodes_.reserve(reserve_capacity); - - // Create NIL node. - nodes_.emplace_back(Node()); - } - - virtual ~MoveToFront() = default; - - // Inserts value in the move-to-front sequence. Does nothing if the value is - // already in the sequence. Returns true if insertion was successful. - // The inserted value is placed at the front of the sequence (rank 1). - bool Insert(uint32_t value); - - // Removes value from move-to-front sequence. Returns false iff the value - // was not found. - bool Remove(uint32_t value); - - // Computes 1-indexed rank of value in the move-to-front sequence and moves - // the value to the front. Example: - // Before the call: 4 8 2 1 7 - // RankFromValue(8) returns 2 - // After the call: 8 4 2 1 7 - // Returns true iff the value was found in the sequence. - bool RankFromValue(uint32_t value, uint32_t* rank); - - // Returns value corresponding to a 1-indexed rank in the move-to-front - // sequence and moves the value to the front. Example: - // Before the call: 4 8 2 1 7 - // ValueFromRank(2) returns 8 - // After the call: 8 4 2 1 7 - // Returns true iff the rank is within bounds [1, GetSize()]. - bool ValueFromRank(uint32_t rank, uint32_t* value); - - // Moves the value to the front of the sequence. - // Returns false iff value is not in the sequence. - bool Promote(uint32_t value); - - // Returns true iff the move-to-front sequence contains the value. - bool HasValue(uint32_t value) const; - - // Returns the number of elements in the move-to-front sequence. - uint32_t GetSize() const { return SizeOf(root_); } - - protected: - // Internal tree data structure uses handles instead of pointers. Leaves and - // root parent reference a singleton under handle 0. Although dereferencing - // a null pointer is not possible, inappropriate access to handle 0 would - // cause an assertion. Handles are not garbage collected if value was - // deprecated - // with DeprecateValue(). But handles are recycled when a node is - // repositioned. - - // Internal tree data structure node. - struct Node { - // Timestamp from a logical clock which updates every time the element is - // accessed through ValueFromRank or RankFromValue. - uint32_t timestamp = 0; - // The size of the node's subtree, including the node. - // SizeOf(LeftOf(node)) + SizeOf(RightOf(node)) + 1. - uint32_t size = 0; - // Handles to connected nodes. - uint32_t left = 0; - uint32_t right = 0; - uint32_t parent = 0; - // Distance to the farthest leaf. - // Leaves have height 0, real nodes at least 1. - uint32_t height = 0; - // Stored value. - uint32_t value = 0; - }; - - // Creates node and sets correct values. Non-NIL nodes should be created only - // through this function. If the node with this value has been created - // previously - // and since orphaned, reuses the old node instead of creating a new one. - uint32_t CreateNode(uint32_t timestamp, uint32_t value); - - // Node accessor methods. Naming is designed to be similar to natural - // language as these functions tend to be used in sequences, for example: - // ParentOf(LeftestDescendentOf(RightOf(node))) - - // Returns value of the node referenced by |handle|. - uint32_t ValueOf(uint32_t node) const { return nodes_.at(node).value; } - - // Returns left child of |node|. - uint32_t LeftOf(uint32_t node) const { return nodes_.at(node).left; } - - // Returns right child of |node|. - uint32_t RightOf(uint32_t node) const { return nodes_.at(node).right; } - - // Returns parent of |node|. - uint32_t ParentOf(uint32_t node) const { return nodes_.at(node).parent; } - - // Returns timestamp of |node|. - uint32_t TimestampOf(uint32_t node) const { - assert(node); - return nodes_.at(node).timestamp; - } - - // Returns size of |node|. - uint32_t SizeOf(uint32_t node) const { return nodes_.at(node).size; } - - // Returns height of |node|. - uint32_t HeightOf(uint32_t node) const { return nodes_.at(node).height; } - - // Returns mutable reference to value of |node|. - uint32_t& MutableValueOf(uint32_t node) { - assert(node); - return nodes_.at(node).value; - } - - // Returns mutable reference to handle of left child of |node|. - uint32_t& MutableLeftOf(uint32_t node) { - assert(node); - return nodes_.at(node).left; - } - - // Returns mutable reference to handle of right child of |node|. - uint32_t& MutableRightOf(uint32_t node) { - assert(node); - return nodes_.at(node).right; - } - - // Returns mutable reference to handle of parent of |node|. - uint32_t& MutableParentOf(uint32_t node) { - assert(node); - return nodes_.at(node).parent; - } - - // Returns mutable reference to timestamp of |node|. - uint32_t& MutableTimestampOf(uint32_t node) { - assert(node); - return nodes_.at(node).timestamp; - } - - // Returns mutable reference to size of |node|. - uint32_t& MutableSizeOf(uint32_t node) { - assert(node); - return nodes_.at(node).size; - } - - // Returns mutable reference to height of |node|. - uint32_t& MutableHeightOf(uint32_t node) { - assert(node); - return nodes_.at(node).height; - } - - // Returns true iff |node| is left child of its parent. - bool IsLeftChild(uint32_t node) const { - assert(node); - return LeftOf(ParentOf(node)) == node; - } - - // Returns true iff |node| is right child of its parent. - bool IsRightChild(uint32_t node) const { - assert(node); - return RightOf(ParentOf(node)) == node; - } - - // Returns true iff |node| has no relatives. - bool IsOrphan(uint32_t node) const { - assert(node); - return !ParentOf(node) && !LeftOf(node) && !RightOf(node); - } - - // Returns true iff |node| is in the tree. - bool IsInTree(uint32_t node) const { - assert(node); - return node == root_ || !IsOrphan(node); - } - - // Returns the height difference between right and left subtrees. - int BalanceOf(uint32_t node) const { - return int(HeightOf(RightOf(node))) - int(HeightOf(LeftOf(node))); - } - - // Updates size and height of the node, assuming that the children have - // correct values. - void UpdateNode(uint32_t node); - - // Returns the most LeftOf(LeftOf(... descendent which is not leaf. - uint32_t LeftestDescendantOf(uint32_t node) const { - uint32_t parent = 0; - while (node) { - parent = node; - node = LeftOf(node); - } - return parent; - } - - // Returns the most RightOf(RightOf(... descendent which is not leaf. - uint32_t RightestDescendantOf(uint32_t node) const { - uint32_t parent = 0; - while (node) { - parent = node; - node = RightOf(node); - } - return parent; - } - - // Inserts node in the tree. The node must be an orphan. - void InsertNode(uint32_t node); - - // Removes node from the tree. May change value_to_node_ if removal uses a - // scapegoat. Returns the removed (orphaned) handle for recycling. The - // returned handle may not be equal to |node| if scapegoat was used. - uint32_t RemoveNode(uint32_t node); - - // Rotates |node| left, reassigns all connections and returns the node - // which takes place of the |node|. - uint32_t RotateLeft(const uint32_t node); - - // Rotates |node| right, reassigns all connections and returns the node - // which takes place of the |node|. - uint32_t RotateRight(const uint32_t node); - - // Root node handle. The tree is empty if root_ is 0. - uint32_t root_ = 0; - - // Incremented counters for next timestamp and value. - uint32_t next_timestamp_ = 1; - - // Holds all tree nodes. Indices of this vector are node handles. - std::vector nodes_; - - // Maps ids to node handles. - std::unordered_map value_to_node_; - - // Cache for the last accessed value in the sequence. - uint32_t last_accessed_value_ = 0; - bool last_accessed_value_valid_ = false; -}; - -class MultiMoveToFront { - public: - // Inserts |value| to sequence with handle |mtf|. - // Returns false if |mtf| already has |value|. - bool Insert(uint64_t mtf, uint32_t value) { - if (GetMtf(mtf).Insert(value)) { - val_to_mtfs_[value].insert(mtf); - return true; - } - return false; - } - - // Removes |value| from sequence with handle |mtf|. - // Returns false if |mtf| doesn't have |value|. - bool Remove(uint64_t mtf, uint32_t value) { - if (GetMtf(mtf).Remove(value)) { - val_to_mtfs_[value].erase(mtf); - return true; - } - assert(val_to_mtfs_[value].count(mtf) == 0); - return false; - } - - // Removes |value| from all sequences which have it. - void RemoveFromAll(uint32_t value) { - auto it = val_to_mtfs_.find(value); - if (it == val_to_mtfs_.end()) return; - - auto& mtfs_containing_value = it->second; - for (uint64_t mtf : mtfs_containing_value) { - GetMtf(mtf).Remove(value); - } - - val_to_mtfs_.erase(value); - } - - // Computes rank of |value| in sequence |mtf|. - // Returns false if |mtf| doesn't have |value|. - bool RankFromValue(uint64_t mtf, uint32_t value, uint32_t* rank) { - return GetMtf(mtf).RankFromValue(value, rank); - } - - // Finds |value| with |rank| in sequence |mtf|. - // Returns false if |rank| is out of bounds. - bool ValueFromRank(uint64_t mtf, uint32_t rank, uint32_t* value) { - return GetMtf(mtf).ValueFromRank(rank, value); - } - - // Returns size of |mtf| sequence. - uint32_t GetSize(uint64_t mtf) { return GetMtf(mtf).GetSize(); } - - // Promotes |value| in all sequences which have it. - void Promote(uint32_t value) { - const auto it = val_to_mtfs_.find(value); - if (it == val_to_mtfs_.end()) return; - - const auto& mtfs_containing_value = it->second; - for (uint64_t mtf : mtfs_containing_value) { - GetMtf(mtf).Promote(value); - } - } - - // Inserts |value| in sequence |mtf| or promotes if it's already there. - void InsertOrPromote(uint64_t mtf, uint32_t value) { - if (!Insert(mtf, value)) { - GetMtf(mtf).Promote(value); - } - } - - // Returns if |mtf| sequence has |value|. - bool HasValue(uint64_t mtf, uint32_t value) { - return GetMtf(mtf).HasValue(value); - } - - private: - // Returns actual MoveToFront object corresponding to |handle|. - // As multiple operations are often performed consecutively for the same - // sequence, the last returned value is cached. - MoveToFront& GetMtf(uint64_t handle) { - if (!cached_mtf_ || cached_handle_ != handle) { - cached_handle_ = handle; - cached_mtf_ = &mtfs_[handle]; - } - - return *cached_mtf_; - } - - // Container holding MoveToFront objects. Map key is sequence handle. - std::map mtfs_; - - // Container mapping value to sequences which contain that value. - std::unordered_map> val_to_mtfs_; - - // Cache for the last accessed sequence. - uint64_t cached_handle_ = 0; - MoveToFront* cached_mtf_ = nullptr; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MOVE_TO_FRONT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt new file mode 100644 index 000000000..c1c0c1f82 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt @@ -0,0 +1,120 @@ +# 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. + +if(SPIRV_BUILD_FUZZER) + set(PROTOBUF_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/protobufs/spvtoolsfuzz.proto) + + add_custom_command( + OUTPUT protobufs/spvtoolsfuzz.pb.cc protobufs/spvtoolsfuzz.pb.h + COMMAND protobuf::protoc + -I=${CMAKE_CURRENT_SOURCE_DIR}/protobufs + --cpp_out=protobufs + ${PROTOBUF_SOURCE} + DEPENDS ${PROTOBUF_SOURCE} + COMMENT "Generate protobuf sources from proto definition file." + ) + + set(SPIRV_TOOLS_FUZZ_SOURCES + fact_manager.h + fuzzer.h + fuzzer_context.h + fuzzer_pass.h + fuzzer_pass_add_useful_constructs.h + fuzzer_pass_add_dead_breaks.h + fuzzer_pass_permute_blocks.h + fuzzer_pass_split_blocks.h + fuzzer_util.h + id_use_descriptor.h + protobufs/spirvfuzz_protobufs.h + pseudo_random_generator.h + random_generator.h + transformation_add_constant_boolean.h + transformation_add_constant_scalar.h + transformation_add_dead_break.h + transformation_add_type_boolean.h + transformation_add_type_float.h + transformation_add_type_int.h + transformation_move_block_down.h + transformation_replace_boolean_constant_with_constant_binary.h + transformation_split_block.h + ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h + + fact_manager.cpp + fuzzer.cpp + fuzzer_context.cpp + fuzzer_pass.cpp + fuzzer_pass_add_dead_breaks.cpp + fuzzer_pass_add_useful_constructs.cpp + fuzzer_pass_permute_blocks.cpp + fuzzer_pass_split_blocks.cpp + fuzzer_util.cpp + id_use_descriptor.cpp + pseudo_random_generator.cpp + random_generator.cpp + transformation_add_constant_boolean.cpp + transformation_add_constant_scalar.cpp + transformation_add_dead_break.cpp + transformation_add_type_boolean.cpp + transformation_add_type_float.cpp + transformation_add_type_int.cpp + transformation_move_block_down.cpp + transformation_replace_boolean_constant_with_constant_binary.cpp + transformation_split_block.cpp + ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc + ) + + if(MSVC) + # Enable parallel builds across four cores for this lib + add_definitions(/MP4) + endif() + + spvtools_pch(SPIRV_TOOLS_FUZZ_SOURCES pch_source_fuzz) + + add_library(SPIRV-Tools-fuzz ${SPIRV_TOOLS_FUZZ_SOURCES}) + + spvtools_default_compile_options(SPIRV-Tools-fuzz) + target_compile_definitions(SPIRV-Tools-fuzz PUBLIC -DGOOGLE_PROTOBUF_NO_RTTI -DGOOGLE_PROTOBUF_USE_UNALIGNED=0) + + # Compilation of the auto-generated protobuf source file will yield warnings, + # which we have no control over and thus wish to ignore. + if(${COMPILER_IS_LIKE_GNU}) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS -w) + endif() + if(MSVC) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS /w) + endif() + + target_include_directories(SPIRV-Tools-fuzz + PUBLIC ${spirv-tools_SOURCE_DIR}/include + PUBLIC ${SPIRV_HEADER_INCLUDE_DIR} + PRIVATE ${spirv-tools_BINARY_DIR} + PRIVATE ${CMAKE_BINARY_DIR}) + + # The fuzzer reuses a lot of functionality from the SPIRV-Tools library. + target_link_libraries(SPIRV-Tools-fuzz + PUBLIC ${SPIRV_TOOLS} + PUBLIC SPIRV-Tools-opt + PUBLIC protobuf::libprotobuf) + + set_property(TARGET SPIRV-Tools-fuzz PROPERTY FOLDER "SPIRV-Tools libraries") + spvtools_check_symbol_exports(SPIRV-Tools-fuzz) + + if(ENABLE_SPIRV_TOOLS_INSTALL) + install(TARGETS SPIRV-Tools-fuzz + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(ENABLE_SPIRV_TOOLS_INSTALL) + +endif(SPIRV_BUILD_FUZZER) diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp new file mode 100644 index 000000000..1c1928789 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp @@ -0,0 +1,46 @@ +// 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 + +#include "source/fuzz/fact_manager.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +FactManager::FactManager() = default; + +FactManager::~FactManager() = default; + +bool FactManager::AddFacts(const protobufs::FactSequence& initial_facts, + opt::IRContext* context) { + for (auto& fact : initial_facts.fact()) { + if (!AddFact(fact, context)) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2621) Provide + // information about the fact that could not be added. + return false; + } + } + return true; +} + +bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact&, + spvtools::opt::IRContext*) { + assert(0 && "No facts are yet supported."); + return true; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager.h b/3rdparty/spirv-tools/source/fuzz/fact_manager.h new file mode 100644 index 000000000..49b6d6dc8 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fact_manager.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_FACT_MANAGER_H_ +#define SOURCE_FUZZ_FACT_MANAGER_H_ + +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/constants.h" + +namespace spvtools { +namespace fuzz { + +// Keeps track of facts about the module being transformed on which the fuzzing +// process can depend. Some initial facts can be provided, for example about +// guarantees on the values of inputs to SPIR-V entry points. Transformations +// may then rely on these facts, can add further facts that they establish. +// Facts are intended to be simple properties that either cannot be deduced from +// the module (such as properties that are guaranteed to hold for entry point +// inputs), or that are established by transformations, likely to be useful for +// future transformations, and not completely trivial to deduce straight from +// the module. +class FactManager { + public: + FactManager(); + + ~FactManager(); + + // Adds all the facts from |facts|, checking them for validity with respect to + // |context|. Returns true if and only if all facts are valid. + bool AddFacts(const protobufs::FactSequence& facts, opt::IRContext* context); + + // Adds |fact| to the fact manager, checking it for validity with respect to + // |context|. Returns true if and only if the fact is valid. + bool AddFact(const protobufs::Fact& fact, opt::IRContext* context); +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // #define SOURCE_FUZZ_FACT_MANAGER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp new file mode 100644 index 000000000..25c24fc9d --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp @@ -0,0 +1,131 @@ +// 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.h" + +#include +#include + +#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_useful_constructs.h" +#include "source/fuzz/fuzzer_pass_permute_blocks.h" +#include "source/fuzz/fuzzer_pass_split_blocks.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/pseudo_random_generator.h" +#include "source/opt/build_module.h" +#include "source/spirv_fuzzer_options.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +namespace { +const uint32_t kIdBoundGap = 100; +} + +struct Fuzzer::Impl { + explicit Impl(spv_target_env env) : target_env(env) {} + + const spv_target_env target_env; // Target environment. + MessageConsumer consumer; // Message consumer. +}; + +Fuzzer::Fuzzer(spv_target_env env) : impl_(MakeUnique(env)) {} + +Fuzzer::~Fuzzer() = default; + +void Fuzzer::SetMessageConsumer(MessageConsumer c) { + impl_->consumer = std::move(c); +} + +Fuzzer::FuzzerResultStatus Fuzzer::Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out, + spv_const_fuzzer_options options) const { + // Check compatibility between the library version being linked with and the + // header files being used. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + spvtools::SpirvTools tools(impl_->target_env); + if (!tools.IsValid()) { + impl_->consumer(SPV_MSG_ERROR, nullptr, {}, + "Failed to create SPIRV-Tools interface; stopping."); + return Fuzzer::FuzzerResultStatus::kFailedToCreateSpirvToolsInterface; + } + + // Initial binary should be valid. + if (!tools.Validate(&binary_in[0], binary_in.size())) { + impl_->consumer(SPV_MSG_ERROR, nullptr, {}, + "Initial binary is invalid; stopping."); + return Fuzzer::FuzzerResultStatus::kInitialBinaryInvalid; + } + + // Build the module from the input binary. + std::unique_ptr ir_context = BuildModule( + impl_->target_env, impl_->consumer, binary_in.data(), binary_in.size()); + assert(ir_context); + + // Make a PRNG, either from a given seed or from a random device. + PseudoRandomGenerator random_generator( + options->has_random_seed ? options->random_seed + : static_cast(std::random_device()())); + + // The fuzzer will introduce new ids into the module. The module's id bound + // gives the smallest id that can be used for this purpose. We add an offset + // to this so that there is a sizeable gap between the ids used in the + // original module and the ids used for fuzzing, as a readability aid. + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the + // case where the maximum id bound is reached. + auto minimum_fresh_id = ir_context->module()->id_bound() + kIdBoundGap; + FuzzerContext fuzzer_context(&random_generator, minimum_fresh_id); + + FactManager fact_manager; + if (!fact_manager.AddFacts(initial_facts, ir_context.get())) { + return Fuzzer::FuzzerResultStatus::kInitialFactsInvalid; + } + + // Add some essential ingredients to the module if they are not already + // present, such as boolean constants. + FuzzerPassAddUsefulConstructs(ir_context.get(), &fact_manager, + &fuzzer_context, transformation_sequence_out) + .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(); + + // TODO(afd) Various other passes will be added. + + // Finally, give the blocks in the module a good shake-up. + FuzzerPassPermuteBlocks(ir_context.get(), &fact_manager, &fuzzer_context, + transformation_sequence_out) + .Apply(); + + // Encode the module as a binary. + ir_context->module()->ToBinary(binary_out, false); + + return Fuzzer::FuzzerResultStatus::kComplete; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer.h b/3rdparty/spirv-tools/source/fuzz/fuzzer.h new file mode 100644 index 000000000..f81f29793 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer.h @@ -0,0 +1,74 @@ +// 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_H_ +#define SOURCE_FUZZ_FUZZER_H_ + +#include +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace fuzz { + +// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by +// running a number of randomized fuzzer passes. +class Fuzzer { + public: + // Possible statuses that can result from running the fuzzer. + enum class FuzzerResultStatus { + kComplete, + kFailedToCreateSpirvToolsInterface, + kInitialBinaryInvalid, + kInitialFactsInvalid, + }; + + // Constructs a fuzzer from the given target environment. + explicit Fuzzer(spv_target_env env); + + // Disables copy/move constructor/assignment operations. + Fuzzer(const Fuzzer&) = delete; + Fuzzer(Fuzzer&&) = delete; + Fuzzer& operator=(const Fuzzer&) = delete; + Fuzzer& operator=(Fuzzer&&) = delete; + + ~Fuzzer(); + + // Sets the message consumer to the given |consumer|. The |consumer| will be + // invoked once for each message communicated from the library. + void SetMessageConsumer(MessageConsumer consumer); + + // Transforms |binary_in| to |binary_out| by running a number of randomized + // fuzzer passes, controlled via |options|. Initial facts about the input + // binary and the context in which it will execute are provided via + // |initial_facts|. The transformation sequence that was applied is returned + // via |transformation_sequence_out|. + FuzzerResultStatus Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out, + spv_const_fuzzer_options options) const; + + private: + struct Impl; // Opaque struct for holding internal data. + std::unique_ptr impl_; // Unique pointer to internal data. +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp new file mode 100644 index 000000000..b50dfab14 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp @@ -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. + +#include "source/fuzz/fuzzer_context.h" + +namespace spvtools { +namespace fuzz { + +namespace { +// Default probabilities for applying various transformations. +// All values are percentages. +// Keep them in alphabetical order. + +const uint32_t kDefaultChanceOfAddingDeadBreak = 20; +const uint32_t kDefaultChanceOfMovingBlockDown = 25; +const uint32_t kDefaultChanceOfSplittingBlock = 20; + +} // namespace + +FuzzerContext::FuzzerContext(RandomGenerator* random_generator, + uint32_t min_fresh_id) + : random_generator_(random_generator), + next_fresh_id_(min_fresh_id), + chance_of_adding_dead_break_(kDefaultChanceOfAddingDeadBreak), + chance_of_moving_block_down_(kDefaultChanceOfMovingBlockDown), + chance_of_splitting_block_(kDefaultChanceOfSplittingBlock) {} + +FuzzerContext::~FuzzerContext() = default; + +uint32_t FuzzerContext::GetFreshId() { return next_fresh_id_++; } + +RandomGenerator* FuzzerContext::GetRandomGenerator() { + return random_generator_; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h new file mode 100644 index 000000000..936ffbc90 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h @@ -0,0 +1,64 @@ +// 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_CONTEXT_H_ +#define SOURCE_FUZZ_FUZZER_CONTEXT_H_ + +#include "source/fuzz/random_generator.h" +#include "source/opt/function.h" + +namespace spvtools { +namespace fuzz { + +// Encapsulates all parameters that control the fuzzing process, such as the +// source of randomness and the probabilities with which transformations are +// applied. +class FuzzerContext { + public: + // Constructs a fuzzer context with a given random generator and the minimum + // value that can be used for fresh ids. + FuzzerContext(RandomGenerator* random_generator, uint32_t min_fresh_id); + + ~FuzzerContext(); + + // Provides the random generator used to control fuzzing. + RandomGenerator* GetRandomGenerator(); + + // Yields an id that is guaranteed not to be used in the module being fuzzed, + // or to have been issued before. + uint32_t GetFreshId(); + + // Probabilities associated with applying various transformations. + // Keep them in alphabetical order. + uint32_t GetChanceOfAddingDeadBreak() { return chance_of_adding_dead_break_; } + uint32_t GetChanceOfMovingBlockDown() { return chance_of_moving_block_down_; } + uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; } + + private: + // The source of randomness. + RandomGenerator* random_generator_; + // The next fresh id to be issued. + uint32_t next_fresh_id_; + + // Probabilities associated with applying various transformations. + // Keep them in alphabetical order. + uint32_t chance_of_adding_dead_break_; + uint32_t chance_of_moving_block_down_; + uint32_t chance_of_splitting_block_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_CONTEXT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp new file mode 100644 index 000000000..823f2e09a --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp @@ -0,0 +1,31 @@ +// 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.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPass::FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : ir_context_(ir_context), + fact_manager_(fact_manager), + fuzzer_context_(fuzzer_context), + transformations_(transformations) {} + +FuzzerPass::~FuzzerPass() = default; + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h new file mode 100644 index 000000000..4d0861e6f --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h @@ -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. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/fuzzer_context.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" + +namespace spvtools { +namespace fuzz { + +// Interface for applying a pass of transformations to a module. +class FuzzerPass { + public: + FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + virtual ~FuzzerPass(); + + // Applies the pass to the module |ir_context_|, assuming and updating + // facts from |fact_manager_|, and using |fuzzer_context_| to guide the + // process. Appends to |transformations_| all transformations that were + // applied during the pass. + virtual void Apply() = 0; + + protected: + opt::IRContext* GetIRContext() const { return ir_context_; } + + FactManager* GetFactManager() const { return fact_manager_; } + + FuzzerContext* GetFuzzerContext() const { return fuzzer_context_; } + + protobufs::TransformationSequence* GetTransformations() const { + return transformations_; + } + + private: + opt::IRContext* ir_context_; + FactManager* fact_manager_; + FuzzerContext* fuzzer_context_; + protobufs::TransformationSequence* transformations_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // #define SOURCE_FUZZ_FUZZER_PASS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp new file mode 100644 index 000000000..eef28d91d --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp @@ -0,0 +1,105 @@ +// 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_dead_breaks.h" + +#include "source/fuzz/transformation_add_dead_break.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default; + +void FuzzerPassAddDeadBreaks::Apply() { + // We first collect up lots of possibly-applicable transformations. + std::vector candidate_transformations; + // We consider each function separately. + for (auto& function : *GetIRContext()->module()) { + // For a given function, we find all the merge blocks in that function. + std::vector merge_block_ids; + for (auto& block : function) { + auto maybe_merge_id = block.MergeBlockIdIfAny(); + if (maybe_merge_id) { + merge_block_ids.push_back(maybe_merge_id); + } + } + // We rather aggressively consider the possibility of adding a break from + // every block in the function to every merge block. Many of these will be + // inapplicable as they would be illegal. That's OK - we later discard the + // 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. + std::vector phi_ids; + auto candidate_transformation = + transformation::MakeTransformationAddDeadBreak( + block.id(), merge_block_id, + GetFuzzerContext()->GetRandomGenerator()->RandomBool(), + std::move(phi_ids)); + if (transformation::IsApplicable(candidate_transformation, + GetIRContext(), *GetFactManager())) { + // Only consider a transformation as a candidate if it is applicable. + candidate_transformations.push_back( + std::move(candidate_transformation)); + } + } + } + } + + // Go through the candidate transformations that were accumulated, + // probabilistically deciding whether to consider each one further and + // applying the still-applicable ones that are considered further. + // + // We iterate through the candidate transformations in a random order by + // repeatedly removing a random candidate transformation from the sequence + // until no candidate transformations remain. This is done because + // transformations can potentially disable one another, so that iterating + // through them in order would lead to a higher probability of + // transformations appearing early in the sequence being applied compared + // with later transformations. + while (!candidate_transformations.empty()) { + // Choose a random index into the sequence of remaining candidate + // transformations. + auto index = GetFuzzerContext()->GetRandomGenerator()->RandomUint32( + static_cast(candidate_transformations.size())); + // 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. + if (GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() > + GetFuzzerContext()->GetChanceOfAddingDeadBreak()) { + continue; + } + // If the transformation can be applied, apply it and add it to the + // sequence of transformations that have been applied. + if (transformation::IsApplicable(transformation, GetIRContext(), + *GetFactManager())) { + transformation::Apply(transformation, GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation()->mutable_add_dead_break() = + transformation; + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h new file mode 100644 index 000000000..ad1985653 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.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_ADD_DEAD_BREAKS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for adding dead break edges to the module. +class FuzzerPassAddDeadBreaks : public FuzzerPass { + public: + FuzzerPassAddDeadBreaks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddDeadBreaks(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // #define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp new file mode 100644 index 000000000..335e3cac0 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp @@ -0,0 +1,182 @@ +// 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_useful_constructs.h" + +#include "source/fuzz/transformation_add_constant_boolean.h" +#include "source/fuzz/transformation_add_constant_scalar.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" + +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){}; + +FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default; + +void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant( + uint32_t width, bool is_signed, std::vector data) const { + opt::analysis::Integer temp_int_type(width, is_signed); + assert(GetIRContext()->get_type_mgr()->GetId(&temp_int_type) && + "int type should already be registered."); + auto registered_int_type = GetIRContext() + ->get_type_mgr() + ->GetRegisteredType(&temp_int_type) + ->AsInteger(); + auto int_type_id = GetIRContext()->get_type_mgr()->GetId(registered_int_type); + assert(int_type_id && + "The relevant int type should have been added to the module already."); + opt::analysis::IntConstant int_constant(registered_int_type, data); + if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) { + protobufs::TransformationAddConstantScalar add_constant_int = + transformation::MakeTransformationAddConstantScalar( + GetFuzzerContext()->GetFreshId(), int_type_id, data); + assert(transformation::IsApplicable(add_constant_int, GetIRContext(), + *GetFactManager()) && + "Should be applicable by construction."); + transformation::Apply(add_constant_int, GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation()->mutable_add_constant_scalar() = + add_constant_int; + } +} + +void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant( + uint32_t width, std::vector data) const { + opt::analysis::Float temp_float_type(width); + assert(GetIRContext()->get_type_mgr()->GetId(&temp_float_type) && + "float type should already be registered."); + auto registered_float_type = GetIRContext() + ->get_type_mgr() + ->GetRegisteredType(&temp_float_type) + ->AsFloat(); + auto float_type_id = + GetIRContext()->get_type_mgr()->GetId(registered_float_type); + assert( + float_type_id && + "The relevant float type should have been added to the module already."); + opt::analysis::FloatConstant float_constant(registered_float_type, data); + if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) { + protobufs::TransformationAddConstantScalar add_constant_float = + transformation::MakeTransformationAddConstantScalar( + GetFuzzerContext()->GetFreshId(), float_type_id, data); + assert(transformation::IsApplicable(add_constant_float, GetIRContext(), + *GetFactManager()) && + "Should be applicable by construction."); + transformation::Apply(add_constant_float, GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation()->mutable_add_constant_scalar() = + add_constant_float; + } +} + +void FuzzerPassAddUsefulConstructs::Apply() { + { + // Add boolean type if not present. + opt::analysis::Bool temp_bool_type; + if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) { + protobufs::TransformationAddTypeBoolean add_type_boolean = + transformation::MakeTransformationAddTypeBoolean( + GetFuzzerContext()->GetFreshId()); + assert(transformation::IsApplicable(add_type_boolean, GetIRContext(), + *GetFactManager()) && + "Should be applicable by construction."); + transformation::Apply(add_type_boolean, GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation()->mutable_add_type_boolean() = + add_type_boolean; + } + } + + { + // Add signed and unsigned 32-bit integer types if not present. + for (auto is_signed : {true, false}) { + opt::analysis::Integer temp_int_type(32, is_signed); + if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) { + protobufs::TransformationAddTypeInt add_type_int = + transformation::MakeTransformationAddTypeInt( + GetFuzzerContext()->GetFreshId(), 32, is_signed); + assert(transformation::IsApplicable(add_type_int, GetIRContext(), + *GetFactManager()) && + "Should be applicable by construction."); + transformation::Apply(add_type_int, GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation()->mutable_add_type_int() = + add_type_int; + } + } + } + + { + // Add 32-bit float type if not present. + opt::analysis::Float temp_float_type(32); + if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) { + protobufs::TransformationAddTypeFloat add_type_float = + transformation::MakeTransformationAddTypeFloat( + GetFuzzerContext()->GetFreshId(), 32); + assert(transformation::IsApplicable(add_type_float, GetIRContext(), + *GetFactManager()) && + "Should be applicable by construction."); + transformation::Apply(add_type_float, GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation()->mutable_add_type_float() = + add_type_float; + } + } + + // Add boolean constants true and false if not present. + opt::analysis::Bool temp_bool_type; + auto bool_type = GetIRContext() + ->get_type_mgr() + ->GetRegisteredType(&temp_bool_type) + ->AsBool(); + for (auto boolean_value : {true, false}) { + // Add OpConstantTrue/False if not already there. + opt::analysis::BoolConstant bool_constant(bool_type, boolean_value); + if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) { + protobufs::TransformationAddConstantBoolean add_constant_boolean = + transformation::MakeTransformationAddConstantBoolean( + GetFuzzerContext()->GetFreshId(), boolean_value); + assert(transformation::IsApplicable(add_constant_boolean, GetIRContext(), + *GetFactManager()) && + "Should be applicable by construction."); + transformation::Apply(add_constant_boolean, GetIRContext(), + GetFactManager()); + *GetTransformations() + ->add_transformation() + ->mutable_add_constant_boolean() = add_constant_boolean; + } + } + + // Add signed and unsigned 32-bit integer constants 0 and 1 if not present. + for (auto is_signed : {true, false}) { + for (auto value : {0u, 1u}) { + MaybeAddIntConstant(32, is_signed, {value}); + } + } + + // Add 32-bit float constants 0.0 and 1.0 if not present. + uint32_t uint_data[2]; + float float_data[2] = {0.0, 1.0}; + memcpy(uint_data, float_data, sizeof(float_data)); + for (unsigned int& datum : uint_data) { + MaybeAddFloatConstant(32, {datum}); + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h new file mode 100644 index 000000000..a8ac9a303 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h @@ -0,0 +1,46 @@ +// 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_USEFUL_CONSTRUCTS_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// An initial pass for adding useful ingredients to the module, such as boolean +// constants, if they are not present. +class FuzzerPassAddUsefulConstructs : public FuzzerPass { + public: + FuzzerPassAddUsefulConstructs( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddUsefulConstructs() override; + + void Apply() override; + + private: + void MaybeAddIntConstant(uint32_t width, bool is_signed, + std::vector data) const; + + void MaybeAddFloatConstant(uint32_t width, std::vector data) const; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // #define SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp new file mode 100644 index 000000000..34131dc4c --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp @@ -0,0 +1,85 @@ +// 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_permute_blocks.h" + +#include "source/fuzz/transformation_move_block_down.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassPermuteBlocks::~FuzzerPassPermuteBlocks() = default; + +void FuzzerPassPermuteBlocks::Apply() { + // For now we do something very simple: we randomly decide whether to move a + // block, and for each block that we do move, we push it down as far as we + // legally can. + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2635): it would be + // nice to randomly sample from the set of legal block permutations and then + // encode the chosen permutation via a series of move-block-down + // transformations. This should be possible but will require some thought. + + for (auto& function : *GetIRContext()->module()) { + std::vector block_ids; + // Collect all block ids for the function before messing with block + // ordering. + for (auto& block : function) { + block_ids.push_back(block.id()); + } + // Now consider each block id. We consider block ids in reverse, because + // e.g. in code generated from the following: + // + // if (...) { + // A + // B + // } else { + // C + // } + // + // block A cannot be moved down, but B has freedom to move and that movement + // 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()) { + continue; + } + // Keep pushing the block down, until pushing down fails. + // The loop is guaranteed to terminate because a block cannot be pushed + // down indefinitely. + while (true) { + protobufs::TransformationMoveBlockDown message; + message.set_block_id(*id); + if (transformation::IsApplicable(message, GetIRContext(), + *GetFactManager())) { + transformation::Apply(message, GetIRContext(), GetFactManager()); + *GetTransformations() + ->add_transformation() + ->mutable_move_block_down() = message; + } else { + break; + } + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h new file mode 100644 index 000000000..d8aed72bb --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.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_PERMUTE_BLOCKS_ +#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for shuffling the blocks of the module in a validity-preserving +// manner. +class FuzzerPassPermuteBlocks : public FuzzerPass { + public: + FuzzerPassPermuteBlocks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassPermuteBlocks() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // #define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp new file mode 100644 index 000000000..7c023987f --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp @@ -0,0 +1,99 @@ +// 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_split_blocks.h" + +#include +#include + +#include "source/fuzz/transformation_split_block.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassSplitBlocks::FuzzerPassSplitBlocks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassSplitBlocks::~FuzzerPassSplitBlocks() = default; + +void FuzzerPassSplitBlocks::Apply() { + // Gather up pointers to all the blocks in the module. We are then able to + // iterate over these pointers and split the blocks to which they point; + // we cannot safely split blocks while we iterate through the module. + std::vector blocks; + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + blocks.push_back(&block); + } + } + + // 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()) { + continue; + } + // 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> base_offset_pairs; + // The initial base instruction is the block label. + uint32_t base = block->id(); + uint32_t offset = 0; + // 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. + 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++; + } + base_offset_pairs.emplace_back(base, offset); + } + // 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(base_offset_pairs.size()))]; + auto message = transformation::MakeTransformationSplitBlock( + base_offset.first, base_offset.second, + 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. + if (transformation::IsApplicable(message, GetIRContext(), + *GetFactManager())) { + transformation::Apply(message, GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation()->mutable_split_block() = + message; + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h new file mode 100644 index 000000000..951022b2f --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.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_SPLIT_BLOCKS_ +#define SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for splitting blocks in the module, to create more blocks; this +// can be very useful for giving other passes a chance to apply. +class FuzzerPassSplitBlocks : public FuzzerPass { + public: + FuzzerPassSplitBlocks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassSplitBlocks() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // #define SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp new file mode 100644 index 000000000..645c121d8 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp @@ -0,0 +1,36 @@ +// 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_util.h" + +namespace spvtools { +namespace fuzz { + +namespace fuzzerutil { + +bool IsFreshId(opt::IRContext* context, uint32_t id) { + return !context->get_def_use_mgr()->GetDef(id); +} + +void UpdateModuleIdBound(opt::IRContext* context, uint32_t id) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the + // case where the maximum id bound is reached. + context->module()->SetIdBound( + std::max(context->module()->id_bound(), id + 1)); +} + +} // namespace fuzzerutil + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h new file mode 100644 index 000000000..30d870b4b --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.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_UTIL_H_ +#define SOURCE_FUZZ_FUZZER_UTIL_H_ + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Provides global utility methods for use by the fuzzer +namespace fuzzerutil { + +// Returns true if and only if the module does not define the given id. +bool IsFreshId(opt::IRContext* context, uint32_t id); + +// Updates the module's id bound if needed so that it is large enough to +// account for the given id. +void UpdateModuleIdBound(opt::IRContext* context, uint32_t id); + +} // namespace fuzzerutil + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_UTIL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.cpp b/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.cpp new file mode 100644 index 000000000..33d2ca089 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.cpp @@ -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. + +#include "source/fuzz/id_use_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; + } + } + } + return nullptr; +} + +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 result; + result.set_id_of_interest(id_of_interest); + result.set_target_instruction_opcode(target_instruction_opcode); + 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; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.h b/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.h new file mode 100644 index 000000000..63016c5da --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.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_ID_USE_LOCATOR_H_ +#define SOURCE_FUZZ_ID_USE_LOCATOR_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); + +// 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); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_ID_USE_LOCATOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h b/3rdparty/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h new file mode 100644 index 000000000..b801626bb --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h @@ -0,0 +1,52 @@ +// 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_SPIRVFUZZ_PROTOBUFS_H_ +#define SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ + +// This header file serves to act as a barrier between the protobuf header +// files and files that include them. It uses compiler pragmas to disable +// diagnostics, in order to ignore warnings generated during the processing +// of these header files without having to compromise on freedom from warnings +// in the rest of the project. + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + +// The following should be the only place in the project where protobuf files +// are directly included. This is so that they can be compiled in a manner +// where warnings are ignored. + +#include "google/protobuf/util/json_util.h" +#include "source/fuzz/protobufs/spvtoolsfuzz.pb.h" + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto new file mode 100644 index 000000000..f00c51874 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -0,0 +1,226 @@ +// 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. + +// This file is specifically named spvtools_fuzz.proto so that the string +// 'spvtools_fuzz' appears in the names of global-scope symbols that protoc +// generates when targeting C++. This is to reduce the potential for name +// clashes with other globally-scoped symbols. + +syntax = "proto3"; + +package spvtools.fuzz.protobufs; + +message IdUseDescriptor { + + // 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 + // - 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 + // instruction found from instruction 50 onwards (i.e. 7 OpStore + // instructions are skipped). + + // 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. + 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 FactSequence { + repeated Fact fact = 1; +} + +message Fact { + // Currently there are no facts. +} + +message TransformationSequence { + repeated Transformation transformation = 1; +} + +message Transformation { + oneof transformation { + // Order the transformation options by numeric id (rather than + // alphabetically). + TransformationMoveBlockDown move_block_down = 1; + TransformationSplitBlock split_block = 2; + TransformationAddConstantBoolean add_constant_boolean = 3; + TransformationAddConstantScalar add_constant_scalar = 4; + TransformationAddTypeBoolean add_type_boolean = 5; + TransformationAddTypeFloat add_type_float = 6; + TransformationAddTypeInt add_type_int = 7; + TransformationAddDeadBreak add_dead_break = 8; + TransformationReplaceBooleanConstantWithConstantBinary replace_boolean_constant_with_constant_binary = 9; + // Add additional option using the next available number. + } +} + +// Keep transformation message types in alphabetical order: + +message TransformationAddConstantBoolean { + + // Supports adding the constants true and false to a module, which may be + // necessary in order to enable other transformations if they are not present. + + uint32 fresh_id = 1; + bool is_true = 2; + +} + +message TransformationAddConstantScalar { + + // Adds a constant of the given scalar type + + // Id for the constant + uint32 fresh_id = 1; + + // Id for the scalar type of the constant + uint32 type_id = 2; + + // Value of the constant + repeated uint32 word = 3; + +} + +message TransformationAddDeadBreak { + + // A transformation that turns a basic block that unconditionally branches to + // its successor into a block that potentially breaks out of a structured + // control flow construct, but in such a manner that the break cannot actually + // be taken. + + // The block to break from + uint32 from_block = 1; + + // The merge block to break to + uint32 to_block = 2; + + // Determines whether the break condition is true or false + bool break_condition_value = 3; + + // A sequence of ids suitable for extending OpPhi instructions as a result of + // the new break edge + repeated uint32 phi_id = 4; + +} + +message TransformationAddTypeBoolean { + + // Adds OpTypeBool to the module + + // Id to be used for the type + uint32 fresh_id = 1; + +} + +message TransformationAddTypeFloat { + + // Adds OpTypeFloat to the module with the given width + + // Id to be used for the type + uint32 fresh_id = 1; + + // Floating-point width + uint32 width = 2; + +} + +message TransformationAddTypeInt { + + // Adds OpTypeInt to the module with the given width and signedness + + // Id to be used for the type + uint32 fresh_id = 1; + + // Integer width + uint32 width = 2; + + // True if and only if this is a signed type + bool is_signed = 3; + +} + +message TransformationMoveBlockDown { + + // A transformation that moves a basic block to be one position lower in + // program order. + + // The id of the block to move down. + uint32 block_id = 1; + +} + +message TransformationReplaceBooleanConstantWithConstantBinary { + // A transformation to capture replacing a use of a boolean constant with + // binary operation on two constant values + + // A descriptor for the boolean constant id we would like to replace + IdUseDescriptor id_use_descriptor = 1; + + // Id for the constant to be used on the LHS of the comparision + uint32 lhs_id = 2; + + // Id for the constant to be used on the RHS of the comparision + uint32 rhs_id = 3; + + // Opcode for binary operator + uint32 opcode = 4; + + // Id that will store the result of the binary operation instruction + uint32 fresh_id_for_binary_operation = 5; + +} + +message TransformationSplitBlock { + + // A transformation that splits a basic block into two basic blocks. + + // The result id of an instruction. + uint32 result_id = 1; + + // An offset, such that the block containing |result_id_| should be split + // right before the instruction |offset_| instructions after |result_id_|. + uint32 offset = 2; + + // 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 + // application, we require the id to be given upfront in order to facilitate + // reducing fuzzed shaders by removing transformations. The reason is that + // future transformations may refer to the fresh id introduced by this + // 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; + +} diff --git a/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.cpp b/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.cpp new file mode 100644 index 000000000..9643264a2 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.cpp @@ -0,0 +1,47 @@ +// 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/pseudo_random_generator.h" + +#include + +namespace spvtools { +namespace fuzz { + +PseudoRandomGenerator::PseudoRandomGenerator(uint32_t seed) : mt_(seed) {} + +PseudoRandomGenerator::~PseudoRandomGenerator() = default; + +uint32_t PseudoRandomGenerator::RandomUint32(uint32_t bound) { + assert(bound > 0 && "Bound must be positive"); + return static_cast( + std::uniform_int_distribution<>(0, bound - 1)(mt_)); +} + +bool PseudoRandomGenerator::RandomBool() { + return static_cast(std::uniform_int_distribution<>(0, 1)(mt_)); +} + +uint32_t PseudoRandomGenerator::RandomPercentage() { + // We use 101 because we want a result in the closed interval [0, 100], and + // RandomUint32 is not inclusive of its bound. + return RandomUint32(101); +} + +double PseudoRandomGenerator::RandomDouble() { + return std::uniform_real_distribution(0.0, 1.0)(mt_); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.h b/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.h new file mode 100644 index 000000000..d2f529205 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.h @@ -0,0 +1,47 @@ +// 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_PSEUDO_RANDOM_GENERATOR_H_ +#define SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ + +#include + +#include "source/fuzz/random_generator.h" + +namespace spvtools { +namespace fuzz { + +// Generates random data from a pseudo-random number generator. +class PseudoRandomGenerator : public RandomGenerator { + public: + explicit PseudoRandomGenerator(uint32_t seed); + + ~PseudoRandomGenerator() override; + + uint32_t RandomUint32(uint32_t bound) override; + + uint32_t RandomPercentage() override; + + bool RandomBool() override; + + double RandomDouble() override; + + private: + std::mt19937 mt_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ diff --git a/3rdparty/spirv-tools/tools/comp/markv_model_factory.h b/3rdparty/spirv-tools/source/fuzz/random_generator.cpp similarity index 57% rename from 3rdparty/spirv-tools/tools/comp/markv_model_factory.h rename to 3rdparty/spirv-tools/source/fuzz/random_generator.cpp index c13898b98..9ec4845df 100644 --- a/3rdparty/spirv-tools/tools/comp/markv_model_factory.h +++ b/3rdparty/spirv-tools/source/fuzz/random_generator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Google Inc. +// 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. @@ -12,26 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef TOOLS_COMP_MARKV_MODEL_FACTORY_H_ -#define TOOLS_COMP_MARKV_MODEL_FACTORY_H_ - -#include - -#include "source/comp/markv_model.h" +#include "source/fuzz/random_generator.h" namespace spvtools { -namespace comp { +namespace fuzz { -enum MarkvModelType { - kMarkvModelUnknown = 0, - kMarkvModelShaderLite, - kMarkvModelShaderMid, - kMarkvModelShaderMax, -}; +RandomGenerator::RandomGenerator() = default; -std::unique_ptr CreateMarkvModel(MarkvModelType type); +RandomGenerator::~RandomGenerator() = default; -} // namespace comp +} // namespace fuzz } // namespace spvtools - -#endif // TOOLS_COMP_MARKV_MODEL_FACTORY_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/random_generator.h b/3rdparty/spirv-tools/source/fuzz/random_generator.h new file mode 100644 index 000000000..9c467983d --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/random_generator.h @@ -0,0 +1,45 @@ +// 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_RANDOM_GENERATOR_H_ +#define SOURCE_FUZZ_RANDOM_GENERATOR_H_ + +#include + +namespace spvtools { +namespace fuzz { + +class RandomGenerator { + public: + RandomGenerator(); + + virtual ~RandomGenerator(); + + // Returns a value in the half-open interval [0, bound). + virtual uint32_t RandomUint32(uint32_t bound) = 0; + + // Returns a value in the closed interval [0, 100]. + virtual uint32_t RandomPercentage() = 0; + + // Returns a boolean. + virtual bool RandomBool() = 0; + + // Returns a double in the closed interval [0, 1] + virtual double RandomDouble() = 0; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_RANDOM_GENERATOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp new file mode 100644 index 000000000..f5488e6dd --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.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_add_constant_boolean.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/opt/types.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::IRContext; + +bool IsApplicable(const protobufs::TransformationAddConstantBoolean& message, + IRContext* context, const FactManager& /*unused*/) { + opt::analysis::Bool bool_type; + if (!context->get_type_mgr()->GetId(&bool_type)) { + // No OpTypeBool is present. + return false; + } + return fuzzerutil::IsFreshId(context, message.fresh_id()); +} + +void Apply(const protobufs::TransformationAddConstantBoolean& message, + IRContext* context, FactManager* /*unused*/) { + opt::analysis::Bool bool_type; + // Add the boolean constant to the module, ensuring the module's id bound is + // high enough. + fuzzerutil::UpdateModuleIdBound(context, message.fresh_id()); + context->module()->AddGlobalValue( + message.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse, + message.fresh_id(), context->get_type_mgr()->GetId(&bool_type)); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +protobufs::TransformationAddConstantBoolean +MakeTransformationAddConstantBoolean(uint32_t fresh_id, bool is_true) { + protobufs::TransformationAddConstantBoolean result; + result.set_fresh_id(fresh_id); + result.set_is_true(is_true); + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h new file mode 100644 index 000000000..f336de142 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h @@ -0,0 +1,44 @@ +// 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_BOOLEAN_CONSTANT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |fresh_id| must not be used by the module. +// - The module must already contain OpTypeBool. +bool IsApplicable(const protobufs::TransformationAddConstantBoolean& message, + opt::IRContext* context, const FactManager& fact_manager); + +// - Adds OpConstantTrue (OpConstantFalse) to the module with id |fresh_id| +// if |is_true| holds (does not hold). +void Apply(const protobufs::TransformationAddConstantBoolean& message, + opt::IRContext* context, FactManager* fact_manager); + +// Helper factory to create a transformation message. +protobufs::TransformationAddConstantBoolean +MakeTransformationAddConstantBoolean(uint32_t fresh_id, bool is_true); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp new file mode 100644 index 000000000..1f0ef723d --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp @@ -0,0 +1,83 @@ +// 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_constant_scalar.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::IRContext; + +bool IsApplicable(const protobufs::TransformationAddConstantScalar& message, + IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) { + // The id needs to be fresh. + if (!fuzzerutil::IsFreshId(context, message.fresh_id())) { + return false; + } + // The type id for the scalar must exist and be a type. + auto type = context->get_type_mgr()->GetType(message.type_id()); + if (!type) { + return false; + } + uint32_t width; + if (type->AsFloat()) { + width = type->AsFloat()->width(); + } else if (type->AsInteger()) { + width = type->AsInteger()->width(); + } else { + return false; + } + // The number of words is the integer floor of the width. + auto words = (width + 32 - 1) / 32; + + // The number of words provided by the transformation needs to match the + // width of the type. + return static_cast(message.word().size()) == words; +} + +void Apply(const protobufs::TransformationAddConstantScalar& message, + IRContext* context, spvtools::fuzz::FactManager* /*unused*/) { + opt::Instruction::OperandList operand_list; + for (auto word : message.word()) { + operand_list.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {word}}); + } + context->module()->AddGlobalValue( + MakeUnique(context, SpvOpConstant, message.type_id(), + message.fresh_id(), operand_list)); + + fuzzerutil::UpdateModuleIdBound(context, message.fresh_id()); + + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +protobufs::TransformationAddConstantScalar MakeTransformationAddConstantScalar( + uint32_t fresh_id, uint32_t type_id, std::vector words) { + protobufs::TransformationAddConstantScalar result; + result.set_fresh_id(fresh_id); + result.set_type_id(type_id); + for (auto word : words) { + result.add_word(word); + } + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h new file mode 100644 index 000000000..0279feb79 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h @@ -0,0 +1,46 @@ +// 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_CONSTANT_SCALAR_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |message.fresh_id| must not be used by the module +// - |message.type_id| must be the id of a floating-point or integer type +// - The size of |message.word| must be compatible with the width of this type +bool IsApplicable(const protobufs::TransformationAddConstantScalar& message, + opt::IRContext* context, const FactManager& fact_manager); + +// Adds a new OpConstant instruction with the given type and words. +void Apply(const protobufs::TransformationAddConstantScalar& message, + opt::IRContext* context, FactManager* fact_manager); + +// Helper factory to create a transformation message. +protobufs::TransformationAddConstantScalar MakeTransformationAddConstantScalar( + uint32_t fresh_id, uint32_t type_id, std::vector words); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp new file mode 100644 index 000000000..e5da8c9b6 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp @@ -0,0 +1,316 @@ +// 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_dead_break.h" + +#include "source/fuzz/fact_manager.h" +#include "source/opt/basic_block.h" +#include "source/opt/ir_context.h" +#include "source/opt/struct_cfg_analysis.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::BasicBlock; +using opt::IRContext; +using opt::Instruction; + +namespace { + +BasicBlock* MaybeFindBlock(IRContext* context, uint32_t maybe_block_id) { + auto inst = context->get_def_use_mgr()->GetDef(maybe_block_id); + if (inst == nullptr) { + // No instruction defining this id was found. + return nullptr; + } + if (inst->opcode() != SpvOpLabel) { + // The instruction defining the id is not a label, so it cannot be a block + // id. + return nullptr; + } + return context->cfg()->block(maybe_block_id); +} + +bool PhiIdsOk(const protobufs::TransformationAddDeadBreak& message, + IRContext* context, BasicBlock* bb_from, BasicBlock* bb_to) { + if (bb_from->IsSuccessor(bb_to)) { + // There is already an edge from |from_block| to |to_block|, so there is + // no need to extend OpPhi instructions. Do not allow phi ids to be + // present. This might turn out to be too strict; perhaps it would be OK + // just to ignore the ids in this case. + return message.phi_id().empty(); + } + // The break would add a previously non-existent edge from |from_block| to + // |to_block|, so we go through the given phi ids and check that they exactly + // match the OpPhi instructions in |to_block|. + uint32_t phi_index = 0; + // An explicit loop, rather than applying a lambda to each OpPhi in |bb_to|, + // makes sense here because we need to increment |phi_index| for each OpPhi + // instruction. + for (auto& inst : *bb_to) { + if (inst.opcode() != SpvOpPhi) { + // The OpPhi instructions all occur at the start of the block; if we find + // a non-OpPhi then we have seen them all. + break; + } + if (phi_index == static_cast(message.phi_id().size())) { + // Not enough phi ids have been provided to account for the OpPhi + // instructions. + return false; + } + // Look for an instruction defining the next phi id. + Instruction* phi_extension = + context->get_def_use_mgr()->GetDef(message.phi_id()[phi_index]); + if (!phi_extension) { + // The id given to extend this OpPhi does not exist. + return false; + } + if (phi_extension->type_id() != inst.type_id()) { + // The instruction given to extend this OpPhi either does not have a type + // or its type does not match that of the OpPhi. + return false; + } + + if (context->get_instr_block(phi_extension)) { + // The instruction defining the phi id has an associated block (i.e., it + // is not a global value). Check whether its definition dominates the + // exit of |from_block|. + auto dominator_analysis = + context->GetDominatorAnalysis(bb_from->GetParent()); + if (!dominator_analysis->Dominates(phi_extension, + bb_from->terminator())) { + // The given id is no good as its definition does not dominate the exit + // of |from_block| + return false; + } + } + phi_index++; + } + // Reject the transformation if not all of the ids for extending OpPhi + // instructions are needed. This might turn out to be stricter than necessary; + // perhaps it would be OK just to not use the ids in this case. + return phi_index == static_cast(message.phi_id().size()); +} + +bool FromBlockIsInLoopContinueConstruct( + const protobufs::TransformationAddDeadBreak& message, IRContext* context, + uint32_t maybe_loop_header) { + // We deem a block to be part of a loop's continue construct if the loop's + // continue target dominates the block. + auto containing_construct_block = context->cfg()->block(maybe_loop_header); + if (containing_construct_block->IsLoopHeader()) { + auto continue_target = containing_construct_block->ContinueBlockId(); + if (context->GetDominatorAnalysis(containing_construct_block->GetParent()) + ->Dominates(continue_target, message.from_block())) { + return true; + } + } + return false; +} + +bool AddingBreakRespectsStructuredControlFlow( + const protobufs::TransformationAddDeadBreak& message, IRContext* context, + BasicBlock* bb_from) { + // Look at the structured control flow associated with |from_block| and + // check whether it is contained in an appropriate construct with merge id + // |to_block| such that a break from |from_block| to |to_block| is legal. + + // There are three legal cases to consider: + // (1) |from_block| is a loop header and |to_block| is its merge + // (2) |from_block| is a non-header node of a construct, and |to_block| + // is the merge for that construct + // (3) |from_block| is a non-header node of a selection construct, and + // |to_block| is the merge for the innermost loop containing + // |from_block| + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2653) It may be + // possible to be more aggressive in breaking from switch constructs. + // + // The reason we need to distinguish between cases (1) and (2) is that the + // structured CFG analysis does not deem a header to be part of the construct + // that it heads. + + // Consider case (1) + if (bb_from->IsLoopHeader()) { + // Case (1) holds if |to_block| is the merge block for the loop; + // otherwise no case holds + return bb_from->MergeBlockId() == message.to_block(); + } + + // Both cases (2) and (3) require that |from_block| is inside some + // structured control flow construct. + + auto containing_construct = + context->GetStructuredCFGAnalysis()->ContainingConstruct( + message.from_block()); + if (!containing_construct) { + // |from_block| is not in a construct from which we can break. + return false; + } + + // Consider case (2) + if (message.to_block() == + context->cfg()->block(containing_construct)->MergeBlockId()) { + // This looks like an instance of case (2). + // However, the structured CFG analysis regards the continue construct of a + // loop as part of the loop, but it is not legal to jump from a loop's + // continue construct to the loop's merge (except from the back-edge block), + // so we need to check for this case. + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2577): We do not + // currently allow a dead break from a back edge block, but we could and + // ultimately should. + return !FromBlockIsInLoopContinueConstruct(message, context, + containing_construct); + } + + // Case (3) holds if and only if |to_block| is the merge block for this + // innermost loop that contains |from_block| + auto containing_loop_header = + context->GetStructuredCFGAnalysis()->ContainingLoop(message.from_block()); + if (containing_loop_header && + message.to_block() == + context->cfg()->block(containing_loop_header)->MergeBlockId()) { + return !FromBlockIsInLoopContinueConstruct(message, context, + containing_loop_header); + } + return false; +} + +} // namespace + +bool IsApplicable(const protobufs::TransformationAddDeadBreak& message, + IRContext* context, const FactManager& /*unused*/) { + // First, we check that a constant with the same value as + // |break_condition_value| is present. + opt::analysis::Bool bool_type; + auto registered_bool_type = + context->get_type_mgr()->GetRegisteredType(&bool_type); + if (!registered_bool_type) { + return false; + } + opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(), + message.break_condition_value()); + if (!context->get_constant_mgr()->FindConstant(&bool_constant)) { + // The required constant is not present, so the transformation cannot be + // applied. + return false; + } + + // Check that |from_block| and |to_block| really are block ids + BasicBlock* bb_from = MaybeFindBlock(context, message.from_block()); + if (bb_from == nullptr) { + return false; + } + BasicBlock* bb_to = MaybeFindBlock(context, message.to_block()); + if (bb_to == nullptr) { + return false; + } + + // Check that |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 + // branch. + return false; + } + + assert(bb_from != nullptr && + "We should have found a block if this line of code is reached."); + assert( + bb_from->id() == message.from_block() && + "The id of the block we found should match the source id for the break."); + assert(bb_to != nullptr && + "We should have found a block if this line of code is reached."); + assert( + bb_to->id() == message.to_block() && + "The id of the block we found should match the target id for the break."); + + // Check whether the data passed to extend OpPhi instructions is appropriate. + if (!PhiIdsOk(message, context, bb_from, bb_to)) { + return false; + } + + // Finally, check that adding the break would respect the rules of structured + // control flow. + return AddingBreakRespectsStructuredControlFlow(message, context, bb_from); +} + +void Apply(const protobufs::TransformationAddDeadBreak& message, + IRContext* context, FactManager* /*unused*/) { + // Get the id of the boolean constant to be used as the break condition. + opt::analysis::Bool bool_type; + opt::analysis::BoolConstant bool_constant( + context->get_type_mgr()->GetRegisteredType(&bool_type)->AsBool(), + message.break_condition_value()); + uint32_t bool_id = context->get_constant_mgr()->FindDeclaredConstant( + &bool_constant, context->get_type_mgr()->GetId(&bool_type)); + + auto bb_from = context->cfg()->block(message.from_block()); + auto bb_to = context->cfg()->block(message.to_block()); + const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to); + auto successor = bb_from->terminator()->GetSingleWordInOperand(0); + assert(bb_from->terminator()->opcode() == SpvOpBranch && + "Precondition for the transformation requires that the source block " + "ends with OpBranch"); + + // Add the dead break, by turning OpBranch into OpBranchConditional, and + // ordering the targets depending on whether the given boolean corresponds to + // true or false. + bb_from->terminator()->SetOpcode(SpvOpBranchConditional); + bb_from->terminator()->SetInOperands( + {{SPV_OPERAND_TYPE_ID, {bool_id}}, + {SPV_OPERAND_TYPE_ID, + {message.break_condition_value() ? successor : message.to_block()}}, + {SPV_OPERAND_TYPE_ID, + {message.break_condition_value() ? message.to_block() : successor}}}); + + // Update OpPhi instructions in the target block if this break adds a + // previously non-existent edge from source to target. + if (!from_to_edge_already_exists) { + uint32_t phi_index = 0; + for (auto& inst : *bb_to) { + if (inst.opcode() != SpvOpPhi) { + break; + } + assert(phi_index < static_cast(message.phi_id().size()) && + "There should be exactly one phi id per OpPhi instruction."); + inst.AddOperand({SPV_OPERAND_TYPE_ID, {message.phi_id()[phi_index]}}); + inst.AddOperand({SPV_OPERAND_TYPE_ID, {message.from_block()}}); + phi_index++; + } + assert(phi_index == static_cast(message.phi_id().size()) && + "There should be exactly one phi id per OpPhi instruction."); + } + + // Invalidate all analyses + context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +protobufs::TransformationAddDeadBreak MakeTransformationAddDeadBreak( + uint32_t from_block, uint32_t to_block, bool break_condition_value, + std::vector phi_id) { + protobufs::TransformationAddDeadBreak result; + result.set_from_block(from_block); + result.set_to_block(to_block); + result.set_break_condition_value(break_condition_value); + for (auto id : phi_id) { + result.add_phi_id(id); + } + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h new file mode 100644 index 000000000..c99e3ff23 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h @@ -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. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |message.from_block| must be the id of a block a in the given module. +// - |message.to_block| must be the id of a block b in the given module. +// - if |message.break_condition_value| holds (does not hold) then +// OpConstantTrue (OpConstantFalse) must be present in the module +// - |message.phi_ids| must be a list of ids that are all available at +// |message.from_block| +// - a and b must be in the same function. +// - b must be a merge block. +// - a must end with an unconditional branch to some block c. +// - replacing this branch with a conditional branch to b or c, with +// the boolean constant associated with |message.break_condition_value| 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. +bool IsApplicable(const protobufs::TransformationAddDeadBreak& message, + opt::IRContext* context, const FactManager& fact_manager); + +// Replaces the terminator of a with a conditional branch to b or c. +// The boolean constant associated with |message.break_condition_value| is used +// as the condition, and the order of b and c is arranged such that control is +// guaranteed to jump to c. +void Apply(const protobufs::TransformationAddDeadBreak& message, + opt::IRContext* context, FactManager* fact_manager); + +// Helper factory to create a transformation message. +protobufs::TransformationAddDeadBreak MakeTransformationAddDeadBreak( + uint32_t from_block, uint32_t to_block, bool break_condition_value, + std::vector phi_ids); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp new file mode 100644 index 000000000..0a26b9651 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp @@ -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. + +#include "source/fuzz/transformation_add_type_boolean.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::IRContext; + +bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message, + IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) { + // The id must be fresh. + if (!fuzzerutil::IsFreshId(context, message.fresh_id())) { + return false; + } + + // Applicable if there is no bool type already declared in the module. + opt::analysis::Bool bool_type; + return context->get_type_mgr()->GetId(&bool_type) == 0; +} + +void Apply(const protobufs::TransformationAddTypeBoolean& message, + IRContext* context, spvtools::fuzz::FactManager* /*unused*/) { + opt::Instruction::OperandList empty_operands; + context->module()->AddType(MakeUnique( + context, SpvOpTypeBool, 0, message.fresh_id(), empty_operands)); + fuzzerutil::UpdateModuleIdBound(context, message.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +protobufs::TransformationAddTypeBoolean MakeTransformationAddTypeBoolean( + uint32_t fresh_id) { + protobufs::TransformationAddTypeBoolean result; + result.set_fresh_id(fresh_id); + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h new file mode 100644 index 000000000..4361acfa4 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h @@ -0,0 +1,43 @@ +// 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_TYPE_BOOLEAN_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |message.fresh_id| must not be used by the module. +// - The module must not yet declare OpTypeBoolean +bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message, + opt::IRContext* context, const FactManager& fact_manager); + +// Adds OpTypeBoolean with |message.fresh_id| as result id. +void Apply(const protobufs::TransformationAddTypeBoolean& message, + opt::IRContext* context, FactManager* fact_manager); + +// Helper factory to create a transformation message. +protobufs::TransformationAddTypeBoolean MakeTransformationAddTypeBoolean( + uint32_t fresh_id); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp new file mode 100644 index 000000000..1a5ce4662 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.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/transformation_add_type_float.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::IRContext; + +bool IsApplicable(const protobufs::TransformationAddTypeFloat& message, + IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) { + // The id must be fresh. + if (!fuzzerutil::IsFreshId(context, message.fresh_id())) { + return false; + } + + // Applicable if there is no float type with this width already declared in + // the module. + opt::analysis::Float float_type(message.width()); + return context->get_type_mgr()->GetId(&float_type) == 0; +} + +void Apply(const protobufs::TransformationAddTypeFloat& message, + IRContext* context, spvtools::fuzz::FactManager* /*unused*/) { + opt::Instruction::OperandList width = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.width()}}}; + context->module()->AddType(MakeUnique( + context, SpvOpTypeFloat, 0, message.fresh_id(), width)); + fuzzerutil::UpdateModuleIdBound(context, message.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +protobufs::TransformationAddTypeFloat MakeTransformationAddTypeFloat( + uint32_t fresh_id, uint32_t width) { + protobufs::TransformationAddTypeFloat result; + result.set_fresh_id(fresh_id); + result.set_width(width); + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h new file mode 100644 index 000000000..ac54193a5 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h @@ -0,0 +1,44 @@ +// 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_TYPE_FLOAT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |message.fresh_id| must not be used by the module +// - The module must not contain an OpTypeFloat instruction with width +// |message.width| +bool IsApplicable(const protobufs::TransformationAddTypeFloat& message, + opt::IRContext* context, const FactManager& fact_manager); + +// Adds an OpTypeFloat instruction to the module with the given width +void Apply(const protobufs::TransformationAddTypeFloat& message, + opt::IRContext* context, FactManager* fact_manager); + +// Helper factory to create a transformation message. +protobufs::TransformationAddTypeFloat MakeTransformationAddTypeFloat( + uint32_t fresh_id, uint32_t width); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp new file mode 100644 index 000000000..749294a98 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp @@ -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. + +#include "source/fuzz/transformation_add_type_int.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::IRContext; + +bool IsApplicable(const protobufs::TransformationAddTypeInt& message, + IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) { + // The id must be fresh. + if (!fuzzerutil::IsFreshId(context, message.fresh_id())) { + return false; + } + + // Applicable if there is no int type with this width and signedness already + // declared in the module. + opt::analysis::Integer int_type(message.width(), message.is_signed()); + return context->get_type_mgr()->GetId(&int_type) == 0; +} + +void Apply(const protobufs::TransformationAddTypeInt& message, + IRContext* context, spvtools::fuzz::FactManager* /*unused*/) { + opt::Instruction::OperandList in_operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.width()}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.is_signed() ? 1u : 0u}}}; + context->module()->AddType(MakeUnique( + context, SpvOpTypeInt, 0, message.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +protobufs::TransformationAddTypeInt MakeTransformationAddTypeInt( + uint32_t fresh_id, uint32_t width, bool is_signed) { + protobufs::TransformationAddTypeInt result; + result.set_fresh_id(fresh_id); + result.set_width(width); + result.set_is_signed(is_signed); + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h new file mode 100644 index 000000000..9e0264b5a --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h @@ -0,0 +1,45 @@ +// 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_TYPE_INT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |message.fresh_id| must not be used by the module +// - The module must not contain an OpTypeInt instruction with width +// |message.width| and signedness |message.is_signed| +bool IsApplicable(const protobufs::TransformationAddTypeInt& message, + opt::IRContext* context, const FactManager& fact_manager); + +// Adds an OpTypeInt instruction to the module with the given width and +// signedness. +void Apply(const protobufs::TransformationAddTypeInt& message, + opt::IRContext* context, FactManager* fact_manager); + +// Helper factory to create a transformation message. +protobufs::TransformationAddTypeInt MakeTransformationAddTypeInt( + uint32_t fresh_id, uint32_t width, bool is_signed); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp new file mode 100644 index 000000000..858af741a --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp @@ -0,0 +1,102 @@ +// 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_move_block_down.h" + +#include "source/opt/basic_block.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::BasicBlock; +using opt::IRContext; + +bool IsApplicable(const protobufs::TransformationMoveBlockDown& message, + IRContext* context, const FactManager& /*unused*/) { + // Go through every block in every function, looking for a block whose id + // matches that of the block we want to consider moving down. + for (auto& function : *context->module()) { + for (auto block_it = function.begin(); block_it != function.end(); + ++block_it) { + if (block_it->id() == message.block_id()) { + // We have found a match. + if (block_it == function.begin()) { + // The block is the first one appearing in the function. We are not + // allowed to move this block down. + return false; + } + // Record the block we would like to consider moving down. + BasicBlock* block_matching_id = &*block_it; + // Now see whether there is some block following that block in program + // order. + ++block_it; + if (block_it == function.end()) { + // There is no such block; i.e., the block we are considering moving + // is the last one in the function. The transformation thus does not + // apply. + return false; + } + BasicBlock* next_block_in_program_order = &*block_it; + // We can move the block of interest down if and only if it does not + // dominate the block that comes next. + return !context->GetDominatorAnalysis(&function)->Dominates( + block_matching_id, next_block_in_program_order); + } + } + } + + // We did not find a matching block, so the transformation is not applicable: + // there is no relevant block to move. + return false; +} + +void Apply(const protobufs::TransformationMoveBlockDown& message, + IRContext* context, FactManager* /*unused*/) { + // Go through every block in every function, looking for a block whose id + // matches that of the block we want to move down. + for (auto& function : *context->module()) { + for (auto block_it = function.begin(); block_it != function.end(); + ++block_it) { + if (block_it->id() == message.block_id()) { + ++block_it; + assert(block_it != function.end() && + "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. + context->InvalidateAnalysesExceptFor( + IRContext::Analysis::kAnalysisDefUse | + IRContext::Analysis::kAnalysisDominatorAnalysis); + + return; + } + } + } + assert(false && "No block was found to move down."); +} + +protobufs::TransformationMoveBlockDown MakeTransformationMoveBlockDown( + uint32_t id) { + protobufs::TransformationMoveBlockDown result; + result.set_block_id(id); + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h b/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h new file mode 100644 index 000000000..072ad5392 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h @@ -0,0 +1,46 @@ +// 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_MOVE_BLOCK_DOWN_H_ +#define SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |block_id| must be the id of a block b in the given module. +// - b must not be the first nor last block appearing, in program order, +// in a function. +// - b must not dominate the block that follows it in program order. +bool IsApplicable(const protobufs::TransformationMoveBlockDown& message, + opt::IRContext* context, const FactManager& fact_manager); + +// The block with id |block_id| is moved down; i.e. the program order +// between it and the block that follows it is swapped. +void Apply(const protobufs::TransformationMoveBlockDown& message, + opt::IRContext* context, FactManager* fact_manager); + +// Creates a protobuf message to move down the block with id |id|. +protobufs::TransformationMoveBlockDown MakeTransformationMoveBlockDown( + uint32_t id); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp new file mode 100644 index 000000000..85844c544 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp @@ -0,0 +1,282 @@ +// 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_boolean_constant_with_constant_binary.h" + +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/id_use_descriptor.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +namespace { + +// Given floating-point values |lhs| and |rhs|, and a floating-point binary +// operator |binop|, returns true if it is certain that 'lhs binop rhs' +// evaluates to |required_value|. +template +bool float_binop_evaluates_to(T lhs, T rhs, SpvOp binop, bool required_value) { + // Infinity and NaN values are conservatively treated as out of scope. + if (!std::isfinite(lhs) || !std::isfinite(rhs)) { + return false; + } + bool binop_result; + // The following captures the binary operators that spirv-fuzz can actually + // generate when turning a boolean constant into a binary expression. + switch (binop) { + case SpvOpFOrdGreaterThanEqual: + case SpvOpFUnordGreaterThanEqual: + binop_result = (lhs >= rhs); + break; + case SpvOpFOrdGreaterThan: + case SpvOpFUnordGreaterThan: + binop_result = (lhs > rhs); + break; + case SpvOpFOrdLessThanEqual: + case SpvOpFUnordLessThanEqual: + binop_result = (lhs <= rhs); + break; + case SpvOpFOrdLessThan: + case SpvOpFUnordLessThan: + binop_result = (lhs < rhs); + break; + default: + return false; + } + return binop_result == required_value; +} + +// Analogous to 'float_binop_evaluates_to', but for signed int values. +template +bool signed_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop, + bool required_value) { + bool binop_result; + switch (binop) { + case SpvOpSGreaterThanEqual: + binop_result = (lhs >= rhs); + break; + case SpvOpSGreaterThan: + binop_result = (lhs > rhs); + break; + case SpvOpSLessThanEqual: + binop_result = (lhs <= rhs); + break; + case SpvOpSLessThan: + binop_result = (lhs < rhs); + break; + default: + return false; + } + return binop_result == required_value; +} + +// Analogous to 'float_binop_evaluates_to', but for unsigned int values. +template +bool unsigned_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop, + bool required_value) { + bool binop_result; + switch (binop) { + case SpvOpUGreaterThanEqual: + binop_result = (lhs >= rhs); + break; + case SpvOpUGreaterThan: + binop_result = (lhs > rhs); + break; + case SpvOpULessThanEqual: + binop_result = (lhs <= rhs); + break; + case SpvOpULessThan: + binop_result = (lhs < rhs); + break; + default: + return false; + } + return binop_result == required_value; +} + +} // namespace + +bool IsApplicable( + const protobufs::TransformationReplaceBooleanConstantWithConstantBinary& + message, + opt::IRContext* context, const FactManager& /*unused*/) { + // The id for the binary result must be fresh + if (!fuzzerutil::IsFreshId(context, + message.fresh_id_for_binary_operation())) { + return false; + } + + // The used id must be for a boolean constant + auto boolean_constant = context->get_def_use_mgr()->GetDef( + message.id_use_descriptor().id_of_interest()); + if (!boolean_constant) { + return false; + } + if (!(boolean_constant->opcode() == SpvOpConstantFalse || + boolean_constant->opcode() == SpvOpConstantTrue)) { + return false; + } + + // The left-hand-side id must correspond to a constant instruction. + auto lhs_constant_inst = context->get_def_use_mgr()->GetDef(message.lhs_id()); + if (!lhs_constant_inst) { + return false; + } + if (lhs_constant_inst->opcode() != SpvOpConstant) { + return false; + } + + // The right-hand-side id must correspond to a constant instruction. + auto rhs_constant_inst = context->get_def_use_mgr()->GetDef(message.rhs_id()); + if (!rhs_constant_inst) { + return false; + } + if (rhs_constant_inst->opcode() != SpvOpConstant) { + return false; + } + + // The left- and right-hand side instructions must have the same type. + if (lhs_constant_inst->type_id() != rhs_constant_inst->type_id()) { + return false; + } + + // The expression 'LHS opcode RHS' must evaluate to the boolean constant. + auto lhs_constant = + context->get_constant_mgr()->FindDeclaredConstant(message.lhs_id()); + auto rhs_constant = + context->get_constant_mgr()->FindDeclaredConstant(message.rhs_id()); + bool expected_result = (boolean_constant->opcode() == SpvOpConstantTrue); + + const SpvOp binary_opcode = static_cast(message.opcode()); + + // We consider the floating point, signed and unsigned integer cases + // separately. In each case the logic is very similar. + if (lhs_constant->AsFloatConstant()) { + assert(rhs_constant->AsFloatConstant() && + "Both constants should be of the same type."); + if (lhs_constant->type()->AsFloat()->width() == 32) { + if (!float_binop_evaluates_to(lhs_constant->GetFloat(), + rhs_constant->GetFloat(), binary_opcode, + expected_result)) { + return false; + } + } else { + assert(lhs_constant->type()->AsFloat()->width() == 64); + if (!float_binop_evaluates_to(lhs_constant->GetDouble(), + rhs_constant->GetDouble(), binary_opcode, + expected_result)) { + return false; + } + } + } else { + assert(lhs_constant->AsIntConstant() && "Constants should be in or float."); + assert(rhs_constant->AsIntConstant() && + "Both constants should be of the same type."); + if (lhs_constant->type()->AsInteger()->IsSigned()) { + if (lhs_constant->type()->AsInteger()->width() == 32) { + if (!signed_int_binop_evaluates_to(lhs_constant->GetS32(), + rhs_constant->GetS32(), + binary_opcode, expected_result)) { + return false; + } + } else { + assert(lhs_constant->type()->AsInteger()->width() == 64); + if (!signed_int_binop_evaluates_to(lhs_constant->GetS64(), + rhs_constant->GetS64(), + binary_opcode, expected_result)) { + return false; + } + } + } else { + if (lhs_constant->type()->AsInteger()->width() == 32) { + if (!unsigned_int_binop_evaluates_to(lhs_constant->GetU32(), + rhs_constant->GetU32(), + binary_opcode, expected_result)) { + return false; + } + } else { + assert(lhs_constant->type()->AsInteger()->width() == 64); + if (!unsigned_int_binop_evaluates_to(lhs_constant->GetU64(), + rhs_constant->GetU64(), + binary_opcode, expected_result)) { + return false; + } + } + } + } + + // The id use descriptor must identify some instruction + return transformation::FindInstruction(message.id_use_descriptor(), + context) != nullptr; +} + +opt::Instruction* Apply( + const protobufs::TransformationReplaceBooleanConstantWithConstantBinary& + message, + opt::IRContext* context, FactManager* /*unused*/) { + opt::analysis::Bool bool_type; + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_ID, {message.lhs_id()}}, + {SPV_OPERAND_TYPE_ID, {message.rhs_id()}}}; + auto binary_instruction = MakeUnique( + context, static_cast(message.opcode()), + context->get_type_mgr()->GetId(&bool_type), + 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); + + // 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 + // the using instruction is preceded by a merge instruction. + auto instruction_before_which_to_insert = instruction_containing_constant_use; + { + opt::Instruction* previous_node = + instruction_before_which_to_insert->PreviousNode(); + if (previous_node && (previous_node->opcode() == SpvOpLoopMerge || + previous_node->opcode() == SpvOpSelectionMerge)) { + instruction_before_which_to_insert = previous_node; + } + } + instruction_before_which_to_insert->InsertBefore( + std::move(binary_instruction)); + instruction_containing_constant_use->SetInOperand( + message.id_use_descriptor().in_operand_index(), + {message.fresh_id_for_binary_operation()}); + fuzzerutil::UpdateModuleIdBound(context, + message.fresh_id_for_binary_operation()); + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + return result; +} + +protobufs::TransformationReplaceBooleanConstantWithConstantBinary +MakeTransformationReplaceBooleanConstantWithConstantBinary( + const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id, + uint32_t rhs_id, SpvOp comparison_opcode, + uint32_t fresh_id_for_binary_operation) { + protobufs::TransformationReplaceBooleanConstantWithConstantBinary result; + *result.mutable_id_use_descriptor() = id_use_descriptor; + result.set_lhs_id(lhs_id); + result.set_rhs_id(rhs_id); + result.set_opcode(comparison_opcode); + result.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation); + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h new file mode 100644 index 000000000..a6dae2acf --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h @@ -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. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ +#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |message.fresh_id_for_binary_operation| must not already be used by the +// module. +// - |message.id_use_descriptor| must identify a use of a boolean constant c. +// - |message.lhs_id| and |message.rhs_id| must be the ids of constant +// instructions with the same type +// - |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. +bool IsApplicable( + const protobufs::TransformationReplaceBooleanConstantWithConstantBinary& + message, + opt::IRContext* context, const FactManager& fact_manager); + +// A new instruction is added before the boolean constant usage that computes +// the result of applying |message.opcode| to |message.lhs_id| and +// |message.rhs_id| is added, with result id +// |message.fresh_id_for_binary_operation|. The boolean constant usage is +// replaced with this result id. +opt::Instruction* Apply( + const protobufs::TransformationReplaceBooleanConstantWithConstantBinary& + message, + opt::IRContext* context, FactManager* fact_manager); + +// Helper factory to create a transformation message. +protobufs::TransformationReplaceBooleanConstantWithConstantBinary +MakeTransformationReplaceBooleanConstantWithConstantBinary( + const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id, + uint32_t rhs_id, SpvOp comparison_opcode, + uint32_t fresh_id_for_binary_operation); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp new file mode 100644 index 000000000..943bed07a --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp @@ -0,0 +1,183 @@ +// 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_split_block.h" + +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +using opt::BasicBlock; +using opt::IRContext; +using opt::Instruction; +using opt::Operand; + +namespace { + +// Returns: +// - (true, block->end()) if the relevant instruction is in this block +// but inapplicable +// - (true, it) if 'it' is an iterator for the relevant instruction +// - (false, _) otherwise. +std::pair FindInstToSplitBefore( + const protobufs::TransformationSplitBlock& message, BasicBlock* block) { + // There are three possibilities: + // (1) the transformation wants to split at some offset from the block's + // label. + // (2) the transformation wants to split at some offset from a + // non-label instruction inside the block. + // (3) the split associated with this transformation has nothing to do with + // this block + if (message.result_id() == block->id()) { + // Case (1). + if (message.offset() == 0) { + // The offset is not allowed to be 0: this would mean splitting before the + // block's label. + // By returning (true, block->end()), we indicate that we did find the + // instruction (so that it is not worth searching further for it), but + // that splitting will not be possible. + return {true, 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 < message.offset() && inst_it != block->end(); i++) { + ++inst_it; + } + // This is either the desired instruction, or the end of the block. + return {true, inst_it}; + } + for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) { + if (message.result_id() == inst_it->result_id()) { + // Case (2): we have found the base instruction; we now apply the offset. + for (uint32_t i = 0; i < message.offset() && inst_it != block->end(); + i++) { + ++inst_it; + } + // This is either the desired instruction, or the end of the block. + return {true, inst_it}; + } + } + // Case (3). + return {false, block->end()}; +} + +} // namespace + +bool IsApplicable(const protobufs::TransformationSplitBlock& message, + IRContext* context, const FactManager& /*unused*/) { + if (!fuzzerutil::IsFreshId(context, message.fresh_id())) { + // We require the id for the new block to be unused. + return false; + } + // Consider every block in every function. + for (auto& function : *context->module()) { + for (auto& block : function) { + auto maybe_split_before = FindInstToSplitBefore(message, &block); + if (!maybe_split_before.first) { + continue; + } + if (maybe_split_before.second == block.end()) { + // The base instruction was found, but the offset was inappropriate. + return false; + } + if (block.IsLoopHeader()) { + // We cannot split a loop header block: back-edges would become invalid. + return false; + } + auto split_before = maybe_split_before.second; + if (split_before->PreviousNode() && + split_before->PreviousNode()->opcode() == SpvOpSelectionMerge) { + // We cannot split directly after a selection merge: this would separate + // the merge from its associated branch or switch operation. + return false; + } + if (split_before->opcode() == SpvOpVariable) { + // We cannot split directly after a variable; variables in a function + // must be contiguous in the entry block. + return false; + } + if (split_before->opcode() == SpvOpPhi && + split_before->NumInOperands() != 2) { + // We cannot split before an OpPhi unless the OpPhi has exactly one + // associated incoming edge. + return false; + } + return true; + } + } + return false; +} + +void Apply(const protobufs::TransformationSplitBlock& message, + IRContext* context, FactManager* /*unused*/) { + for (auto& function : *context->module()) { + for (auto& block : function) { + auto maybe_split_before = FindInstToSplitBefore(message, &block); + if (!maybe_split_before.first) { + continue; + } + assert(maybe_split_before.second != block.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.SplitBasicBlock(context, message.fresh_id(), + maybe_split_before.second); + // The split does not automatically add a branch between the two parts of + // the original block, so we add one. + block.AddInstruction(MakeUnique( + context, SpvOpBranch, 0, 0, + std::initializer_list{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](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.id()}); + }); + // Invalidate all analyses + context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); + return; + } + } + assert(0 && + "Should be unreachable: it should have been possible to apply this " + "transformation."); +} + +protobufs::TransformationSplitBlock MakeTransformationSplitBlock( + uint32_t result_id, uint32_t offset, uint32_t fresh_id) { + protobufs::TransformationSplitBlock result; + result.set_result_id(result_id); + result.set_offset(offset); + result.set_fresh_id(fresh_id); + return result; +} + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h new file mode 100644 index 000000000..9ae419bc3 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h @@ -0,0 +1,52 @@ +// 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_SPLIT_BLOCK_H_ +#define SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { +namespace transformation { + +// - |result_id| must be the result id of an instruction 'base' in some +// block 'blk'. +// - 'blk' must contain an instruction 'inst' located |offset| instructions +// after 'inst' (if |offset| = 0 then 'inst' = 'base'). +// - Splitting 'blk' at 'inst', so that all instructions from 'inst' onwards +// appear in a new block that 'blk' directly jumps to must be valid. +// - |fresh_id| must not be used by the module. +bool IsApplicable(const protobufs::TransformationSplitBlock& message, + opt::IRContext* context, const FactManager& fact_manager); + +// - A new block with label |fresh_id| is inserted right after 'blk' in +// program order. +// - All instructions of 'blk' from 'inst' onwards are moved into the new +// block. +// - 'blk' is made to jump unconditionally to the new block. +void Apply(const protobufs::TransformationSplitBlock& message, + opt::IRContext* context, FactManager* fact_manager); + +// Creates a protobuf message representing a block-splitting transformation. +protobufs::TransformationSplitBlock MakeTransformationSplitBlock( + uint32_t result_id, uint32_t offset, uint32_t fresh_id); + +} // namespace transformation +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_H_ diff --git a/3rdparty/spirv-tools/source/id_descriptor.cpp b/3rdparty/spirv-tools/source/id_descriptor.cpp deleted file mode 100644 index d44ed672c..000000000 --- a/3rdparty/spirv-tools/source/id_descriptor.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2017 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/id_descriptor.h" - -#include -#include - -#include "source/opcode.h" -#include "source/operand.h" - -namespace spvtools { -namespace { - -// Hashes an array of words. Order of words is important. -uint32_t HashU32Array(const std::vector& words) { - // The hash function is a sum of hashes of each word seeded by word index. - // Knuth's multiplicative hash is used to hash the words. - const uint32_t kKnuthMulHash = 2654435761; - uint32_t val = 0; - for (uint32_t i = 0; i < words.size(); ++i) { - val += (words[i] + i + 123) * kKnuthMulHash; - } - return val; -} - -} // namespace - -uint32_t IdDescriptorCollection::ProcessInstruction( - const spv_parsed_instruction_t& inst) { - if (!inst.result_id) return 0; - - assert(words_.empty()); - words_.push_back(inst.words[0]); - - for (size_t operand_index = 0; operand_index < inst.num_operands; - ++operand_index) { - const auto& operand = inst.operands[operand_index]; - if (spvIsIdType(operand.type)) { - const uint32_t id = inst.words[operand.offset]; - const auto it = id_to_descriptor_.find(id); - // Forward declared ids are not hashed. - if (it != id_to_descriptor_.end()) { - words_.push_back(it->second); - } - } else { - for (size_t operand_word_index = 0; - operand_word_index < operand.num_words; ++operand_word_index) { - words_.push_back(inst.words[operand.offset + operand_word_index]); - } - } - } - - uint32_t descriptor = - custom_hash_func_ ? custom_hash_func_(words_) : HashU32Array(words_); - if (descriptor == 0) descriptor = 1; - assert(descriptor); - - words_.clear(); - - const auto result = id_to_descriptor_.emplace(inst.result_id, descriptor); - assert(result.second); - (void)result; - return descriptor; -} - -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/id_descriptor.h b/3rdparty/spirv-tools/source/id_descriptor.h deleted file mode 100644 index add23343a..000000000 --- a/3rdparty/spirv-tools/source/id_descriptor.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_ID_DESCRIPTOR_H_ -#define SOURCE_ID_DESCRIPTOR_H_ - -#include -#include - -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { - -using CustomHashFunc = std::function&)>; - -// Computes and stores id descriptors. -// -// Descriptors are computed as hash of all words in the instruction where ids -// were substituted with previously computed descriptors. -class IdDescriptorCollection { - public: - explicit IdDescriptorCollection( - CustomHashFunc custom_hash_func = CustomHashFunc()) - : custom_hash_func_(custom_hash_func) { - words_.reserve(16); - } - - // Computes descriptor for the result id of the given instruction and - // registers it in id_to_descriptor_. Returns the computed descriptor. - // This function needs to be sequentially called for every instruction in the - // module. - uint32_t ProcessInstruction(const spv_parsed_instruction_t& inst); - - // Returns a previously computed descriptor id. - uint32_t GetDescriptor(uint32_t id) const { - const auto it = id_to_descriptor_.find(id); - if (it == id_to_descriptor_.end()) return 0; - return it->second; - } - - private: - std::unordered_map id_to_descriptor_; - - std::function&)> custom_hash_func_; - - // Scratch buffer used for hashing. Class member to optimize on allocation. - std::vector words_; -}; - -} // namespace spvtools - -#endif // SOURCE_ID_DESCRIPTOR_H_ diff --git a/3rdparty/spirv-tools/source/link/linker.cpp b/3rdparty/spirv-tools/source/link/linker.cpp index f28b7595a..d99a1e872 100644 --- a/3rdparty/spirv-tools/source/link/linker.cpp +++ b/3rdparty/spirv-tools/source/link/linker.cpp @@ -33,6 +33,7 @@ #include "source/opt/ir_loader.h" #include "source/opt/pass_manager.h" #include "source/opt/remove_duplicates_pass.h" +#include "source/opt/type_manager.h" #include "source/spirv_target_env.h" #include "source/util/make_unique.h" #include "spirv-tools/libspirv.hpp" @@ -40,14 +41,15 @@ namespace spvtools { namespace { -using opt::IRContext; using opt::Instruction; +using opt::IRContext; using opt::Module; -using opt::Operand; using opt::PassManager; using opt::RemoveDuplicatesPass; using opt::analysis::DecorationManager; using opt::analysis::DefUseManager; +using opt::analysis::Type; +using opt::analysis::TypeManager; // Stores various information about an imported or exported symbol. struct LinkageSymbolInfo { @@ -472,14 +474,15 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, opt::IRContext* context) { spv_position_t position = {}; - // Ensure th import and export types are the same. - const DefUseManager& def_use_manager = *context->get_def_use_mgr(); + // Ensure the import and export types are the same. const DecorationManager& decoration_manager = *context->get_decoration_mgr(); + const TypeManager& type_manager = *context->get_type_mgr(); for (const auto& linking_entry : linkings_to_do) { - if (!RemoveDuplicatesPass::AreTypesEqual( - *def_use_manager.GetDef(linking_entry.imported_symbol.type_id), - *def_use_manager.GetDef(linking_entry.exported_symbol.type_id), - context)) + Type* imported_symbol_type = + type_manager.GetType(linking_entry.imported_symbol.type_id); + Type* exported_symbol_type = + type_manager.GetType(linking_entry.exported_symbol.type_id); + if (!(*imported_symbol_type == *exported_symbol_type)) return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) << "Type mismatch on symbol \"" << linking_entry.imported_symbol.name diff --git a/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp b/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp index 3df5a83ec..10fcde408 100644 --- a/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp @@ -408,6 +408,28 @@ UnaryScalarFoldingRule FoldIToFOp() { }; } +// This defines a |UnaryScalarFoldingRule| that performs |OpQuantizeToF16|. +UnaryScalarFoldingRule FoldQuantizeToF16Scalar() { + return [](const analysis::Type* result_type, const analysis::Constant* a, + analysis::ConstantManager* const_mgr) -> const analysis::Constant* { + assert(result_type != nullptr && a != nullptr); + const analysis::Float* float_type = a->type()->AsFloat(); + assert(float_type != nullptr); + if (float_type->width() != 32) { + return nullptr; + } + + float fa = a->GetFloat(); + utils::HexFloat> orignal(fa); + utils::HexFloat> quantized(0); + utils::HexFloat> result(0.0f); + orignal.castTo(quantized, utils::round_direction::kToZero); + quantized.castTo(result, utils::round_direction::kToZero); + std::vector words = {result.getBits()}; + return const_mgr->GetConstant(result_type, words); + }; +} + // 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) \ @@ -438,6 +460,9 @@ UnaryScalarFoldingRule FoldIToFOp() { // Define the folding rule for conversion between floating point and integer ConstantFoldingRule FoldFToI() { return FoldFPUnaryOp(FoldFToIOp()); } ConstantFoldingRule FoldIToF() { return FoldFPUnaryOp(FoldIToFOp()); } +ConstantFoldingRule FoldQuantizeToF16() { + return FoldFPUnaryOp(FoldQuantizeToF16Scalar()); +} // Define the folding rules for subtraction, addition, multiplication, and // division for floating point values. @@ -848,6 +873,7 @@ ConstantFoldingRules::ConstantFoldingRules() { rules_[SpvOpVectorTimesScalar].push_back(FoldVectorTimesScalar()); rules_[SpvOpFNegate].push_back(FoldFNegate()); + rules_[SpvOpQuantizeToF16].push_back(FoldQuantizeToF16()); } } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/constants.cpp b/3rdparty/spirv-tools/source/opt/constants.cpp index 8dce8ec56..3c05f9e9e 100644 --- a/3rdparty/spirv-tools/source/opt/constants.cpp +++ b/3rdparty/spirv-tools/source/opt/constants.cpp @@ -185,8 +185,6 @@ Instruction* ConstantManager::BuildInstructionAndAddToModule( Instruction* ConstantManager::GetDefiningInstruction( const Constant* c, uint32_t type_id, Module::inst_iterator* pos) { - assert(type_id == 0 || - context()->get_type_mgr()->GetType(type_id) == c->type()); uint32_t decl_id = FindDeclaredConstant(c, type_id); if (decl_id == 0) { auto iter = context()->types_values_end(); diff --git a/3rdparty/spirv-tools/source/opt/constants.h b/3rdparty/spirv-tools/source/opt/constants.h index 5baeaebe8..d62d55208 100644 --- a/3rdparty/spirv-tools/source/opt/constants.h +++ b/3rdparty/spirv-tools/source/opt/constants.h @@ -524,12 +524,7 @@ class ConstantManager { // instruction at the end of the current module's types section. // // |type_id| is an optional argument for disambiguating equivalent types. If - // |type_id| is specified, it is used as the type of the constant when a new - // instruction is created. Otherwise the type of the constant is derived by - // getting an id from the type manager for |c|. - // - // When |type_id| is not zero, the type of |c| must be the type returned by - // type manager when given |type_id|. + // |type_id| is specified, the contant returned will have that type id. Instruction* GetDefiningInstruction(const Constant* c, uint32_t type_id = 0, Module::inst_iterator* pos = nullptr); diff --git a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp index 087c2af2a..68c0f22f4 100644 --- a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp @@ -169,24 +169,43 @@ bool DeadBranchElimPass::MarkLiveBlocks( if (simplify) { modified = true; - // Replace with unconditional branch. - // Remove the merge instruction if it is a selection merge. - AddBranch(live_lab_id, block); - context()->KillInst(terminator); + // Replace branch with a simpler branch. + // Fix up the merge instruction if it is a selection merge. Instruction* mergeInst = block->GetMergeInst(); if (mergeInst && mergeInst->opcode() == SpvOpSelectionMerge) { - Instruction* first_break = FindFirstExitFromSelectionMerge( - live_lab_id, mergeInst->GetSingleWordInOperand(0), - cfgAnalysis->LoopMergeBlock(live_lab_id), - cfgAnalysis->LoopContinueBlock(live_lab_id)); - if (first_break == nullptr) { - context()->KillInst(mergeInst); + if (mergeInst->NextNode()->opcode() == SpvOpSwitch && + SwitchHasNestedBreak(block->id())) { + // We have to keep the switch because it has a nest break, so we + // remove all cases except for the live one. + Instruction::OperandList new_operands; + new_operands.push_back(terminator->GetInOperand(0)); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {live_lab_id}}); + terminator->SetInOperands(std::move(new_operands)); + context()->UpdateDefUse(terminator); } else { - mergeInst->RemoveFromList(); - first_break->InsertBefore(std::unique_ptr(mergeInst)); - context()->set_instr_block(mergeInst, - context()->get_instr_block(first_break)); + // Check if the merge instruction is still needed because of a + // non-nested break from the construct. Move the merge instruction if + // it is still needed. + Instruction* first_break = FindFirstExitFromSelectionMerge( + live_lab_id, mergeInst->GetSingleWordInOperand(0), + cfgAnalysis->LoopMergeBlock(live_lab_id), + cfgAnalysis->LoopContinueBlock(live_lab_id), + cfgAnalysis->SwitchMergeBlock(live_lab_id)); + + AddBranch(live_lab_id, block); + context()->KillInst(terminator); + if (first_break == nullptr) { + context()->KillInst(mergeInst); + } else { + mergeInst->RemoveFromList(); + first_break->InsertBefore(std::unique_ptr(mergeInst)); + context()->set_instr_block(mergeInst, + context()->get_instr_block(first_break)); + } } + } else { + AddBranch(live_lab_id, block); + context()->KillInst(terminator); } stack.push_back(GetParentBlock(live_lab_id)); } else { @@ -455,11 +474,12 @@ Pass::Status DeadBranchElimPass::Process() { Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge( uint32_t start_block_id, uint32_t merge_block_id, uint32_t loop_merge_id, - uint32_t loop_continue_id) { + uint32_t loop_continue_id, uint32_t switch_merge_id) { // To find the "first" exit, we follow branches looking for a conditional // branch that is not in a nested construct and is not the header of a new // construct. We follow the control flow from |start_block_id| to find the // first one. + while (start_block_id != merge_block_id && start_block_id != loop_merge_id && start_block_id != loop_continue_id) { BasicBlock* start_block = context()->get_instr_block(start_block_id); @@ -483,6 +503,11 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge( next_block_id = branch->GetSingleWordInOperand(3 - i); break; } + if (branch->GetSingleWordInOperand(i) == switch_merge_id && + switch_merge_id != merge_block_id) { + next_block_id = branch->GetSingleWordInOperand(3 - i); + break; + } } if (next_block_id == 0) { @@ -493,11 +518,15 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge( case SpvOpSwitch: next_block_id = start_block->MergeBlockIdIfAny(); if (next_block_id == 0) { - // A switch with no merge instructions can have at most 4 targets: + // A switch with no merge instructions can have at most 5 targets: // a. |merge_block_id| // b. |loop_merge_id| // c. |loop_continue_id| - // d. 1 block inside the current region. + // d. |switch_merge_id| + // e. 1 block inside the current region. + // + // Note that because this is a switch, |merge_block_id| must equal + // |switch_merge_id|. // // This leads to a number of cases of what to do. // @@ -511,7 +540,6 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge( // // 3. Otherwise, this branch may break, but not to the current merge // block. So we continue with the block that is inside the loop. - bool found_break = false; for (uint32_t i = 1; i < branch->NumInOperands(); i += 2) { uint32_t target = branch->GetSingleWordInOperand(i); @@ -585,5 +613,26 @@ void DeadBranchElimPass::AddBlocksWithBackEdge( } } +bool DeadBranchElimPass::SwitchHasNestedBreak(uint32_t switch_header_id) { + std::vector block_in_construct; + BasicBlock* start_block = context()->get_instr_block(switch_header_id); + uint32_t merge_block_id = start_block->MergeBlockIdIfAny(); + + StructuredCFGAnalysis* cfg_analysis = context()->GetStructuredCFGAnalysis(); + return !get_def_use_mgr()->WhileEachUser( + merge_block_id, + [this, cfg_analysis, switch_header_id](Instruction* inst) { + if (!inst->IsBranch()) { + return true; + } + + BasicBlock* bb = context()->get_instr_block(inst); + if (bb->id() == switch_header_id) { + return true; + } + return (cfg_analysis->ContainingConstruct(inst) == switch_header_id); + }); +} + } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h index 2ced589d7..eadf04d8d 100644 --- a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h +++ b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h @@ -147,7 +147,8 @@ class DeadBranchElimPass : public MemPass { Instruction* FindFirstExitFromSelectionMerge(uint32_t start_block_id, uint32_t merge_block_id, uint32_t loop_merge_id, - uint32_t loop_continue_id); + uint32_t loop_continue_id, + uint32_t switch_merge_id); // Adds to |blocks_with_back_edges| all of the blocks on the path from the // basic block |cont_id| to |header_id| and |merge_id|. The intention is that @@ -156,6 +157,10 @@ class DeadBranchElimPass : public MemPass { void AddBlocksWithBackEdge( uint32_t cont_id, uint32_t header_id, uint32_t merge_id, std::unordered_set* blocks_with_back_edges); + + // Returns true if there is a brach to the merge node of the selection + // construct |switch_header_id| that is inside a nested selection construct. + bool SwitchHasNestedBreak(uint32_t switch_header_id); }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp index 663d112d4..56d0137f3 100644 --- a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -120,19 +120,15 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp( switch (static_cast(inst->GetSingleWordInOperand(0))) { case SpvOp::SpvOpCompositeExtract: - folded_inst = DoCompositeExtract(pos); - break; case SpvOp::SpvOpVectorShuffle: - folded_inst = DoVectorShuffle(pos); - break; - case SpvOp::SpvOpCompositeInsert: - // Current Glslang does not generate code with OpSpecConstantOp - // CompositeInsert instruction, so this is not implmented so far. - // TODO(qining): Implement CompositeInsert case. - return false; - + case SpvOp::SpvOpQuantizeToF16: + folded_inst = FoldWithInstructionFolder(pos); + break; default: + // TODO: This should use the instruction folder as well, but some folding + // rules are missing. + // Component-wise operations. folded_inst = DoComponentWiseOperation(pos); break; @@ -157,54 +153,65 @@ uint32_t FoldSpecConstantOpAndCompositePass::GetTypeComponent( return subtype; } -Instruction* FoldSpecConstantOpAndCompositePass::DoCompositeExtract( - Module::inst_iterator* pos) { - Instruction* inst = &**pos; - assert(inst->NumInOperands() - 1 >= 2 && - "OpSpecConstantOp CompositeExtract requires at least two non-type " - "non-opcode operands."); - assert(inst->GetInOperand(1).type == SPV_OPERAND_TYPE_ID && - "The composite operand must have a SPV_OPERAND_TYPE_ID type"); - assert( - inst->GetInOperand(2).type == SPV_OPERAND_TYPE_LITERAL_INTEGER && - "The literal operand must have a SPV_OPERAND_TYPE_LITERAL_INTEGER type"); - - // Note that for OpSpecConstantOp, the second in-operand is the first id - // operand. The first in-operand is the spec opcode. - uint32_t source = inst->GetSingleWordInOperand(1); - uint32_t type = context()->get_def_use_mgr()->GetDef(source)->type_id(); - const analysis::Constant* first_operand_const = - context()->get_constant_mgr()->FindDeclaredConstant(source); - if (!first_operand_const) return nullptr; - - const analysis::Constant* current_const = first_operand_const; - for (uint32_t i = 2; i < inst->NumInOperands(); i++) { - uint32_t literal = inst->GetSingleWordInOperand(i); - type = GetTypeComponent(type, literal); - } - for (uint32_t i = 2; i < inst->NumInOperands(); i++) { - uint32_t literal = inst->GetSingleWordInOperand(i); - if (const analysis::CompositeConstant* composite_const = - current_const->AsCompositeConstant()) { - // Case 1: current constant is a non-null composite type constant. - assert(literal < composite_const->GetComponents().size() && - "Literal index out of bound of the composite constant"); - current_const = composite_const->GetComponents().at(literal); - } else if (current_const->AsNullConstant()) { - // Case 2: current constant is a constant created with OpConstantNull. - // Because components of a NullConstant are always NullConstants, we can - // return early with a NullConstant in the result type. - return context()->get_constant_mgr()->BuildInstructionAndAddToModule( - context()->get_constant_mgr()->GetConstant( - context()->get_constant_mgr()->GetType(inst), {}), - pos, type); - } else { - // Dereferencing a non-composite constant. Invalid case. +Instruction* FoldSpecConstantOpAndCompositePass::FoldWithInstructionFolder( + Module::inst_iterator* inst_iter_ptr) { + // If one of operands to the instruction is not a + // constant, then we cannot fold this spec constant. + for (uint32_t i = 1; i < (*inst_iter_ptr)->NumInOperands(); i++) { + const Operand& operand = (*inst_iter_ptr)->GetInOperand(i); + if (operand.type != SPV_OPERAND_TYPE_ID && + operand.type != SPV_OPERAND_TYPE_OPTIONAL_ID) { + continue; + } + uint32_t id = operand.words[0]; + if (context()->get_constant_mgr()->FindDeclaredConstant(id) == nullptr) { return nullptr; } } - return context()->get_constant_mgr()->BuildInstructionAndAddToModule( - current_const, pos); + + // All of the operands are constant. Construct a regular version of the + // instruction and pass it to the instruction folder. + std::unique_ptr inst((*inst_iter_ptr)->Clone(context())); + inst->SetOpcode( + static_cast((*inst_iter_ptr)->GetSingleWordInOperand(0))); + inst->RemoveOperand(2); + + // We want the current instruction to be replaced by an |OpConstant*| + // instruction in the same position. We need to keep track of which constants + // the instruction folder creates, so we can move them into the correct place. + auto last_type_value_iter = (context()->types_values_end()); + --last_type_value_iter; + Instruction* last_type_value = &*last_type_value_iter; + + auto identity_map = [](uint32_t id) { return id; }; + Instruction* new_const_inst = + context()->get_instruction_folder().FoldInstructionToConstant( + inst.get(), identity_map); + assert(new_const_inst != nullptr && + "Failed to fold instruction that must be folded."); + + // Get the instruction before |pos| to insert after. |pos| cannot be the + // first instruction in the list because its type has to come first. + Instruction* insert_pos = (*inst_iter_ptr)->PreviousNode(); + assert(insert_pos != nullptr && + "pos is the first instruction in the types and values."); + bool need_to_clone = true; + for (Instruction* i = last_type_value->NextNode(); i != nullptr; + i = last_type_value->NextNode()) { + if (i == new_const_inst) { + need_to_clone = false; + } + i->InsertAfter(insert_pos); + insert_pos = insert_pos->NextNode(); + } + + if (need_to_clone) { + new_const_inst = new_const_inst->Clone(context()); + new_const_inst->SetResultId(TakeNextId()); + new_const_inst->InsertAfter(insert_pos); + get_def_use_mgr()->AnalyzeInstDefUse(new_const_inst); + } + return new_const_inst; } Instruction* FoldSpecConstantOpAndCompositePass::DoVectorShuffle( diff --git a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h index 16271251f..361d3cacb 100644 --- a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h +++ b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h @@ -54,11 +54,9 @@ class FoldSpecConstantOpAndCompositePass : public Pass { // it. bool ProcessOpSpecConstantOp(Module::inst_iterator* pos); - // Try to fold the OpSpecConstantOp CompositeExtract instruction pointed by - // the given instruction iterator to a normal constant defining instruction. - // Returns the pointer to the new constant defining instruction if succeeded. - // Otherwise returns nullptr. - Instruction* DoCompositeExtract(Module::inst_iterator* inst_iter_ptr); + // Returns the result of folding the OpSpecConstantOp instruction + // |inst_iter_ptr| using the instruction folder. + Instruction* FoldWithInstructionFolder(Module::inst_iterator* inst_iter_ptr); // Try to fold the OpSpecConstantOp VectorShuffle instruction pointed by the // given instruction iterator to a normal constant defining instruction. diff --git a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h index 5e9921e2f..12384b1fd 100644 --- a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h +++ b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h @@ -30,13 +30,14 @@ class InstBindlessCheckPass : public InstrumentPass { public: // For test harness only InstBindlessCheckPass() - : InstrumentPass(7, 23, kInstValidationIdBindless), + : InstrumentPass(7, 23, kInstValidationIdBindless, 1), input_length_enabled_(true), input_init_enabled_(true) {} // For all other interfaces InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id, - bool input_length_enable, bool input_init_enable) - : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless), + bool input_length_enable, bool input_init_enable, + uint32_t version) + : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, version), input_length_enabled_(input_length_enable), input_init_enabled_(input_init_enable) {} diff --git a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp index 032cd280a..36fe00e43 100644 --- a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp @@ -143,23 +143,21 @@ void InstrumentPass::GenFragCoordEltDebugOutputCode( element_val_inst->result_id(), builder); } +uint32_t InstrumentPass::GenVarLoad(uint32_t var_id, + InstructionBuilder* builder) { + Instruction* var_inst = get_def_use_mgr()->GetDef(var_id); + uint32_t type_id = GetPointeeTypeId(var_inst); + Instruction* load_inst = builder->AddUnaryOp(type_id, SpvOpLoad, var_id); + return load_inst->result_id(); +} + void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id, uint32_t builtin_off, uint32_t base_offset_id, InstructionBuilder* builder) { // Load and store builtin - Instruction* var_inst = get_def_use_mgr()->GetDef(builtin_id); - uint32_t type_id = GetPointeeTypeId(var_inst); - Instruction* load_inst = builder->AddUnaryOp(type_id, SpvOpLoad, builtin_id); - uint32_t val_id = GenUintCastCode(load_inst->result_id(), builder); - GenDebugOutputFieldCode(base_offset_id, builtin_off, val_id, builder); -} - -void InstrumentPass::GenUintNullOutputCode(uint32_t field_off, - uint32_t base_offset_id, - InstructionBuilder* builder) { - GenDebugOutputFieldCode(base_offset_id, field_off, - builder->GetNullId(GetUintId()), builder); + uint32_t load_id = GenVarLoad(builtin_id, builder); + GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder); } void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, @@ -169,37 +167,97 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, switch (stage_idx) { case SpvExecutionModelVertex: { // Load and store VertexId and InstanceId - GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexIndex), - kInstVertOutVertexIndex, base_offset_id, builder); - GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceIndex), - kInstVertOutInstanceIndex, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInVertexIndex), + kInstVertOutVertexIndex, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInInstanceIndex), + kInstVertOutInstanceIndex, base_offset_id, builder); } break; case SpvExecutionModelGLCompute: { - // Load and store GlobalInvocationId. Second word is unused; store zero. - GenBuiltinOutputCode( - context()->GetBuiltinVarId(SpvBuiltInGlobalInvocationId), - kInstCompOutGlobalInvocationId, base_offset_id, builder); - GenUintNullOutputCode(kInstCompOutUnused, base_offset_id, builder); + // Load and store GlobalInvocationId. + uint32_t load_id = GenVarLoad( + context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId), + builder); + Instruction* x_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 0); + Instruction* y_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 1); + Instruction* z_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 2); + if (version_ == 1) { + // For version 1 format, as a stopgap, pack uvec3 into first word: + // x << 21 | y << 10 | z. Second word is unused. (DEPRECATED) + Instruction* x_shft_inst = builder->AddBinaryOp( + GetUintId(), SpvOpShiftLeftLogical, x_inst->result_id(), + builder->GetUintConstantId(21)); + Instruction* y_shft_inst = builder->AddBinaryOp( + GetUintId(), SpvOpShiftLeftLogical, y_inst->result_id(), + builder->GetUintConstantId(10)); + Instruction* x_or_y_inst = builder->AddBinaryOp( + GetUintId(), SpvOpBitwiseOr, x_shft_inst->result_id(), + y_shft_inst->result_id()); + Instruction* x_or_y_or_z_inst = + builder->AddBinaryOp(GetUintId(), SpvOpBitwiseOr, + x_or_y_inst->result_id(), z_inst->result_id()); + GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationId, + x_or_y_or_z_inst->result_id(), builder); + } else { + // For version 2 format, write all three words + GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX, + x_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY, + y_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ, + z_inst->result_id(), builder); + } } break; case SpvExecutionModelGeometry: { // Load and store PrimitiveId and InvocationId. - GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInPrimitiveId), - kInstGeomOutPrimitiveId, base_offset_id, builder); - GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInvocationId), - kInstGeomOutInvocationId, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), + kInstGeomOutPrimitiveId, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInInvocationId), + kInstGeomOutInvocationId, base_offset_id, builder); + } break; + case SpvExecutionModelTessellationControl: { + // Load and store InvocationId and PrimitiveId + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInInvocationId), + kInstTessCtlOutInvocationId, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), + kInstTessCtlOutPrimitiveId, base_offset_id, builder); } break; - case SpvExecutionModelTessellationControl: case SpvExecutionModelTessellationEvaluation: { - // Load and store InvocationId. Second word is unused; store zero. - GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInvocationId), - kInstTessOutInvocationId, base_offset_id, builder); - GenUintNullOutputCode(kInstTessOutUnused, base_offset_id, builder); + if (version_ == 1) { + // For format version 1, load and store InvocationId. + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInInvocationId), + kInstTessOutInvocationId, base_offset_id, builder); + } else { + // For format version 2, load and store PrimitiveId and TessCoord.uv + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), + kInstTessEvalOutPrimitiveId, base_offset_id, builder); + uint32_t load_id = GenVarLoad( + context()->GetBuiltinInputVarId(SpvBuiltInTessCoord), builder); + Instruction* u_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 0); + Instruction* v_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 1); + GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU, + u_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV, + v_inst->result_id(), builder); + } } break; case SpvExecutionModelFragment: { // Load FragCoord and convert to Uint - Instruction* frag_coord_inst = - builder->AddUnaryOp(GetVec4FloatId(), SpvOpLoad, - context()->GetBuiltinVarId(SpvBuiltInFragCoord)); + Instruction* frag_coord_inst = builder->AddUnaryOp( + GetVec4FloatId(), SpvOpLoad, + context()->GetBuiltinInputVarId(SpvBuiltInFragCoord)); Instruction* uint_frag_coord_inst = builder->AddUnaryOp( GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id()); for (uint32_t u = 0; u < 2u; ++u) @@ -547,7 +605,9 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, context(), &*new_blk_ptr, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); // Gen test if debug output buffer size will not be exceeded. - uint32_t obuf_record_sz = kInstStageOutCnt + val_spec_param_cnt; + uint32_t val_spec_offset = + (version_ == 1) ? kInstStageOutCnt : kInst2StageOutCnt; + uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt; uint32_t buf_id = GetOutputBufferId(); uint32_t buf_uint_ptr_id = GetBufferUintPtrId(); Instruction* obuf_curr_sz_ac_inst = @@ -593,7 +653,7 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder); // Gen writes of validation specific data for (uint32_t i = 0; i < val_spec_param_cnt; ++i) { - GenDebugOutputFieldCode(obuf_curr_sz_id, kInstStageOutCnt + i, + GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i, param_vec[kInstCommonParamCnt + i], &builder); } // Close write block and gen merge block diff --git a/3rdparty/spirv-tools/source/opt/instrument_pass.h b/3rdparty/spirv-tools/source/opt/instrument_pass.h index c4b97d638..d2556989b 100644 --- a/3rdparty/spirv-tools/source/opt/instrument_pass.h +++ b/3rdparty/spirv-tools/source/opt/instrument_pass.h @@ -78,16 +78,18 @@ class InstrumentPass : public Pass { } protected: - // Create instrumentation pass which utilizes descriptor set |desc_set| - // for debug input and output buffers and writes |shader_id| into debug - // output records. - InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id) + // Create instrumentation pass for |validation_id| which utilizes descriptor + // set |desc_set| for debug input and output buffers and writes |shader_id| + // into debug output records with format |version|. + InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id, + uint32_t version) : Pass(), desc_set_(desc_set), shader_id_(shader_id), - validation_id_(validation_id) {} + validation_id_(validation_id), + version_(version) {} - // Initialize state for instrumentation of module by |validation_id|. + // Initialize state for instrumentation of module. void InitializeInstrument(); // Call |pfn| on all instructions in all functions in the call tree of the @@ -146,6 +148,7 @@ class InstrumentPass : public Pass { // Stage // Stage-specific Word 0 // Stage-specific Word 1 + // ... // Validation Error Code // Validation-specific Word 0 // Validation-specific Word 1 @@ -170,12 +173,12 @@ class InstrumentPass : public Pass { // following Stage-specific words. // // The Stage-specific Words identify which invocation of the shader generated - // the error. Every stage will write two words, although in some cases the - // second word is unused and so zero is written. Vertex shaders will write - // the Vertex and Instance ID. Fragment shaders will write FragCoord.xy. - // Compute shaders will write the Global Invocation ID and zero (unused). - // Both tesselation shaders will write the Invocation Id and zero (unused). - // The geometry shader will write the Primitive ID and Invocation ID. + // the error. Every stage will write a fixed number of words. Vertex shaders + // will write the Vertex and Instance ID. Fragment shaders will write + // FragCoord.xy. Compute shaders will write the GlobalInvocation ID. + // The tesselation eval shader will write the Primitive ID and TessCoords.uv. + // The tesselation control shader and geometry shader will write the + // Primitive ID and Invocation ID. // // The Validation Error Code specifies the exact error which has occurred. // These are enumerated with the kInstError* static consts. This allows @@ -291,16 +294,15 @@ class InstrumentPass : public Pass { uint32_t component, InstructionBuilder* builder); + // Generate instructions into |builder| which will load |var_id| and return + // its result id. + uint32_t GenVarLoad(uint32_t var_id, InstructionBuilder* builder); + // Generate instructions into |builder| which will load the uint |builtin_id| // and write it into the debug output buffer at |base_off| + |builtin_off|. void GenBuiltinOutputCode(uint32_t builtin_id, uint32_t builtin_off, uint32_t base_off, InstructionBuilder* builder); - // Generate instructions into |builder| which will write a uint null into - // the debug output buffer at |base_off| + |builtin_off|. - void GenUintNullOutputCode(uint32_t field_off, uint32_t base_off, - InstructionBuilder* builder); - // Generate instructions into |builder| which will write the |stage_idx|- // specific members of the debug output stream at |base_off|. void GenStageStreamWriteCode(uint32_t stage_idx, uint32_t base_off, @@ -376,6 +378,9 @@ class InstrumentPass : public Pass { // id for void type uint32_t void_id_; + // Record format version + uint32_t version_; + // boolean to remember storage buffer extension bool storage_buffer_ext_defined_; diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index 61c5425d6..081fdbc1e 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -621,7 +621,7 @@ LoopDescriptor* IRContext::GetLoopDescriptor(const Function* f) { return &it->second; } -uint32_t IRContext::FindBuiltinVar(uint32_t builtin) { +uint32_t IRContext::FindBuiltinInputVar(uint32_t builtin) { for (auto& a : module_->annotations()) { if (a.opcode() != SpvOpDecorate) continue; if (a.GetSingleWordInOperand(kSpvDecorateDecorationInIdx) != @@ -631,6 +631,7 @@ uint32_t IRContext::FindBuiltinVar(uint32_t builtin) { uint32_t target_id = a.GetSingleWordInOperand(kSpvDecorateTargetIdInIdx); Instruction* b_var = get_def_use_mgr()->GetDef(target_id); if (b_var->opcode() != SpvOpVariable) continue; + if (b_var->GetSingleWordInOperand(0) != SpvStorageClassInput) continue; return target_id; } return 0; @@ -653,14 +654,14 @@ void IRContext::AddVarToEntryPoints(uint32_t var_id) { } } -uint32_t IRContext::GetBuiltinVarId(uint32_t builtin) { +uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) { if (!AreAnalysesValid(kAnalysisBuiltinVarId)) ResetBuiltinAnalysis(); // If cached, return it. std::unordered_map::iterator it = builtin_var_id_map_.find(builtin); if (it != builtin_var_id_map_.end()) return it->second; // Look for one in shader - uint32_t var_id = FindBuiltinVar(builtin); + uint32_t var_id = FindBuiltinInputVar(builtin); if (var_id == 0) { // If not found, create it // TODO(greg-lunarg): Add support for all builtins diff --git a/3rdparty/spirv-tools/source/opt/ir_context.h b/3rdparty/spirv-tools/source/opt/ir_context.h index c857c520e..32d5b1791 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.h +++ b/3rdparty/spirv-tools/source/opt/ir_context.h @@ -491,10 +491,10 @@ class IRContext { uint32_t max_id_bound() const { return max_id_bound_; } void set_max_id_bound(uint32_t new_bound) { max_id_bound_ = new_bound; } - // Return id of variable only decorated with |builtin|, if in module. + // Return id of input variable only decorated with |builtin|, if in module. // Create variable and return its id otherwise. If builtin not currently // supported, return 0. - uint32_t GetBuiltinVarId(uint32_t builtin); + uint32_t GetBuiltinInputVarId(uint32_t builtin); // Returns the function whose id is |id|, if one exists. Returns |nullptr| // otherwise. @@ -657,9 +657,9 @@ class IRContext { // true if the cfg is invalidated. bool CheckCFG(); - // Return id of variable only decorated with |builtin|, if in module. + // Return id of input variable only decorated with |builtin|, if in module. // Return 0 otherwise. - uint32_t FindBuiltinVar(uint32_t builtin); + uint32_t FindBuiltinInputVar(uint32_t builtin); // Add |var_id| to all entry points in module. void AddVarToEntryPoints(uint32_t var_id); diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index d6f9cef94..62d886a64 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -229,11 +229,13 @@ Optimizer& Optimizer::RegisterVulkanToWebGPUPasses() { .RegisterPass(CreateEliminateDeadConstantPass()) .RegisterPass(CreateFlattenDecorationPass()) .RegisterPass(CreateAggressiveDCEPass()) - .RegisterPass(CreateDeadBranchElimPass()); + .RegisterPass(CreateDeadBranchElimPass()) + .RegisterPass(CreateCompactIdsPass()); } Optimizer& Optimizer::RegisterWebGPUToVulkanPasses() { - return RegisterPass(CreateDecomposeInitializedVariablesPass()); + return RegisterPass(CreateDecomposeInitializedVariablesPass()) + .RegisterPass(CreateCompactIdsPass()); } bool Optimizer::RegisterPassesFromFlags(const std::vector& flags) { @@ -397,7 +399,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } else if (pass_name == "replace-invalid-opcode") { RegisterPass(CreateReplaceInvalidOpcodePass()); } else if (pass_name == "inst-bindless-check") { - RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true)); + RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true, 1)); RegisterPass(CreateSimplificationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); @@ -472,6 +474,10 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateGenerateWebGPUInitializersPass()); } else if (pass_name == "legalize-vector-shuffle") { RegisterPass(CreateLegalizeVectorShufflePass()); + } else if (pass_name == "split-invalid-unreachable") { + RegisterPass(CreateLegalizeVectorShufflePass()); + } else if (pass_name == "decompose-initialized-variables") { + RegisterPass(CreateDecomposeInitializedVariablesPass()); } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -843,10 +849,12 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() { Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id, bool input_length_enable, - bool input_init_enable) { + bool input_init_enable, + uint32_t version) { return MakeUnique( - MakeUnique( - desc_set, shader_id, input_length_enable, input_init_enable)); + MakeUnique(desc_set, shader_id, + input_length_enable, + input_init_enable, version)); } Optimizer::PassToken CreateCodeSinkingPass() { diff --git a/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.cpp b/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.cpp index a37e9df9e..0e65cc8d1 100644 --- a/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.cpp @@ -96,35 +96,67 @@ bool RemoveDuplicatesPass::RemoveDuplicateTypes() const { return modified; } + analysis::TypeManager type_manager(context()->consumer(), context()); + std::vector visited_types; + std::vector visited_forward_pointers; std::vector to_delete; for (auto* i = &*context()->types_values_begin(); i; i = i->NextNode()) { + const bool is_i_forward_pointer = i->opcode() == SpvOpTypeForwardPointer; + // We only care about types. - if (!spvOpcodeGeneratesType((i->opcode())) && - i->opcode() != SpvOpTypeForwardPointer) { + if (!spvOpcodeGeneratesType(i->opcode()) && !is_i_forward_pointer) { continue; } - // Is the current type equal to one of the types we have aready visited? - SpvId id_to_keep = 0u; - // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the - // ResultIdTrie from unify_const_pass.cpp for this. - for (auto j : visited_types) { - if (AreTypesEqual(*i, *j, context())) { - id_to_keep = j->result_id(); - break; + if (!is_i_forward_pointer) { + // Is the current type equal to one of the types we have already visited? + SpvId id_to_keep = 0u; + analysis::Type* i_type = type_manager.GetType(i->result_id()); + assert(i_type); + // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the + // ResultIdTrie from unify_const_pass.cpp for this. + for (auto j : visited_types) { + analysis::Type* j_type = type_manager.GetType(j->result_id()); + assert(j_type); + if (*i_type == *j_type) { + id_to_keep = j->result_id(); + break; + } } - } - if (id_to_keep == 0u) { - // This is a never seen before type, keep it around. - visited_types.emplace_back(i); + if (id_to_keep == 0u) { + // This is a never seen before type, keep it around. + visited_types.emplace_back(i); + } else { + // The same type has already been seen before, remove this one. + context()->KillNamesAndDecorates(i->result_id()); + context()->ReplaceAllUsesWith(i->result_id(), id_to_keep); + modified = true; + to_delete.emplace_back(i); + } } else { - // The same type has already been seen before, remove this one. - context()->KillNamesAndDecorates(i->result_id()); - context()->ReplaceAllUsesWith(i->result_id(), id_to_keep); - modified = true; - to_delete.emplace_back(i); + analysis::ForwardPointer i_type( + i->GetSingleWordInOperand(0u), + (SpvStorageClass)i->GetSingleWordInOperand(1u)); + i_type.SetTargetPointer( + type_manager.GetType(i_type.target_id())->AsPointer()); + + // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the + // ResultIdTrie from unify_const_pass.cpp for this. + const bool found_a_match = + std::find(std::begin(visited_forward_pointers), + std::end(visited_forward_pointers), + i_type) != std::end(visited_forward_pointers); + + if (!found_a_match) { + // This is a never seen before type, keep it around. + visited_forward_pointers.emplace_back(i_type); + } else { + // The same type has already been seen before, remove this one. + modified = true; + to_delete.emplace_back(i); + } } } @@ -151,8 +183,8 @@ bool RemoveDuplicatesPass::RemoveDuplicateDecorations() const { analysis::DecorationManager decoration_manager(context()->module()); for (auto* i = &*context()->annotation_begin(); i;) { - // Is the current decoration equal to one of the decorations we have aready - // visited? + // Is the current decoration equal to one of the decorations we have + // already visited? bool already_visited = false; // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the // ResultIdTrie from unify_const_pass.cpp for this. @@ -177,20 +209,5 @@ bool RemoveDuplicatesPass::RemoveDuplicateDecorations() const { return modified; } -bool RemoveDuplicatesPass::AreTypesEqual(const Instruction& inst1, - const Instruction& inst2, - IRContext* context) { - if (inst1.opcode() != inst2.opcode()) return false; - if (!IsTypeInst(inst1.opcode())) return false; - - const analysis::Type* type1 = - context->get_type_mgr()->GetType(inst1.result_id()); - const analysis::Type* type2 = - context->get_type_mgr()->GetType(inst2.result_id()); - if (type1 && type2 && *type1 == *type2) return true; - - return false; -} - } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.h b/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.h index 8554a987d..038caa8b9 100644 --- a/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.h +++ b/3rdparty/spirv-tools/source/opt/remove_duplicates_pass.h @@ -36,12 +36,6 @@ class RemoveDuplicatesPass : public Pass { const char* name() const override { return "remove-duplicates"; } Status Process() override; - // TODO(pierremoreau): Move this function somewhere else (e.g. pass.h or - // within the type manager) - // Returns whether two types are equal, and have the same decorations. - static bool AreTypesEqual(const Instruction& inst1, const Instruction& inst2, - IRContext* context); - private: // Remove duplicate capabilities from the module // diff --git a/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp b/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp index dcfd4a59b..152ded508 100644 --- a/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp +++ b/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.cpp @@ -52,6 +52,7 @@ void StructuredCFGAnalysis::AddBlocksInFunction(Function* func) { state.emplace_back(); state[0].cinfo.containing_construct = 0; state[0].cinfo.containing_loop = 0; + state[0].cinfo.containing_switch = 0; state[0].merge_node = 0; for (BasicBlock* block : order) { @@ -74,8 +75,15 @@ void StructuredCFGAnalysis::AddBlocksInFunction(Function* func) { if (merge_inst->opcode() == SpvOpLoopMerge) { new_state.cinfo.containing_loop = block->id(); + new_state.cinfo.containing_switch = 0; } else { new_state.cinfo.containing_loop = state.back().cinfo.containing_loop; + if (merge_inst->NextNode()->opcode() == SpvOpSwitch) { + new_state.cinfo.containing_switch = block->id(); + } else { + new_state.cinfo.containing_switch = + state.back().cinfo.containing_switch; + } } state.emplace_back(new_state); @@ -84,6 +92,11 @@ void StructuredCFGAnalysis::AddBlocksInFunction(Function* func) { } } +uint32_t StructuredCFGAnalysis::ContainingConstruct(Instruction* inst) { + uint32_t bb = context_->get_instr_block(inst)->id(); + return ContainingConstruct(bb); +} + uint32_t StructuredCFGAnalysis::MergeBlock(uint32_t bb_id) { uint32_t header_id = ContainingConstruct(bb_id); if (header_id == 0) { @@ -117,6 +130,17 @@ uint32_t StructuredCFGAnalysis::LoopContinueBlock(uint32_t bb_id) { return merge_inst->GetSingleWordInOperand(kContinueNodeIndex); } +uint32_t StructuredCFGAnalysis::SwitchMergeBlock(uint32_t bb_id) { + uint32_t header_id = ContainingSwitch(bb_id); + if (header_id == 0) { + return 0; + } + + BasicBlock* header = context_->cfg()->block(header_id); + Instruction* merge_inst = header->GetMergeInst(); + return merge_inst->GetSingleWordInOperand(kMergeNodeIndex); +} + bool StructuredCFGAnalysis::IsContinueBlock(uint32_t bb_id) { assert(bb_id != 0); return LoopContinueBlock(bb_id) == bb_id; diff --git a/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.h b/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.h index ef0229d05..f25266a8f 100644 --- a/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.h +++ b/3rdparty/spirv-tools/source/opt/struct_cfg_analysis.h @@ -42,6 +42,11 @@ class StructuredCFGAnalysis { return it->second.containing_construct; } + // Returns the id of the header of the innermost merge construct + // that contains |inst|. Returns |0| if |inst| is not contained in any + // merge construct. + uint32_t ContainingConstruct(Instruction* inst); + // Returns the id of the merge block of the innermost merge construct // that contains |bb_id|. Returns |0| if |bb_id| is not contained in any // merge construct. @@ -68,6 +73,21 @@ class StructuredCFGAnalysis { // construct. uint32_t LoopContinueBlock(uint32_t bb_id); + // Returns the id of the header of the innermost switch construct + // that contains |bb_id| as long as there is no intervening loop. Returns |0| + // if no such construct exists. + uint32_t ContainingSwitch(uint32_t bb_id) { + auto it = bb_to_construct_.find(bb_id); + if (it == bb_to_construct_.end()) { + return 0; + } + return it->second.containing_switch; + } + // Returns the id of the merge block of the innermost switch construct + // that contains |bb_id| as long as there is no intervening loop. Return |0| + // if no such block exists. + uint32_t SwitchMergeBlock(uint32_t bb_id); + bool IsContinueBlock(uint32_t bb_id); bool IsMergeBlock(uint32_t bb_id); @@ -82,6 +102,7 @@ class StructuredCFGAnalysis { struct ConstructInfo { uint32_t containing_construct; uint32_t containing_loop; + uint32_t containing_switch; }; // Populates |bb_to_construct_| with the innermost containing merge and loop diff --git a/3rdparty/spirv-tools/source/opt/type_manager.cpp b/3rdparty/spirv-tools/source/opt/type_manager.cpp index 001883cad..1c27b16f4 100644 --- a/3rdparty/spirv-tools/source/opt/type_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/type_manager.cpp @@ -66,7 +66,13 @@ uint32_t TypeManager::GetId(const Type* type) const { } void TypeManager::AnalyzeTypes(const Module& module) { - // First pass through the types. Any types that reference a forward pointer + // First pass through the constants, as some will be needed when traversing + // the types in the next pass. + for (const auto* inst : module.GetConstants()) { + id_to_constant_inst_[inst->result_id()] = inst; + } + + // Then pass through the types. Any types that reference a forward pointer // (directly or indirectly) are incomplete, and are added to incomplete types. for (const auto* inst : module.GetTypes()) { RecordIfTypeDefinition(*inst); @@ -154,7 +160,7 @@ void TypeManager::AnalyzeTypes(const Module& module) { #ifndef NDEBUG // Check if the type pool contains two types that are the same. This - // is an indication that the hashing and comparision are wrong. It + // is an indication that the hashing and comparison are wrong. It // will cause a problem if the type pool gets resized and everything // is rehashed. for (auto& i : type_pool_) { @@ -504,9 +510,8 @@ Type* TypeManager::RebuildType(const Type& type) { } case Type::kArray: { const Array* array_ty = type.AsArray(); - const Type* ele_ty = array_ty->element_type(); rebuilt_ty = - MakeUnique(RebuildType(*ele_ty), array_ty->LengthId()); + MakeUnique(array_ty->element_type(), array_ty->length_info()); break; } case Type::kRuntimeArray: { @@ -636,15 +641,56 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) { case SpvOpTypeSampledImage: type = new SampledImage(GetType(inst.GetSingleWordInOperand(0))); break; - case SpvOpTypeArray: - type = new Array(GetType(inst.GetSingleWordInOperand(0)), - inst.GetSingleWordInOperand(1)); + case SpvOpTypeArray: { + const uint32_t length_id = inst.GetSingleWordInOperand(1); + const Instruction* length_constant_inst = id_to_constant_inst_[length_id]; + assert(length_constant_inst); + + // How will we distinguish one length value from another? + // Determine extra words required to distinguish this array length + // from another. + std::vector extra_words{Array::LengthInfo::kDefiningId}; + // If it is a specialised constant, retrieve its SpecId. + // Only OpSpecConstant has a SpecId. + uint32_t spec_id = 0u; + bool has_spec_id = false; + if (length_constant_inst->opcode() == SpvOpSpecConstant) { + context()->get_decoration_mgr()->ForEachDecoration( + length_id, SpvDecorationSpecId, + [&spec_id, &has_spec_id](const Instruction& decoration) { + assert(decoration.opcode() == SpvOpDecorate); + spec_id = decoration.GetSingleWordOperand(2u); + has_spec_id = true; + }); + } + const auto opcode = length_constant_inst->opcode(); + if (has_spec_id) { + extra_words.push_back(spec_id); + } + if ((opcode == SpvOpConstant) || (opcode == SpvOpSpecConstant)) { + // Always include the literal constant words. In the spec constant + // case, the constant might not be overridden, so it's still + // significant. + extra_words.insert(extra_words.end(), + length_constant_inst->GetOperand(2).words.begin(), + length_constant_inst->GetOperand(2).words.end()); + extra_words[0] = has_spec_id ? Array::LengthInfo::kConstantWithSpecId + : Array::LengthInfo::kConstant; + } else { + assert(extra_words[0] == Array::LengthInfo::kDefiningId); + extra_words.push_back(length_id); + } + assert(extra_words.size() >= 2); + Array::LengthInfo length_info{length_id, extra_words}; + + type = new Array(GetType(inst.GetSingleWordInOperand(0)), length_info); + if (id_to_incomplete_type_.count(inst.GetSingleWordInOperand(0))) { incomplete_types_.emplace_back(inst.result_id(), type); id_to_incomplete_type_[inst.result_id()] = type; return type; } - break; + } break; case SpvOpTypeRuntimeArray: type = new RuntimeArray(GetType(inst.GetSingleWordInOperand(0))); if (id_to_incomplete_type_.count(inst.GetSingleWordInOperand(0))) { diff --git a/3rdparty/spirv-tools/source/opt/type_manager.h b/3rdparty/spirv-tools/source/opt/type_manager.h index c44969e84..ecc7858fe 100644 --- a/3rdparty/spirv-tools/source/opt/type_manager.h +++ b/3rdparty/spirv-tools/source/opt/type_manager.h @@ -209,6 +209,8 @@ class TypeManager { IdToTypeMap id_to_incomplete_type_; // Maps ids to their type representations // for incomplete types. + + std::unordered_map id_to_constant_inst_; }; } // namespace analysis diff --git a/3rdparty/spirv-tools/source/opt/types.cpp b/3rdparty/spirv-tools/source/opt/types.cpp index cfafc7dce..e345b2dcb 100644 --- a/3rdparty/spirv-tools/source/opt/types.cpp +++ b/3rdparty/spirv-tools/source/opt/types.cpp @@ -12,14 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/types.h" + #include #include #include #include +#include #include -#include "source/opt/types.h" #include "source/util/make_unique.h" +#include "spirv/unified1/spirv.h" namespace spvtools { namespace opt { @@ -383,29 +386,42 @@ void SampledImage::GetExtraHashWords( image_type_->GetHashWords(words, seen); } -Array::Array(Type* type, uint32_t length_id) - : Type(kArray), element_type_(type), length_id_(length_id) { +Array::Array(const Type* type, const Array::LengthInfo& length_info_arg) + : Type(kArray), element_type_(type), length_info_(length_info_arg) { + assert(type != nullptr); assert(!type->AsVoid()); + // We always have a word to say which case we're in, followed + // by at least one more word. + assert(length_info_arg.words.size() >= 2); } bool Array::IsSameImpl(const Type* that, IsSameCache* seen) const { const Array* at = that->AsArray(); if (!at) return false; - return length_id_ == at->length_id_ && - element_type_->IsSameImpl(at->element_type_, seen) && - HasSameDecorations(that); + bool is_same = element_type_->IsSameImpl(at->element_type_, seen); + is_same = is_same && HasSameDecorations(that); + is_same = is_same && (length_info_.words == at->length_info_.words); + return is_same; } std::string Array::str() const { std::ostringstream oss; - oss << "[" << element_type_->str() << ", id(" << length_id_ << ")]"; + oss << "[" << element_type_->str() << ", id(" << LengthId() << "), words("; + const char* spacer = ""; + for (auto w : length_info_.words) { + oss << spacer << w; + spacer = ","; + } + oss << ")]"; return oss.str(); } void Array::GetExtraHashWords(std::vector* words, std::unordered_set* seen) const { element_type_->GetHashWords(words, seen); - words->push_back(length_id_); + // This should mirror the logic in IsSameImpl + words->insert(words->end(), length_info_.words.begin(), + length_info_.words.end()); } void Array::ReplaceElementType(const Type* type) { element_type_ = type; } @@ -540,7 +556,12 @@ bool Pointer::IsSameImpl(const Type* that, IsSameCache* seen) const { return HasSameDecorations(that); } -std::string Pointer::str() const { return pointee_type_->str() + "*"; } +std::string Pointer::str() const { + std::ostringstream os; + os << pointee_type_->str() << " " << static_cast(storage_class_) + << "*"; + return os.str(); +} void Pointer::GetExtraHashWords(std::vector* words, std::unordered_set* seen) const { @@ -609,7 +630,8 @@ void Pipe::GetExtraHashWords(std::vector* words, bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const { const ForwardPointer* fpt = that->AsForwardPointer(); if (!fpt) return false; - return target_id_ == fpt->target_id_ && + return (pointer_ && fpt->pointer_ ? *pointer_ == *fpt->pointer_ + : target_id_ == fpt->target_id_) && storage_class_ == fpt->storage_class_ && HasSameDecorations(that); } diff --git a/3rdparty/spirv-tools/source/opt/types.h b/3rdparty/spirv-tools/source/opt/types.h index fe0f39af3..e9dcc7068 100644 --- a/3rdparty/spirv-tools/source/opt/types.h +++ b/3rdparty/spirv-tools/source/opt/types.h @@ -27,6 +27,7 @@ #include #include "source/latest_version_spirv_header.h" +#include "source/opt/instruction.h" #include "spirv-tools/libspirv.h" namespace spvtools { @@ -356,12 +357,36 @@ class SampledImage : public Type { class Array : public Type { public: - Array(Type* element_type, uint32_t length_id); + // Data about the length operand, that helps us distinguish between one + // array length and another. + struct LengthInfo { + // The result id of the instruction defining the length. + const uint32_t id; + enum Case : uint32_t { + kConstant = 0, + kConstantWithSpecId = 1, + kDefiningId = 2 + }; + // Extra words used to distinshish one array length and another. + // - if OpConstant, then it's 0, then the words in the literal constant + // value. + // - if OpSpecConstant, then it's 1, then the SpecID decoration if there + // is one, followed by the words in the literal constant value. + // The spec might not be overridden, in which case we'll end up using + // the literal value. + // - Otherwise, it's an OpSpecConsant, and this 2, then the ID (again). + const std::vector words; + }; + + // Constructs an array type with given element and length. If the length + // is an OpSpecConstant, then |spec_id| should be its SpecId decoration. + Array(const Type* element_type, const LengthInfo& length_info_arg); Array(const Array&) = default; std::string str() const override; const Type* element_type() const { return element_type_; } - uint32_t LengthId() const { return length_id_; } + uint32_t LengthId() const { return length_info_.id; } + const LengthInfo& length_info() const { return length_info_; } Array* AsArray() override { return this; } const Array* AsArray() const override { return this; } @@ -375,7 +400,7 @@ class Array : public Type { bool IsSameImpl(const Type* that, IsSameCache*) const override; const Type* element_type_; - uint32_t length_id_; + const LengthInfo length_info_; }; class RuntimeArray : public Type { diff --git a/3rdparty/spirv-tools/source/spirv_fuzzer_options.cpp b/3rdparty/spirv-tools/source/spirv_fuzzer_options.cpp new file mode 100644 index 000000000..f6319ca31 --- /dev/null +++ b/3rdparty/spirv-tools/source/spirv_fuzzer_options.cpp @@ -0,0 +1,31 @@ +// 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/spirv_fuzzer_options.h" + +spv_fuzzer_options_t::spv_fuzzer_options_t() = default; + +SPIRV_TOOLS_EXPORT spv_fuzzer_options spvFuzzerOptionsCreate() { + return new spv_fuzzer_options_t(); +} + +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsDestroy(spv_fuzzer_options options) { + delete options; +} + +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetRandomSeed( + spv_fuzzer_options options, uint32_t seed) { + options->has_random_seed = true; + options->random_seed = seed; +} diff --git a/3rdparty/spirv-tools/source/spirv_fuzzer_options.h b/3rdparty/spirv-tools/source/spirv_fuzzer_options.h new file mode 100644 index 000000000..1193bfd72 --- /dev/null +++ b/3rdparty/spirv-tools/source/spirv_fuzzer_options.h @@ -0,0 +1,33 @@ +// 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_SPIRV_FUZZER_OPTIONS_H_ +#define SOURCE_SPIRV_FUZZER_OPTIONS_H_ + +#include "spirv-tools/libspirv.h" + +#include +#include + +// Manages command line options passed to the SPIR-V Fuzzer. New struct +// members may be added for any new option. +struct spv_fuzzer_options_t { + spv_fuzzer_options_t(); + + // See spvFuzzerOptionsSetRandomSeed. + bool has_random_seed = false; + uint32_t random_seed = 0; +}; + +#endif // SOURCE_SPIRV_FUZZER_OPTIONS_H_ diff --git a/3rdparty/spirv-tools/source/val/construct.cpp b/3rdparty/spirv-tools/source/val/construct.cpp index 7e106e647..156444923 100644 --- a/3rdparty/spirv-tools/source/val/construct.cpp +++ b/3rdparty/spirv-tools/source/val/construct.cpp @@ -133,6 +133,7 @@ bool Construct::IsStructuredExit(ValidationState_t& _, BasicBlock* dest) const { // - Selection: // - branch to its merge // - branch to nearest enclosing loop merge or continue + // - branch to nearest enclosing switch selection merge // - Loop: // - branch to its merge // - branch to its continue @@ -168,13 +169,17 @@ bool Construct::IsStructuredExit(ValidationState_t& _, BasicBlock* dest) const { return true; } + bool seen_switch = false; auto header = entry_block(); - auto block = header; + auto block = header->immediate_dominator(); while (block) { auto terminator = block->terminator(); auto index = terminator - &_.ordered_instructions()[0]; auto merge_inst = &_.ordered_instructions()[index - 1]; - if (merge_inst->opcode() == SpvOpLoopMerge) { + if (merge_inst->opcode() == SpvOpLoopMerge || + (header->terminator()->opcode() != SpvOpSwitch && + merge_inst->opcode() == SpvOpSelectionMerge && + terminator->opcode() == SpvOpSwitch)) { auto merge_target = merge_inst->GetOperandAs(0u); auto merge_block = merge_inst->function()->GetBlock(merge_target).first; if (merge_block->dominates(*header)) { @@ -182,10 +187,20 @@ bool Construct::IsStructuredExit(ValidationState_t& _, BasicBlock* dest) const { continue; } - auto continue_target = merge_inst->GetOperandAs(1u); - if (dest->id() == merge_target || dest->id() == continue_target) { + if ((!seen_switch || merge_inst->opcode() == SpvOpLoopMerge) && + dest->id() == merge_target) { return true; + } else if (merge_inst->opcode() == SpvOpLoopMerge) { + auto continue_target = merge_inst->GetOperandAs(1u); + if (dest->id() == continue_target) { + return true; + } } + + if (terminator->opcode() == SpvOpSwitch) seen_switch = true; + + // Hit an enclosing loop and didn't break or continue. + if (merge_inst->opcode() == SpvOpLoopMerge) return false; } block = block->immediate_dominator(); diff --git a/3rdparty/spirv-tools/source/val/construct.h b/3rdparty/spirv-tools/source/val/construct.h index 172976d6c..9476760a3 100644 --- a/3rdparty/spirv-tools/source/val/construct.h +++ b/3rdparty/spirv-tools/source/val/construct.h @@ -116,7 +116,9 @@ class Construct { // * branch to the associated merge // * branch to the merge or continue of the innermost loop containing the // selection - // Loop: + // * branch to the merge block of the innermost switch containing the + // selection + // Loop: // * branch to the associated merge or continue // Continue: // * back-edge to the associated loop header diff --git a/3rdparty/spirv-tools/source/val/function.cpp b/3rdparty/spirv-tools/source/val/function.cpp index 90893b326..af1498d2f 100644 --- a/3rdparty/spirv-tools/source/val/function.cpp +++ b/3rdparty/spirv-tools/source/val/function.cpp @@ -389,5 +389,29 @@ bool Function::IsCompatibleWithExecutionModel(SpvExecutionModel model, return return_value; } +bool Function::CheckLimitations(const ValidationState_t& _, + const Function* entry_point, + std::string* reason) const { + bool return_value = true; + std::stringstream ss_reason; + + for (const auto& is_compatible : limitations_) { + std::string message; + if (!is_compatible(_, entry_point, &message)) { + if (!reason) return false; + return_value = false; + if (!message.empty()) { + ss_reason << message << "\n"; + } + } + } + + if (!return_value && reason) { + *reason = ss_reason.str(); + } + + return return_value; +} + } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/val/function.h b/3rdparty/spirv-tools/source/val/function.h index 9cda2ff46..0d6873d8d 100644 --- a/3rdparty/spirv-tools/source/val/function.h +++ b/3rdparty/spirv-tools/source/val/function.h @@ -216,6 +216,16 @@ class Function { execution_model_limitations_.push_back(is_compatible); } + /// Registers limitation with an |is_compatible| functor. + void RegisterLimitation(std::function + is_compatible) { + limitations_.push_back(is_compatible); + } + + bool CheckLimitations(const ValidationState_t& _, const Function* entry_point, + std::string* reason) const; + /// Returns true if the given execution model passes the limitations stored in /// execution_model_limitations_. Returns false otherwise and fills optional /// |reason| parameter. @@ -376,6 +386,12 @@ class Function { std::list> execution_model_limitations_; + /// Stores limitations imposed by instructions used within the function. + /// Similar to execution_model_limitations_; + std::list> + limitations_; + /// Stores ids of all functions called from this function. std::set function_call_targets_; }; diff --git a/3rdparty/spirv-tools/source/val/validate.cpp b/3rdparty/spirv-tools/source/val/validate.cpp index 4a730da42..0840662f4 100644 --- a/3rdparty/spirv-tools/source/val/validate.cpp +++ b/3rdparty/spirv-tools/source/val/validate.cpp @@ -366,7 +366,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( // Keep these passes in the order they appear in the SPIR-V specification // sections to maintain test consistency. - // Miscellaneous + if (auto error = MiscPass(*vstate, &instruction)) return error; if (auto error = DebugPass(*vstate, &instruction)) return error; if (auto error = AnnotationPass(*vstate, &instruction)) return error; if (auto error = ExtensionPass(*vstate, &instruction)) return error; diff --git a/3rdparty/spirv-tools/source/val/validate.h b/3rdparty/spirv-tools/source/val/validate.h index fe357a2f8..aaae57014 100644 --- a/3rdparty/spirv-tools/source/val/validate.h +++ b/3rdparty/spirv-tools/source/val/validate.h @@ -199,6 +199,9 @@ spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst); /// Validates correctness of function instructions. spv_result_t FunctionPass(ValidationState_t& _, const Instruction* inst); +/// Validates correctness of miscellaneous instructions. +spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst); + /// Validates execution limitations. /// /// Verifies execution models are allowed for all functionality they contain. diff --git a/3rdparty/spirv-tools/source/val/validate_builtins.cpp b/3rdparty/spirv-tools/source/val/validate_builtins.cpp index dbe7beff5..06560655d 100644 --- a/3rdparty/spirv-tools/source/val/validate_builtins.cpp +++ b/3rdparty/spirv-tools/source/val/validate_builtins.cpp @@ -60,12 +60,22 @@ spv_result_t GetUnderlyingType(ValidationState_t& _, const Instruction& inst, uint32_t* underlying_type) { if (decoration.struct_member_index() != Decoration::kInvalidMember) { - assert(inst.opcode() == SpvOpTypeStruct); + if (inst.opcode() != SpvOpTypeStruct) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << GetIdDesc(inst) + << "Attempted to get underlying data type via member index for " + "non-struct type."; + } *underlying_type = inst.word(decoration.struct_member_index() + 2); return SPV_SUCCESS; } - assert(inst.opcode() != SpvOpTypeStruct); + if (inst.opcode() == SpvOpTypeStruct) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << GetIdDesc(inst) + << " did not find an member index to get underlying data type for " + "struct type."; + } if (spvOpcodeIsConstant(inst.opcode())) { *underlying_type = inst.type_id(); @@ -198,6 +208,8 @@ class BuiltInsValidator { // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId. spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateSMBuiltinsAtDefinition(const Decoration& decoration, + const Instruction& inst); // The following section contains functions which are called when id defined // by |referenced_inst| is @@ -322,6 +334,11 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidateSMBuiltinsAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + // Validates that |built_in_inst| is not (even indirectly) referenced from // within a function which can be called with |execution_model|. // @@ -353,6 +370,13 @@ class BuiltInsValidator { spv_result_t ValidateI32Arr( const Decoration& decoration, const Instruction& inst, const std::function& diag); + spv_result_t ValidateOptionalArrayedI32( + const Decoration& decoration, const Instruction& inst, + const std::function& diag); + spv_result_t ValidateI32Helper( + const Decoration& decoration, const Instruction& inst, + const std::function& diag, + uint32_t underlying_type); spv_result_t ValidateF32( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -533,6 +557,30 @@ spv_result_t BuiltInsValidator::ValidateI32( return error; } + return ValidateI32Helper(decoration, inst, diag, underlying_type); +} + +spv_result_t BuiltInsValidator::ValidateOptionalArrayedI32( + const Decoration& decoration, const Instruction& inst, + const std::function& diag) { + uint32_t underlying_type = 0; + if (spv_result_t error = + GetUnderlyingType(_, decoration, inst, &underlying_type)) { + return error; + } + + // Strip the array, if present. + if (_.GetIdOpcode(underlying_type) == SpvOpTypeArray) { + underlying_type = _.FindDef(underlying_type)->word(2u); + } + + return ValidateI32Helper(decoration, inst, diag, underlying_type); +} + +spv_result_t BuiltInsValidator::ValidateI32Helper( + const Decoration& decoration, const Instruction& inst, + const std::function& diag, + uint32_t underlying_type) { if (!_.IsIntScalarType(underlying_type)) { return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar."); } @@ -1716,15 +1764,31 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - if (spv_result_t error = ValidateI32( - decoration, inst, - [this, &inst](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn PrimitiveId " - "variable needs to be a 32-bit int scalar. " - << message; - })) { - return error; + // PrimitiveId can be a per-primitive variable for mesh shader stage. + // In such cases variable will have an array of 32-bit integers. + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + // This must be a 32-bit int scalar. + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn PrimitiveId " + "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } else { + if (spv_result_t error = ValidateOptionalArrayedI32( + decoration, inst, + [this, &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn PrimitiveId " + "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } } } @@ -2331,17 +2395,37 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - if (spv_result_t error = ValidateI32( - decoration, inst, - [this, &decoration, - &inst](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << "variable needs to be a 32-bit int scalar. " << message; - })) { - return error; + // This can be a per-primitive variable for mesh shader stage. + // In such cases variable will have an array of 32-bit integers. + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + // This must be a 32-bit int scalar. + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + << "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } else { + if (spv_result_t error = ValidateOptionalArrayedI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + << "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } } } @@ -2577,6 +2661,61 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, + &decoration](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidateSMBuiltinsAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for " + "variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateSMBuiltinsAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]); @@ -2671,6 +2810,12 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInLocalInvocationIndex: { return ValidateLocalInvocationIndexAtDefinition(decoration, inst); } + case SpvBuiltInWarpsPerSMNV: + case SpvBuiltInSMCountNV: + case SpvBuiltInWarpIDNV: + case SpvBuiltInSMIDNV: { + return ValidateSMBuiltinsAtDefinition(decoration, inst); + } case SpvBuiltInWorkDim: case SpvBuiltInGlobalSize: case SpvBuiltInEnqueuedWorkgroupSize: diff --git a/3rdparty/spirv-tools/source/val/validate_cfg.cpp b/3rdparty/spirv-tools/source/val/validate_cfg.cpp index b974d26f9..5a5082fb0 100644 --- a/3rdparty/spirv-tools/source/val/validate_cfg.cpp +++ b/3rdparty/spirv-tools/source/val/validate_cfg.cpp @@ -237,6 +237,10 @@ spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Merge Block " << _.getIdName(merge_id) << " must be an OpLabel"; } + if (merge_id == inst->block()->id()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Merge Block may not be the block containing the OpLoopMerge\n"; + } const auto continue_id = inst->GetOperandAs(1); const auto continue_target = _.FindDef(continue_id); diff --git a/3rdparty/spirv-tools/source/val/validate_execution_limitations.cpp b/3rdparty/spirv-tools/source/val/validate_execution_limitations.cpp index d44930770..aac1c4987 100644 --- a/3rdparty/spirv-tools/source/val/validate_execution_limitations.cpp +++ b/3rdparty/spirv-tools/source/val/validate_execution_limitations.cpp @@ -53,6 +53,17 @@ spv_result_t ValidateExecutionLimitations(ValidationState_t& _, } } } + + std::string reason; + if (!func->CheckLimitations(_, _.function(entry_id), &reason)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpEntryPoint Entry Point '" << _.getIdName(entry_id) + << "'s callgraph contains function " + << _.getIdName(inst->id()) + << ", which cannot be used with the current execution " + "modes:\n" + << reason; + } } return SPV_SUCCESS; } diff --git a/3rdparty/spirv-tools/source/val/validate_extensions.cpp b/3rdparty/spirv-tools/source/val/validate_extensions.cpp index f264c8e76..ec769db89 100644 --- a/3rdparty/spirv-tools/source/val/validate_extensions.cpp +++ b/3rdparty/spirv-tools/source/val/validate_extensions.cpp @@ -1547,11 +1547,14 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { } if (p_storage_class != SpvStorageClassUniformConstant && - p_storage_class != SpvStorageClassGeneric) { + p_storage_class != SpvStorageClassGeneric && + p_storage_class != SpvStorageClassCrossWorkgroup && + p_storage_class != SpvStorageClassWorkgroup && + p_storage_class != SpvStorageClassFunction) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " - << "expected operand P storage class to be UniformConstant or " - "Generic"; + << "expected operand P storage class to be UniformConstant, " + "Generic, CrossWorkgroup, Workgroup or Function"; } if (_.GetComponentType(result_type) != p_data_type) { @@ -1618,10 +1621,14 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { << "expected operand P to be a pointer"; } - if (p_storage_class != SpvStorageClassGeneric) { + if (p_storage_class != SpvStorageClassGeneric && + p_storage_class != SpvStorageClassCrossWorkgroup && + p_storage_class != SpvStorageClassWorkgroup && + p_storage_class != SpvStorageClassFunction) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " - << "expected operand P storage class to be Generic"; + << "expected operand P storage class to be Generic, " + "CrossWorkgroup, Workgroup or Function"; } if (_.GetComponentType(data_type) != p_data_type) { diff --git a/3rdparty/spirv-tools/source/val/validate_image.cpp b/3rdparty/spirv-tools/source/val/validate_image.cpp index ebf9ae04b..2fdb4767e 100644 --- a/3rdparty/spirv-tools/source/val/validate_image.cpp +++ b/3rdparty/spirv-tools/source/val/validate_image.cpp @@ -718,6 +718,11 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Expected Sampled Type to be a 32-bit int or float " "scalar type for Vulkan environment"; } + } else if (spvIsOpenCLEnv(_.context()->target_env)) { + if (!_.IsVoidType(info.sampled_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Sampled Type must be OpTypeVoid in the OpenCL environment."; + } } else { const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type); if (sampled_type_opcode != SpvOpTypeVoid && @@ -741,16 +746,39 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)"; } + if (spvIsOpenCLEnv(_.context()->target_env)) { + if ((info.arrayed == 1) && (info.dim != SpvDim1D) && + (info.dim != SpvDim2D)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "In the OpenCL environment, Arrayed may only be set to 1 " + << "when Dim is either 1D or 2D."; + } + } + if (info.multisampled > 1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Invalid MS " << info.multisampled << " (must be 0 or 1)"; } + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (info.multisampled != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "MS must be 0 in the OpenCL environement."; + } + } + if (info.sampled > 2) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)"; } + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (info.sampled != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Sampled must be 0 in the OpenCL environment."; + } + } + if (info.dim == SpvDimSubpassData) { if (info.sampled != 2) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -763,7 +791,15 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { } } - // Format and Access Qualifier are checked elsewhere. + // Format and Access Qualifier are also checked elsewhere. + + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (info.access_qualifier == SpvAccessQualifierMax) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "In the OpenCL environment, the optional Access Qualifier" + << " must be present."; + } + } return SPV_SUCCESS; } @@ -1078,6 +1114,17 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { } const uint32_t mask = inst->word(5); + + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (opcode == SpvOpImageSampleExplicitLod) { + if (mask & SpvImageOperandsConstOffsetMask) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "ConstOffset image operand not allowed " + << "in the OpenCL environment."; + } + } + } + if (spv_result_t result = ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) return result; @@ -1404,6 +1451,15 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { if (inst->words().size() <= 5) return SPV_SUCCESS; const uint32_t mask = inst->word(5); + + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (mask & SpvImageOperandsConstOffsetMask) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "ConstOffset image operand not allowed " + << "in the OpenCL environment."; + } + } + if (spv_result_t result = ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) return result; @@ -1481,7 +1537,15 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { } } - if (inst->words().size() <= 4) return SPV_SUCCESS; + if (inst->words().size() <= 4) { + return SPV_SUCCESS; + } else { + if (spvIsOpenCLEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Optional Image Operands are not allowed in the OpenCL " + << "environment."; + } + } const uint32_t mask = inst->word(4); if (spv_result_t result = diff --git a/3rdparty/spirv-tools/source/val/validate_misc.cpp b/3rdparty/spirv-tools/source/val/validate_misc.cpp new file mode 100644 index 000000000..dcc65f37f --- /dev/null +++ b/3rdparty/spirv-tools/source/val/validate_misc.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2018 Google LLC. +// Copyright (c) 2019 NVIDIA Corporation +// +// 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/val/validate.h" + +#include "source/opcode.h" +#include "source/spirv_target_env.h" +#include "source/val/instruction.h" +#include "source/val/validation_state.h" + +namespace spvtools { +namespace val { + +spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst) { + switch (inst->opcode()) { + case SpvOpBeginInvocationInterlockEXT: + case SpvOpEndInvocationInterlockEXT: + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation( + SpvExecutionModelFragment, + "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT " + "require Fragment execution model"); + + _.function(inst->function()->id()) + ->RegisterLimitation([](const ValidationState_t& state, + const Function* entry_point, + std::string* message) { + const auto* execution_modes = + state.GetExecutionModes(entry_point->id()); + + auto find_interlock = [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModePixelInterlockOrderedEXT: + case SpvExecutionModePixelInterlockUnorderedEXT: + case SpvExecutionModeSampleInterlockOrderedEXT: + case SpvExecutionModeSampleInterlockUnorderedEXT: + case SpvExecutionModeShadingRateInterlockOrderedEXT: + case SpvExecutionModeShadingRateInterlockUnorderedEXT: + return true; + default: + return false; + } + }; + + bool found = false; + if (execution_modes) { + auto i = std::find_if(execution_modes->begin(), + execution_modes->end(), find_interlock); + found = (i != execution_modes->end()); + } + + if (!found) { + *message = + "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT " + "require a fragment shader interlock execution mode."; + return false; + } + return true; + }); + break; + default: + break; + } + + return SPV_SUCCESS; +} + +} // namespace val +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp b/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp index 943629d11..cbcf11a3f 100644 --- a/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp +++ b/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp @@ -90,6 +90,26 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { "one of DepthGreater, DepthLess or DepthUnchanged " "execution modes."; } + if (execution_modes && + 1 < std::count_if( + execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModePixelInterlockOrderedEXT: + case SpvExecutionModePixelInterlockUnorderedEXT: + case SpvExecutionModeSampleInterlockOrderedEXT: + case SpvExecutionModeSampleInterlockUnorderedEXT: + case SpvExecutionModeShadingRateInterlockOrderedEXT: + case SpvExecutionModeShadingRateInterlockUnorderedEXT: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Fragment execution model entry points can specify at most " + "one fragment shader interlock execution mode."; + } break; case SpvExecutionModelTessellationControl: case SpvExecutionModelTessellationEvaluation: @@ -376,6 +396,12 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, case SpvExecutionModeDepthGreater: case SpvExecutionModeDepthLess: case SpvExecutionModeDepthUnchanged: + case SpvExecutionModePixelInterlockOrderedEXT: + case SpvExecutionModePixelInterlockUnorderedEXT: + case SpvExecutionModeSampleInterlockOrderedEXT: + case SpvExecutionModeSampleInterlockUnorderedEXT: + case SpvExecutionModeShadingRateInterlockOrderedEXT: + case SpvExecutionModeShadingRateInterlockUnorderedEXT: if (!std::all_of(models->begin(), models->end(), [](const SpvExecutionModel& model) { return model == SpvExecutionModelFragment; diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index 745c82bb0..394f72867 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/3rdparty/spirv-tools/source/val/validation_state.cpp @@ -691,6 +691,12 @@ uint32_t ValidationState_t::GetBitWidth(uint32_t id) const { return 0; } +bool ValidationState_t::IsVoidType(uint32_t id) const { + const Instruction* inst = FindDef(id); + assert(inst); + return inst->opcode() == SpvOpTypeVoid; +} + bool ValidationState_t::IsFloatScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); assert(inst); diff --git a/3rdparty/spirv-tools/source/val/validation_state.h b/3rdparty/spirv-tools/source/val/validation_state.h index 9b0a58604..c34c1ec95 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.h +++ b/3rdparty/spirv-tools/source/val/validation_state.h @@ -548,6 +548,7 @@ class ValidationState_t { // Returns true iff |id| is a type corresponding to the name of the function. // Only works for types not for objects. + bool IsVoidType(uint32_t id) const; bool IsFloatScalarType(uint32_t id) const; bool IsFloatVectorType(uint32_t id) const; bool IsFloatScalarOrVectorType(uint32_t id) const; diff --git a/3rdparty/spirv-tools/test/CMakeLists.txt b/3rdparty/spirv-tools/test/CMakeLists.txt index bf0792cfc..3dca430c8 100644 --- a/3rdparty/spirv-tools/test/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/CMakeLists.txt @@ -183,33 +183,10 @@ add_spvtools_unittest( endif() -add_spvtools_unittest( - TARGET bit_stream - SRCS bit_stream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.h - LIBS ${SPIRV_TOOLS}) - -add_spvtools_unittest( - TARGET huffman_codec - SRCS huffman_codec.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.h - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/huffman_codec.h - LIBS ${SPIRV_TOOLS}) - -add_spvtools_unittest( - TARGET move_to_front - SRCS move_to_front_test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/move_to_front.h - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/move_to_front.cpp - LIBS ${SPIRV_TOOLS}) - -add_subdirectory(comp) add_subdirectory(link) add_subdirectory(opt) add_subdirectory(reduce) -add_subdirectory(stats) +add_subdirectory(fuzz) add_subdirectory(tools) add_subdirectory(util) add_subdirectory(val) diff --git a/3rdparty/spirv-tools/test/bit_stream.cpp b/3rdparty/spirv-tools/test/bit_stream.cpp deleted file mode 100644 index f02faf3c6..000000000 --- a/3rdparty/spirv-tools/test/bit_stream.cpp +++ /dev/null @@ -1,1025 +0,0 @@ -// Copyright (c) 2017 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 -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/bit_stream.h" - -namespace spvtools { -namespace comp { -namespace { - -// Converts |buffer| to a stream of '0' and '1'. -template -std::string BufferToStream(const std::vector& buffer) { - std::stringstream ss; - for (auto it = buffer.begin(); it != buffer.end(); ++it) { - std::string str = std::bitset(*it).to_string(); - // Strings generated by std::bitset::to_string are read right to left. - // Reversing to left to right. - std::reverse(str.begin(), str.end()); - ss << str; - } - return ss.str(); -} - -// Converts a left-to-right input string of '0' and '1' to a buffer of |T| -// words. -template -std::vector StreamToBuffer(std::string str) { - // The input string is left-to-right, the input argument of std::bitset needs - // to right-to-left. Instead of reversing tokens, reverse the entire string - // and iterate tokens from end to begin. - std::reverse(str.begin(), str.end()); - const int word_size = static_cast(sizeof(T) * 8); - const int str_length = static_cast(str.length()); - std::vector buffer; - buffer.reserve(NumBitsToNumWords(str.length())); - for (int index = str_length - word_size; index >= 0; index -= word_size) { - buffer.push_back(static_cast( - std::bitset(str, index, word_size).to_ullong())); - } - const size_t suffix_length = str.length() % word_size; - if (suffix_length != 0) { - buffer.push_back(static_cast( - std::bitset(str, 0, suffix_length).to_ullong())); - } - return buffer; -} - -// Adds '0' chars at the end of the string until the size is a multiple of N. -template -std::string PadToWord(std::string&& str) { - const size_t tail_length = str.size() % N; - if (tail_length != 0) str += std::string(N - tail_length, '0'); - return std::move(str); -} - -// Adds '0' chars at the end of the string until the size is a multiple of N. -template -std::string PadToWord(const std::string& str) { - return PadToWord(std::string(str)); -} - -// Converts a left-to-right stream of bits to std::bitset. -template -std::bitset StreamToBitset(std::string str) { - std::reverse(str.begin(), str.end()); - return std::bitset(str); -} - -// Converts a left-to-right stream of bits to uint64. -uint64_t StreamToBits(std::string str) { - std::reverse(str.begin(), str.end()); - return std::bitset<64>(str).to_ullong(); -} - -// A simple and inefficient implementatition of BitWriterInterface, -// using std::stringstream. Intended for tests only. -class BitWriterStringStream : public BitWriterInterface { - public: - void WriteBits(uint64_t bits, size_t num_bits) override { - assert(num_bits <= 64); - ss_ << BitsToStream(bits, num_bits); - } - - size_t GetNumBits() const override { return ss_.str().size(); } - - std::vector GetDataCopy() const override { - return StreamToBuffer(ss_.str()); - } - - std::string GetStreamRaw() const { return ss_.str(); } - - private: - std::stringstream ss_; -}; - -// A simple and inefficient implementatition of BitReaderInterface. -// Intended for tests only. -class BitReaderFromString : public BitReaderInterface { - public: - explicit BitReaderFromString(std::string&& str) - : str_(std::move(str)), pos_(0) {} - - explicit BitReaderFromString(const std::vector& buffer) - : str_(BufferToStream(buffer)), pos_(0) {} - - explicit BitReaderFromString(const std::vector& buffer) - : str_(PadToWord<64>(BufferToStream(buffer))), pos_(0) {} - - size_t ReadBits(uint64_t* bits, size_t num_bits) override { - if (ReachedEnd()) return 0; - std::string sub = str_.substr(pos_, num_bits); - *bits = StreamToBits(sub); - pos_ += sub.length(); - return sub.length(); - } - - size_t GetNumReadBits() const override { return pos_; } - - bool ReachedEnd() const override { return pos_ >= str_.length(); } - - private: - std::string str_; - size_t pos_; -}; - -TEST(NumBitsToNumWords, Word8) { - EXPECT_EQ(0u, NumBitsToNumWords<8>(0)); - EXPECT_EQ(1u, NumBitsToNumWords<8>(1)); - EXPECT_EQ(1u, NumBitsToNumWords<8>(7)); - EXPECT_EQ(1u, NumBitsToNumWords<8>(8)); - EXPECT_EQ(2u, NumBitsToNumWords<8>(9)); - EXPECT_EQ(2u, NumBitsToNumWords<8>(16)); - EXPECT_EQ(3u, NumBitsToNumWords<8>(17)); - EXPECT_EQ(3u, NumBitsToNumWords<8>(23)); - EXPECT_EQ(3u, NumBitsToNumWords<8>(24)); - EXPECT_EQ(4u, NumBitsToNumWords<8>(25)); -} - -TEST(NumBitsToNumWords, Word64) { - EXPECT_EQ(0u, NumBitsToNumWords<64>(0)); - EXPECT_EQ(1u, NumBitsToNumWords<64>(1)); - EXPECT_EQ(1u, NumBitsToNumWords<64>(64)); - EXPECT_EQ(2u, NumBitsToNumWords<64>(65)); - EXPECT_EQ(2u, NumBitsToNumWords<64>(128)); - EXPECT_EQ(3u, NumBitsToNumWords<64>(129)); -} - -TEST(ZigZagCoding, Encode0) { - EXPECT_EQ(0u, EncodeZigZag(0, 0)); - EXPECT_EQ(1u, EncodeZigZag(-1, 0)); - EXPECT_EQ(2u, EncodeZigZag(1, 0)); - EXPECT_EQ(3u, EncodeZigZag(-2, 0)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::max(), 0)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 0)); -} - -TEST(ZigZagCoding, Decode0) { - EXPECT_EQ(0, DecodeZigZag(0, 0)); - EXPECT_EQ(-1, DecodeZigZag(1, 0)); - EXPECT_EQ(1, DecodeZigZag(2, 0)); - EXPECT_EQ(-2, DecodeZigZag(3, 0)); - EXPECT_EQ(std::numeric_limits::min(), - DecodeZigZag(std::numeric_limits::max(), 0)); - EXPECT_EQ(std::numeric_limits::max(), - DecodeZigZag(std::numeric_limits::max() - 1, 0)); -} - -TEST(ZigZagCoding, Encode1) { - EXPECT_EQ(0u, EncodeZigZag(0, 1)); - EXPECT_EQ(1u, EncodeZigZag(1, 1)); - EXPECT_EQ(2u, EncodeZigZag(-1, 1)); - EXPECT_EQ(3u, EncodeZigZag(-2, 1)); - EXPECT_EQ(4u, EncodeZigZag(2, 1)); - EXPECT_EQ(5u, EncodeZigZag(3, 1)); - EXPECT_EQ(6u, EncodeZigZag(-3, 1)); - EXPECT_EQ(7u, EncodeZigZag(-4, 1)); - EXPECT_EQ(std::numeric_limits::max() - 2, - EncodeZigZag(std::numeric_limits::max(), 1)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::min() + 1, 1)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 1)); -} - -TEST(ZigZagCoding, Decode1) { - EXPECT_EQ(0, DecodeZigZag(0, 1)); - EXPECT_EQ(1, DecodeZigZag(1, 1)); - EXPECT_EQ(-1, DecodeZigZag(2, 1)); - EXPECT_EQ(-2, DecodeZigZag(3, 1)); - EXPECT_EQ(2, DecodeZigZag(4, 1)); - EXPECT_EQ(3, DecodeZigZag(5, 1)); - EXPECT_EQ(-3, DecodeZigZag(6, 1)); - EXPECT_EQ(-4, DecodeZigZag(7, 1)); - EXPECT_EQ(std::numeric_limits::min(), - DecodeZigZag(std::numeric_limits::max(), 1)); - EXPECT_EQ(std::numeric_limits::min() + 1, - DecodeZigZag(std::numeric_limits::max() - 1, 1)); - EXPECT_EQ(std::numeric_limits::max(), - DecodeZigZag(std::numeric_limits::max() - 2, 1)); -} - -TEST(ZigZagCoding, Encode2) { - EXPECT_EQ(0u, EncodeZigZag(0, 2)); - EXPECT_EQ(1u, EncodeZigZag(1, 2)); - EXPECT_EQ(2u, EncodeZigZag(2, 2)); - EXPECT_EQ(3u, EncodeZigZag(3, 2)); - EXPECT_EQ(4u, EncodeZigZag(-1, 2)); - EXPECT_EQ(5u, EncodeZigZag(-2, 2)); - EXPECT_EQ(6u, EncodeZigZag(-3, 2)); - EXPECT_EQ(7u, EncodeZigZag(-4, 2)); - EXPECT_EQ(8u, EncodeZigZag(4, 2)); - EXPECT_EQ(9u, EncodeZigZag(5, 2)); - EXPECT_EQ(10u, EncodeZigZag(6, 2)); - EXPECT_EQ(11u, EncodeZigZag(7, 2)); - EXPECT_EQ(12u, EncodeZigZag(-5, 2)); - EXPECT_EQ(13u, EncodeZigZag(-6, 2)); - EXPECT_EQ(14u, EncodeZigZag(-7, 2)); - EXPECT_EQ(15u, EncodeZigZag(-8, 2)); - EXPECT_EQ(std::numeric_limits::max() - 4, - EncodeZigZag(std::numeric_limits::max(), 2)); - EXPECT_EQ(std::numeric_limits::max() - 3, - EncodeZigZag(std::numeric_limits::min() + 3, 2)); - EXPECT_EQ(std::numeric_limits::max() - 2, - EncodeZigZag(std::numeric_limits::min() + 2, 2)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::min() + 1, 2)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 2)); -} - -TEST(ZigZagCoding, Decode2) { - EXPECT_EQ(0, DecodeZigZag(0, 2)); - EXPECT_EQ(1, DecodeZigZag(1, 2)); - EXPECT_EQ(2, DecodeZigZag(2, 2)); - EXPECT_EQ(3, DecodeZigZag(3, 2)); - EXPECT_EQ(-1, DecodeZigZag(4, 2)); - EXPECT_EQ(-2, DecodeZigZag(5, 2)); - EXPECT_EQ(-3, DecodeZigZag(6, 2)); - EXPECT_EQ(-4, DecodeZigZag(7, 2)); - EXPECT_EQ(4, DecodeZigZag(8, 2)); - EXPECT_EQ(5, DecodeZigZag(9, 2)); - EXPECT_EQ(6, DecodeZigZag(10, 2)); - EXPECT_EQ(7, DecodeZigZag(11, 2)); - EXPECT_EQ(-5, DecodeZigZag(12, 2)); - EXPECT_EQ(-6, DecodeZigZag(13, 2)); - EXPECT_EQ(-7, DecodeZigZag(14, 2)); - EXPECT_EQ(-8, DecodeZigZag(15, 2)); - EXPECT_EQ(std::numeric_limits::min(), - DecodeZigZag(std::numeric_limits::max(), 2)); - EXPECT_EQ(std::numeric_limits::min() + 1, - DecodeZigZag(std::numeric_limits::max() - 1, 2)); - EXPECT_EQ(std::numeric_limits::min() + 2, - DecodeZigZag(std::numeric_limits::max() - 2, 2)); - EXPECT_EQ(std::numeric_limits::min() + 3, - DecodeZigZag(std::numeric_limits::max() - 3, 2)); - EXPECT_EQ(std::numeric_limits::max(), - DecodeZigZag(std::numeric_limits::max() - 4, 2)); -} - -TEST(ZigZagCoding, Encode63) { - EXPECT_EQ(0u, EncodeZigZag(0, 63)); - - for (int64_t i = 0; i < 0xFFFFFFFF; i += 1234567) { - const int64_t positive_val = GetLowerBits(i * i * i + i * i, 63) | 1UL; - ASSERT_EQ(static_cast(positive_val), - EncodeZigZag(positive_val, 63)); - ASSERT_EQ((1ULL << 63) - 1 + positive_val, EncodeZigZag(-positive_val, 63)); - } - - EXPECT_EQ((1ULL << 63) - 1, - EncodeZigZag(std::numeric_limits::max(), 63)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::min() + 1, 63)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 63)); -} - -TEST(BufToStream, UInt8_Empty) { - const std::string expected_bits = ""; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_TRUE(buffer.empty()); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt8_OneWord) { - const std::string expected_bits = "00101100"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({static_cast( - StreamToBitset<8>(expected_bits).to_ulong())}), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt8_MultipleWords) { - const std::string expected_bits = - "00100010" - "01101010" - "01111101" - "00100010"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({ - static_cast(StreamToBitset<8>("00100010").to_ulong()), - static_cast(StreamToBitset<8>("01101010").to_ulong()), - static_cast(StreamToBitset<8>("01111101").to_ulong()), - static_cast(StreamToBitset<8>("00100010").to_ulong()), - }), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt64_Empty) { - const std::string expected_bits = ""; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_TRUE(buffer.empty()); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt64_OneWord) { - const std::string expected_bits = - "0001000111101110011001101010101000100010110011000100010010001000"; - std::vector buffer = StreamToBuffer(expected_bits); - ASSERT_EQ(1u, buffer.size()); - EXPECT_EQ(0x1122334455667788u, buffer[0]); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt64_Unaligned) { - const std::string expected_bits = - "0010001001101010011111010010001001001010000111110010010010010101" - "0010001001101010011111111111111111111111"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({ - StreamToBits(expected_bits.substr(0, 64)), - StreamToBits(expected_bits.substr(64, 64)), - }), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(PadToWord<64>(expected_bits), result_bits); -} - -TEST(BufToStream, UInt64_MultipleWords) { - const std::string expected_bits = - "0010001001101010011111010010001001001010000111110010010010010101" - "0010001001101010011111111111111111111111000111110010010010010111" - "0000000000000000000000000000000000000000000000000010010011111111"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({ - StreamToBits(expected_bits.substr(0, 64)), - StreamToBits(expected_bits.substr(64, 64)), - StreamToBits(expected_bits.substr(128, 64)), - }), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(PadToWord, Test) { - EXPECT_EQ("10100000", PadToWord<8>("101")); - EXPECT_EQ( - "10100000" - "00000000", - PadToWord<16>("101")); - EXPECT_EQ( - "10100000" - "00000000" - "00000000" - "00000000", - PadToWord<32>("101")); - EXPECT_EQ( - "10100000" - "00000000" - "00000000" - "00000000" - "00000000" - "00000000" - "00000000" - "00000000", - PadToWord<64>("101")); -} - -TEST(BitWriterStringStream, Empty) { - BitWriterStringStream writer; - EXPECT_EQ(0u, writer.GetNumBits()); - EXPECT_EQ(0u, writer.GetDataSizeBytes()); - EXPECT_EQ("", writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteBits) { - BitWriterStringStream writer; - const uint64_t bits1 = 0x1 | 0x2 | 0x10; - writer.WriteBits(bits1, 5); - EXPECT_EQ(5u, writer.GetNumBits()); - EXPECT_EQ(1u, writer.GetDataSizeBytes()); - EXPECT_EQ("11001", writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteUnencodedU8) { - BitWriterStringStream writer; - const uint8_t bits = 127; - writer.WriteUnencoded(bits); - EXPECT_EQ(8u, writer.GetNumBits()); - EXPECT_EQ("11111110", writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteUnencodedS64) { - BitWriterStringStream writer; - const int64_t bits = std::numeric_limits::min() + 7; - writer.WriteUnencoded(bits); - EXPECT_EQ(64u, writer.GetNumBits()); - EXPECT_EQ("1110000000000000000000000000000000000000000000000000000000000001", - writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteMultiple) { - BitWriterStringStream writer; - - std::string expected_result; - - const uint64_t b2_val = 0x4 | 0x2 | 0x40; - const std::string bits2 = BitsToStream(b2_val, 8); - writer.WriteBits(b2_val, 8); - - const uint64_t val = 0x1 | 0x2 | 0x10; - const std::string bits3 = BitsToStream(val, 8); - writer.WriteBits(val, 8); - - const std::string expected = bits2 + bits3; - - EXPECT_EQ(expected.length(), writer.GetNumBits()); - EXPECT_EQ(2u, writer.GetDataSizeBytes()); - EXPECT_EQ(expected, writer.GetStreamRaw()); - - EXPECT_EQ(PadToWord<8>(expected), BufferToStream(writer.GetDataCopy())); -} - -TEST(BitWriterWord64, Empty) { - BitWriterWord64 writer; - EXPECT_EQ(0u, writer.GetNumBits()); - EXPECT_EQ(0u, writer.GetDataSizeBytes()); -} - -TEST(BitWriterWord64, WriteBits) { - BitWriterWord64 writer; - const uint64_t bits1 = 0x1 | 0x2 | 0x10; - writer.WriteBits(bits1, 5); - writer.WriteBits(bits1, 5); - writer.WriteBits(bits1, 5); - EXPECT_EQ(15u, writer.GetNumBits()); - EXPECT_EQ(2u, writer.GetDataSizeBytes()); -} - -TEST(BitWriterWord64, WriteZeroBits) { - BitWriterWord64 writer; - writer.WriteBits(0, 0); - writer.WriteBits(1, 0); - EXPECT_EQ(0u, writer.GetNumBits()); - writer.WriteBits(1, 1); - writer.WriteBits(0, 0); - writer.WriteBits(0, 63); - EXPECT_EQ(64u, writer.GetNumBits()); - writer.WriteBits(0, 0); - writer.WriteBits(7, 3); - writer.WriteBits(0, 0); -} - -TEST(BitWriterWord64, ComparisonTestWriteLotsOfBits) { - BitWriterStringStream writer1; - BitWriterWord64 writer2(16384); - - for (uint64_t i = 0; i < 65000; i += 25) { - writer1.WriteBits(i, 16); - writer2.WriteBits(i, 16); - ASSERT_EQ(writer1.GetNumBits(), writer2.GetNumBits()); - } -} - -TEST(GetLowerBits, Test) { - EXPECT_EQ(0u, GetLowerBits(255, 0)); - EXPECT_EQ(1u, GetLowerBits(255, 1)); - EXPECT_EQ(3u, GetLowerBits(255, 2)); - EXPECT_EQ(7u, GetLowerBits(255, 3)); - EXPECT_EQ(15u, GetLowerBits(255, 4)); - EXPECT_EQ(31u, GetLowerBits(255, 5)); - EXPECT_EQ(63u, GetLowerBits(255, 6)); - EXPECT_EQ(127u, GetLowerBits(255, 7)); - EXPECT_EQ(255u, GetLowerBits(255, 8)); - EXPECT_EQ(0xFFu, GetLowerBits(0xFFFFFFFF, 8)); - EXPECT_EQ(0xFFFFu, GetLowerBits(0xFFFFFFFF, 16)); - EXPECT_EQ(0xFFFFFFu, GetLowerBits(0xFFFFFFFF, 24)); - EXPECT_EQ(0xFFFFFFu, GetLowerBits(0xFFFFFFFFFFFF, 24)); - EXPECT_EQ(0xFFFFFFFFFFFFFFFFu, - GetLowerBits(0xFFFFFFFFFFFFFFFFu, 64)); - EXPECT_EQ(StreamToBits("1010001110"), - GetLowerBits(StreamToBits("1010001110111101111111"), 10)); -} - -TEST(BitReaderFromString, FromU8) { - std::vector buffer = { - 0xAA, - 0xBB, - 0xCC, - 0xDD, - }; - - const std::string total_stream = - "01010101" - "11011101" - "00110011" - "10111011"; - - BitReaderFromString reader(buffer); - - uint64_t bits = 0; - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(PadToWord<64>("01"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("01010111011101001100"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("11101110110000000000"), BitsToStream(bits)); - EXPECT_EQ(22u, reader.ReadBits(&bits, 30)); - EXPECT_EQ(PadToWord<64>("0000000000000000000000"), BitsToStream(bits)); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderFromString, FromU64) { - std::vector buffer = { - 0xAAAAAAAAAAAAAAAA, - 0xBBBBBBBBBBBBBBBB, - 0xCCCCCCCCCCCCCCCC, - 0xDDDDDDDDDDDDDDDD, - }; - - const std::string total_stream = - "0101010101010101010101010101010101010101010101010101010101010101" - "1101110111011101110111011101110111011101110111011101110111011101" - "0011001100110011001100110011001100110011001100110011001100110011" - "1011101110111011101110111011101110111011101110111011101110111011"; - - BitReaderFromString reader(buffer); - - uint64_t bits = 0; - size_t pos = 0; - size_t to_read = 5; - while (reader.ReadBits(&bits, to_read) > 0) { - EXPECT_EQ(BitsToStream(bits), - PadToWord<64>(total_stream.substr(pos, to_read))); - pos += to_read; - to_read = (to_read + 35) % 64 + 1; - } - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, ReadBitsSingleByte) { - BitReaderWord64 reader(std::vector({uint8_t(0xF0)})); - EXPECT_FALSE(reader.ReachedEnd()); - - uint64_t bits = 0; - EXPECT_EQ(1u, reader.ReadBits(&bits, 1)); - EXPECT_EQ(0u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(0u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(2u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(3u, bits); - EXPECT_FALSE(reader.OnlyZeroesLeft()); - EXPECT_FALSE(reader.ReachedEnd()); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(1u, bits); - EXPECT_TRUE(reader.OnlyZeroesLeft()); - EXPECT_FALSE(reader.ReachedEnd()); - EXPECT_EQ(55u, reader.ReadBits(&bits, 64)); - EXPECT_EQ(0u, bits); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, ReadBitsTwoWords) { - std::vector buffer = {0x0000000000000001, 0x0000000000FFFFFF}; - - BitReaderWord64 reader(std::move(buffer)); - - uint64_t bits = 0; - EXPECT_EQ(1u, reader.ReadBits(&bits, 1)); - EXPECT_EQ(1u, bits); - EXPECT_EQ(62u, reader.ReadBits(&bits, 62)); - EXPECT_EQ(0u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(2u, bits); - EXPECT_EQ(3u, reader.ReadBits(&bits, 3)); - EXPECT_EQ(7u, bits); - EXPECT_FALSE(reader.OnlyZeroesLeft()); - EXPECT_EQ(32u, reader.ReadBits(&bits, 32)); - EXPECT_EQ(0xFFFFFu, bits); - EXPECT_TRUE(reader.OnlyZeroesLeft()); - EXPECT_FALSE(reader.ReachedEnd()); - EXPECT_EQ(28u, reader.ReadBits(&bits, 32)); - EXPECT_EQ(0u, bits); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderFromString, ReadUnencodedU8) { - BitReaderFromString reader("11111110"); - uint8_t val = 0; - ASSERT_TRUE(reader.ReadUnencoded(&val)); - EXPECT_EQ(8u, reader.GetNumReadBits()); - EXPECT_EQ(127, val); -} - -TEST(BitReaderFromString, ReadUnencodedU16Fail) { - BitReaderFromString reader("11111110"); - uint16_t val = 0; - ASSERT_FALSE(reader.ReadUnencoded(&val)); -} - -TEST(BitReaderFromString, ReadUnencodedS64) { - BitReaderFromString reader( - "1110000000000000000000000000000000000000000000000000000000000001"); - int64_t val = 0; - ASSERT_TRUE(reader.ReadUnencoded(&val)); - EXPECT_EQ(64u, reader.GetNumReadBits()); - EXPECT_EQ(std::numeric_limits::min() + 7, val); -} - -TEST(BitReaderWord64, FromU8) { - std::vector buffer = { - 0xAA, - 0xBB, - 0xCC, - 0xDD, - }; - - BitReaderWord64 reader(std::move(buffer)); - - uint64_t bits = 0; - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(PadToWord<64>("01"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("01010111011101001100"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("11101110110000000000"), BitsToStream(bits)); - EXPECT_EQ(22u, reader.ReadBits(&bits, 30)); - EXPECT_EQ(PadToWord<64>("0000000000000000000000"), BitsToStream(bits)); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, FromU64) { - std::vector buffer = { - 0xAAAAAAAAAAAAAAAA, - 0xBBBBBBBBBBBBBBBB, - 0xCCCCCCCCCCCCCCCC, - 0xDDDDDDDDDDDDDDDD, - }; - - const std::string total_stream = - "0101010101010101010101010101010101010101010101010101010101010101" - "1101110111011101110111011101110111011101110111011101110111011101" - "0011001100110011001100110011001100110011001100110011001100110011" - "1011101110111011101110111011101110111011101110111011101110111011"; - - BitReaderWord64 reader(std::move(buffer)); - - uint64_t bits = 0; - size_t pos = 0; - size_t to_read = 5; - while (reader.ReadBits(&bits, to_read) > 0) { - EXPECT_EQ(BitsToStream(bits), - PadToWord<64>(total_stream.substr(pos, to_read))); - pos += to_read; - to_read = (to_read + 35) % 64 + 1; - } - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, ComparisonLotsOfU8) { - std::vector buffer; - for (uint32_t i = 0; i < 10003; ++i) { - buffer.push_back(static_cast(i % 255)); - } - - BitReaderFromString reader1(buffer); - BitReaderWord64 reader2(std::move(buffer)); - - uint64_t bits1 = 0, bits2 = 0; - size_t to_read = 5; - while (reader1.ReadBits(&bits1, to_read) > 0) { - reader2.ReadBits(&bits2, to_read); - EXPECT_EQ(bits1, bits2); - to_read = (to_read + 35) % 64 + 1; - } - - EXPECT_EQ(0u, reader2.ReadBits(&bits2, 1)); -} - -TEST(BitReaderWord64, ComparisonLotsOfU64) { - std::vector buffer; - for (uint64_t i = 0; i < 1000; ++i) { - buffer.push_back(i); - } - - BitReaderFromString reader1(buffer); - BitReaderWord64 reader2(std::move(buffer)); - - uint64_t bits1 = 0, bits2 = 0; - size_t to_read = 5; - while (reader1.ReadBits(&bits1, to_read) > 0) { - reader2.ReadBits(&bits2, to_read); - EXPECT_EQ(bits1, bits2); - to_read = (to_read + 35) % 64 + 1; - } - - EXPECT_EQ(0u, reader2.ReadBits(&bits2, 1)); -} - -TEST(ReadWriteWord64, ReadWriteLotsOfBits) { - BitWriterWord64 writer(16384); - for (uint64_t i = 0; i < 65000; i += 25) { - const uint64_t num_bits = i % 64 + 1; - const uint64_t bits = i >> (64 - num_bits); - writer.WriteBits(bits, size_t(num_bits)); - } - - BitReaderWord64 reader(writer.GetDataCopy()); - for (uint64_t i = 0; i < 65000; i += 25) { - const uint64_t num_bits = i % 64 + 1; - const uint64_t expected_bits = i >> (64 - num_bits); - uint64_t bits = 0; - reader.ReadBits(&bits, size_t(num_bits)); - EXPECT_EQ(expected_bits, bits); - } - - EXPECT_TRUE(reader.OnlyZeroesLeft()); -} - -TEST(VariableWidthWrite, Write0U) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(0, 2); - EXPECT_EQ("000", writer.GetStreamRaw()); - writer.WriteVariableWidthU32(0, 2); - EXPECT_EQ( - "000" - "000", - writer.GetStreamRaw()); - writer.WriteVariableWidthU16(0, 2); - EXPECT_EQ( - "000" - "000" - "000", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, WriteSmallUnsigned) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(1, 2); - EXPECT_EQ("100", writer.GetStreamRaw()); - writer.WriteVariableWidthU32(2, 2); - EXPECT_EQ( - "100" - "010", - writer.GetStreamRaw()); - writer.WriteVariableWidthU16(3, 2); - EXPECT_EQ( - "100" - "010" - "110", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, WriteSmallSigned) { - BitWriterStringStream writer; - writer.WriteVariableWidthS64(1, 2, 0); - EXPECT_EQ("010", writer.GetStreamRaw()); - writer.WriteVariableWidthS64(-1, 2, 0); - EXPECT_EQ( - "010" - "100", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U64Val127ChunkLength7) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(127, 7); - EXPECT_EQ( - "1111111" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U32Val255ChunkLength7) { - BitWriterStringStream writer; - writer.WriteVariableWidthU32(255, 7); - EXPECT_EQ( - "1111111" - "1" - "1000000" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U16Val2ChunkLength4) { - BitWriterStringStream writer; - writer.WriteVariableWidthU16(2, 4); - EXPECT_EQ( - "0100" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U64ValAAAAChunkLength2) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(0xAAAA, 2); - EXPECT_EQ( - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthRead, U64Val127ChunkLength7) { - BitReaderFromString reader( - "1111111" - "0"); - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 7)); - EXPECT_EQ(127u, val); -} - -TEST(VariableWidthRead, U32Val255ChunkLength7) { - BitReaderFromString reader( - "1111111" - "1" - "1000000" - "0"); - uint32_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU32(&val, 7)); - EXPECT_EQ(255u, val); -} - -TEST(VariableWidthRead, U16Val2ChunkLength4) { - BitReaderFromString reader( - "0100" - "0"); - uint16_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU16(&val, 4)); - EXPECT_EQ(2u, val); -} - -TEST(VariableWidthRead, U64ValAAAAChunkLength2) { - BitReaderFromString reader( - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "0"); - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 2)); - EXPECT_EQ(0xAAAAu, val); -} - -TEST(VariableWidthRead, FailTooShort) { - BitReaderFromString reader("00000001100000"); - uint64_t val = 0; - ASSERT_FALSE(reader.ReadVariableWidthU64(&val, 7)); -} - -TEST(VariableWidthWriteRead, SingleWriteReadU64) { - for (uint64_t i = 0; i < 1000000; i += 1234) { - const uint64_t val = i * i * i; - const size_t chunk_length = size_t(i % 16 + 1); - - BitWriterWord64 writer; - writer.WriteVariableWidthU64(val, chunk_length); - - BitReaderWord64 reader(writer.GetDataCopy()); - uint64_t read_val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&read_val, chunk_length)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SingleWriteReadS64) { - for (int64_t i = 0; i < 1000000; i += 4321) { - const int64_t val = i * i * (i % 2 ? -i : i); - const size_t chunk_length = size_t(i % 16 + 1); - const size_t zigzag_exponent = size_t(i % 13); - - BitWriterWord64 writer; - writer.WriteVariableWidthS64(val, chunk_length, zigzag_exponent); - - BitReaderWord64 reader(writer.GetDataCopy()); - int64_t read_val = 0; - ASSERT_TRUE( - reader.ReadVariableWidthS64(&read_val, chunk_length, zigzag_exponent)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SingleWriteReadU32) { - for (uint32_t i = 0; i < 100000; i += 123) { - const uint32_t val = i * i; - const size_t chunk_length = i % 16 + 1; - - BitWriterWord64 writer; - writer.WriteVariableWidthU32(val, chunk_length); - - BitReaderWord64 reader(writer.GetDataCopy()); - uint32_t read_val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU32(&read_val, chunk_length)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SingleWriteReadU16) { - for (int i = 0; i < 65536; i += 123) { - const uint16_t val = static_cast(i); - const size_t chunk_length = val % 10 + 1; - - BitWriterWord64 writer; - writer.WriteVariableWidthU16(val, chunk_length); - - BitReaderWord64 reader(writer.GetDataCopy()); - uint16_t read_val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU16(&read_val, chunk_length)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SmallNumbersChunkLength4) { - const std::vector expected_values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - - BitWriterWord64 writer; - for (uint64_t val : expected_values) { - writer.WriteVariableWidthU64(val, 4); - } - - EXPECT_EQ(50u, writer.GetNumBits()); - - std::vector actual_values; - BitReaderWord64 reader(writer.GetDataCopy()); - while (!reader.OnlyZeroesLeft()) { - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 4)); - actual_values.push_back(val); - } - - EXPECT_EQ(expected_values, actual_values); -} - -TEST(VariableWidthWriteRead, VariedNumbersChunkLength8) { - const std::vector expected_values = {1000, 0, 255, 4294967296}; - const size_t kExpectedNumBits = 9 * (2 + 1 + 1 + 5); - - BitWriterWord64 writer; - for (uint64_t val : expected_values) { - writer.WriteVariableWidthU64(val, 8); - } - - EXPECT_EQ(kExpectedNumBits, writer.GetNumBits()); - - std::vector actual_values; - BitReaderWord64 reader(writer.GetDataCopy()); - while (!reader.OnlyZeroesLeft()) { - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 8)); - actual_values.push_back(val); - } - - EXPECT_EQ(expected_values, actual_values); -} - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/comp/CMakeLists.txt b/3rdparty/spirv-tools/test/comp/CMakeLists.txt deleted file mode 100644 index c947fde0c..000000000 --- a/3rdparty/spirv-tools/test/comp/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2017 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(VAL_TEST_COMMON_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/../test_fixture.h - ${CMAKE_CURRENT_SOURCE_DIR}/../unit_spirv.h -) - -if(SPIRV_BUILD_COMPRESSION) - add_spvtools_unittest(TARGET markv_codec - SRCS - markv_codec_test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/comp/markv_model_factory.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/comp/markv_model_shader.cpp - ${VAL_TEST_COMMON_SRCS} - LIBS SPIRV-Tools-comp ${SPIRV_TOOLS} - ) -endif(SPIRV_BUILD_COMPRESSION) diff --git a/3rdparty/spirv-tools/test/comp/markv_codec_test.cpp b/3rdparty/spirv-tools/test/comp/markv_codec_test.cpp deleted file mode 100644 index a7af61710..000000000 --- a/3rdparty/spirv-tools/test/comp/markv_codec_test.cpp +++ /dev/null @@ -1,829 +0,0 @@ -// Copyright (c) 2017 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. - -// Tests for unique type declaration rules validator. - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/markv.h" -#include "test/test_fixture.h" -#include "test/unit_spirv.h" -#include "tools/comp/markv_model_factory.h" - -namespace spvtools { -namespace comp { -namespace { - -using spvtest::ScopedContext; -using MarkvTest = ::testing::TestWithParam; - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cout << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cout << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -// Compiles |code| to SPIR-V |words|. -void Compile(const std::string& code, std::vector* words, - uint32_t options = SPV_TEXT_TO_BINARY_OPTION_NONE, - spv_target_env env = SPV_ENV_UNIVERSAL_1_2) { - spvtools::Context ctx(env); - ctx.SetMessageConsumer(DiagnosticsMessageHandler); - - spv_binary spirv_binary; - ASSERT_EQ(SPV_SUCCESS, spvTextToBinaryWithOptions( - ctx.CContext(), code.c_str(), code.size(), options, - &spirv_binary, nullptr)); - - *words = std::vector(spirv_binary->code, - spirv_binary->code + spirv_binary->wordCount); - - spvBinaryDestroy(spirv_binary); -} - -// Disassembles SPIR-V |words| to |out_text|. -void Disassemble(const std::vector& words, std::string* out_text, - spv_target_env env = SPV_ENV_UNIVERSAL_1_2) { - spvtools::Context ctx(env); - ctx.SetMessageConsumer(DiagnosticsMessageHandler); - - spv_text text = nullptr; - ASSERT_EQ(SPV_SUCCESS, spvBinaryToText(ctx.CContext(), words.data(), - words.size(), 0, &text, nullptr)); - assert(text); - - *out_text = std::string(text->str, text->length); - spvTextDestroy(text); -} - -// Encodes/decodes |original|, assembles/dissasembles |original|, then compares -// the results of the two operations. -void TestEncodeDecode(MarkvModelType model_type, - const std::string& original_text) { - spvtools::Context ctx(SPV_ENV_UNIVERSAL_1_2); - std::unique_ptr model = CreateMarkvModel(model_type); - MarkvCodecOptions options; - - std::vector expected_binary; - Compile(original_text, &expected_binary); - ASSERT_FALSE(expected_binary.empty()); - - std::string expected_text; - Disassemble(expected_binary, &expected_text); - ASSERT_FALSE(expected_text.empty()); - - std::vector binary_to_encode; - Compile(original_text, &binary_to_encode, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_FALSE(binary_to_encode.empty()); - - std::stringstream encoder_comments; - const auto output_to_string_stream = - [&encoder_comments](const std::string& str) { encoder_comments << str; }; - - std::vector markv; - ASSERT_EQ(SPV_SUCCESS, - SpirvToMarkv(ctx.CContext(), binary_to_encode, options, *model, - DiagnosticsMessageHandler, output_to_string_stream, - MarkvDebugConsumer(), &markv)); - ASSERT_FALSE(markv.empty()); - - std::vector decoded_binary; - ASSERT_EQ(SPV_SUCCESS, - MarkvToSpirv(ctx.CContext(), markv, options, *model, - DiagnosticsMessageHandler, MarkvLogConsumer(), - MarkvDebugConsumer(), &decoded_binary)); - ASSERT_FALSE(decoded_binary.empty()); - - EXPECT_EQ(expected_binary, decoded_binary) << encoder_comments.str(); - - std::string decoded_text; - Disassemble(decoded_binary, &decoded_text); - ASSERT_FALSE(decoded_text.empty()); - - EXPECT_EQ(expected_text, decoded_text) << encoder_comments.str(); -} - -void TestEncodeDecodeShaderMainBody(MarkvModelType model_type, - const std::string& body) { - const std::string prefix = - R"( -OpCapability Shader -OpCapability Int64 -OpCapability Float64 -%ext_inst = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -%void = OpTypeVoid -%func = OpTypeFunction %void -%bool = OpTypeBool -%f32 = OpTypeFloat 32 -%u32 = OpTypeInt 32 0 -%s32 = OpTypeInt 32 1 -%f64 = OpTypeFloat 64 -%u64 = OpTypeInt 64 0 -%s64 = OpTypeInt 64 1 -%boolvec2 = OpTypeVector %bool 2 -%s32vec2 = OpTypeVector %s32 2 -%u32vec2 = OpTypeVector %u32 2 -%f32vec2 = OpTypeVector %f32 2 -%f64vec2 = OpTypeVector %f64 2 -%boolvec3 = OpTypeVector %bool 3 -%u32vec3 = OpTypeVector %u32 3 -%s32vec3 = OpTypeVector %s32 3 -%f32vec3 = OpTypeVector %f32 3 -%f64vec3 = OpTypeVector %f64 3 -%boolvec4 = OpTypeVector %bool 4 -%u32vec4 = OpTypeVector %u32 4 -%s32vec4 = OpTypeVector %s32 4 -%f32vec4 = OpTypeVector %f32 4 -%f64vec4 = OpTypeVector %f64 4 - -%f32_0 = OpConstant %f32 0 -%f32_1 = OpConstant %f32 1 -%f32_2 = OpConstant %f32 2 -%f32_3 = OpConstant %f32 3 -%f32_4 = OpConstant %f32 4 -%f32_pi = OpConstant %f32 3.14159 - -%s32_0 = OpConstant %s32 0 -%s32_1 = OpConstant %s32 1 -%s32_2 = OpConstant %s32 2 -%s32_3 = OpConstant %s32 3 -%s32_4 = OpConstant %s32 4 -%s32_m1 = OpConstant %s32 -1 - -%u32_0 = OpConstant %u32 0 -%u32_1 = OpConstant %u32 1 -%u32_2 = OpConstant %u32 2 -%u32_3 = OpConstant %u32 3 -%u32_4 = OpConstant %u32 4 - -%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 -%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 -%u32vec3_012 = OpConstantComposite %u32vec3 %u32_0 %u32_1 %u32_2 -%u32vec3_123 = OpConstantComposite %u32vec3 %u32_1 %u32_2 %u32_3 -%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 -%u32vec4_1234 = OpConstantComposite %u32vec4 %u32_1 %u32_2 %u32_3 %u32_4 - -%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1 -%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2 -%s32vec3_012 = OpConstantComposite %s32vec3 %s32_0 %s32_1 %s32_2 -%s32vec3_123 = OpConstantComposite %s32vec3 %s32_1 %s32_2 %s32_3 -%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3 -%s32vec4_1234 = OpConstantComposite %s32vec4 %s32_1 %s32_2 %s32_3 %s32_4 - -%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 -%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 -%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 -%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 -%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 -%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 - -%main = OpFunction %void None %func -%main_entry = OpLabel)"; - - const std::string suffix = - R"( -OpReturn -OpFunctionEnd)"; - - TestEncodeDecode(model_type, prefix + body + suffix); -} - -TEST_P(MarkvTest, U32Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -%u32 = OpTypeInt 32 0 -%100 = OpConstant %u32 0 -%200 = OpConstant %u32 1 -%300 = OpConstant %u32 4294967295 -)"); -} - -TEST_P(MarkvTest, S32Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -%s32 = OpTypeInt 32 1 -%100 = OpConstant %s32 0 -%200 = OpConstant %s32 1 -%300 = OpConstant %s32 -1 -%400 = OpConstant %s32 2147483647 -%500 = OpConstant %s32 -2147483648 -)"); -} - -TEST_P(MarkvTest, U64Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int64 -OpMemoryModel Logical GLSL450 -%u64 = OpTypeInt 64 0 -%100 = OpConstant %u64 0 -%200 = OpConstant %u64 1 -%300 = OpConstant %u64 18446744073709551615 -)"); -} - -TEST_P(MarkvTest, S64Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int64 -OpMemoryModel Logical GLSL450 -%s64 = OpTypeInt 64 1 -%100 = OpConstant %s64 0 -%200 = OpConstant %s64 1 -%300 = OpConstant %s64 -1 -%400 = OpConstant %s64 9223372036854775807 -%500 = OpConstant %s64 -9223372036854775808 -)"); -} - -TEST_P(MarkvTest, U16Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int16 -OpMemoryModel Logical GLSL450 -%u16 = OpTypeInt 16 0 -%100 = OpConstant %u16 0 -%200 = OpConstant %u16 1 -%300 = OpConstant %u16 65535 -)"); -} - -TEST_P(MarkvTest, S16Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int16 -OpMemoryModel Logical GLSL450 -%s16 = OpTypeInt 16 1 -%100 = OpConstant %s16 0 -%200 = OpConstant %s16 1 -%300 = OpConstant %s16 -1 -%400 = OpConstant %s16 32767 -%500 = OpConstant %s16 -32768 -)"); -} - -TEST_P(MarkvTest, F32Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -%f32 = OpTypeFloat 32 -%100 = OpConstant %f32 0 -%200 = OpConstant %f32 1 -%300 = OpConstant %f32 0.1 -%400 = OpConstant %f32 -0.1 -)"); -} - -TEST_P(MarkvTest, F64Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Float64 -OpMemoryModel Logical GLSL450 -%f64 = OpTypeFloat 64 -%100 = OpConstant %f64 0 -%200 = OpConstant %f64 1 -%300 = OpConstant %f64 0.1 -%400 = OpConstant %f64 -0.1 -)"); -} - -TEST_P(MarkvTest, F16Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Float16 -OpMemoryModel Logical GLSL450 -%f16 = OpTypeFloat 16 -%100 = OpConstant %f16 0 -%200 = OpConstant %f16 1 -%300 = OpConstant %f16 0.1 -%400 = OpConstant %f16 -0.1 -)"); -} - -TEST_P(MarkvTest, StringLiteral) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_KHR_16bit_storage" -OpExtension "xxx" -OpExtension "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -OpExtension "" -OpMemoryModel Logical GLSL450 -)"); -} - -TEST_P(MarkvTest, WithFunction) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpExtension "SPV_KHR_16bit_storage" -OpMemoryModel Physical32 OpenCL -%f32 = OpTypeFloat 32 -%u32 = OpTypeInt 32 0 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%100 = OpConstant %u32 1 -%200 = OpConstant %u32 2 -%main = OpFunction %void None %void_func -%entry_main = OpLabel -%300 = OpIAdd %u32 %100 %200 -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithMultipleFunctions) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%f32 = OpTypeFloat 32 -%one = OpConstant %f32 1 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%f32_func = OpTypeFunction %f32 %f32 -%sqr_plus_one = OpFunction %f32 None %f32_func -%x = OpFunctionParameter %f32 -%100 = OpLabel -%x2 = OpFMul %f32 %x %x -%x2p1 = OpFunctionCall %f32 %plus_one %x2 -OpReturnValue %x2p1 -OpFunctionEnd -%plus_one = OpFunction %f32 None %f32_func -%y = OpFunctionParameter %f32 -%200 = OpLabel -%yp1 = OpFAdd %f32 %y %one -OpReturnValue %yp1 -OpFunctionEnd -%main = OpFunction %void None %void_func -%entry_main = OpLabel -%1p1 = OpFunctionCall %f32 %sqr_plus_one %one -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, ForwardDeclaredId) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -OpEntryPoint Kernel %1 "simple_kernel" -%2 = OpTypeInt 32 0 -%3 = OpTypeVector %2 2 -%4 = OpConstant %2 2 -%5 = OpTypeArray %2 %4 -%6 = OpTypeVoid -%7 = OpTypeFunction %6 -%1 = OpFunction %6 None %7 -%8 = OpLabel -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithSwitch) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpCapability Int64 -OpMemoryModel Physical32 OpenCL -%u64 = OpTypeInt 64 0 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%val = OpConstant %u64 1 -%main = OpFunction %void None %void_func -%entry_main = OpLabel -OpSwitch %val %default 1 %case1 1000000000000 %case2 -%case1 = OpLabel -OpNop -OpBranch %after_switch -%case2 = OpLabel -OpNop -OpBranch %after_switch -%default = OpLabel -OpNop -OpBranch %after_switch -%after_switch = OpLabel -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithLoop) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%main = OpFunction %void None %void_func -%entry_main = OpLabel -OpLoopMerge %merge %continue DontUnroll|DependencyLength 10 -OpBranch %begin_loop -%begin_loop = OpLabel -OpNop -OpBranch %continue -%continue = OpLabel -OpNop -OpBranch %begin_loop -%merge = OpLabel -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithDecorate) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -OpDecorate %1 ArrayStride 4 -OpDecorate %1 Uniform -%2 = OpTypeFloat 32 -%1 = OpTypeRuntimeArray %2 -)"); -} - -TEST_P(MarkvTest, WithExtInst) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -%opencl = OpExtInstImport "OpenCL.std" -OpMemoryModel Physical32 OpenCL -%f32 = OpTypeFloat 32 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%100 = OpConstant %f32 1.1 -%main = OpFunction %void None %void_func -%entry_main = OpLabel -%200 = OpExtInst %f32 %opencl cos %100 -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, F32Mul) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpFMul %f32 %f32_0 %f32_1 -%val2 = OpFMul %f32 %f32_2 %f32_0 -%val3 = OpFMul %f32 %f32_pi %f32_2 -%val4 = OpFMul %f32 %f32_1 %f32_1 -)"); -} - -TEST_P(MarkvTest, U32Mul) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIMul %u32 %u32_0 %u32_1 -%val2 = OpIMul %u32 %u32_2 %u32_0 -%val3 = OpIMul %u32 %u32_3 %u32_2 -%val4 = OpIMul %u32 %u32_1 %u32_1 -)"); -} - -TEST_P(MarkvTest, S32Mul) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIMul %s32 %s32_0 %s32_1 -%val2 = OpIMul %s32 %s32_2 %s32_0 -%val3 = OpIMul %s32 %s32_m1 %s32_2 -%val4 = OpIMul %s32 %s32_1 %s32_1 -)"); -} - -TEST_P(MarkvTest, F32Add) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpFAdd %f32 %f32_0 %f32_1 -%val2 = OpFAdd %f32 %f32_2 %f32_0 -%val3 = OpFAdd %f32 %f32_pi %f32_2 -%val4 = OpFAdd %f32 %f32_1 %f32_1 -)"); -} - -TEST_P(MarkvTest, U32Add) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIAdd %u32 %u32_0 %u32_1 -%val2 = OpIAdd %u32 %u32_2 %u32_0 -%val3 = OpIAdd %u32 %u32_3 %u32_2 -%val4 = OpIAdd %u32 %u32_1 %u32_1 -)"); -} - -TEST_P(MarkvTest, S32Add) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIAdd %s32 %s32_0 %s32_1 -%val2 = OpIAdd %s32 %s32_2 %s32_0 -%val3 = OpIAdd %s32 %s32_m1 %s32_2 -%val4 = OpIAdd %s32 %s32_1 %s32_1 -)"); -} - -TEST_P(MarkvTest, F32Dot) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%dot2_1 = OpDot %f32 %f32vec2_01 %f32vec2_12 -%dot2_2 = OpDot %f32 %f32vec2_01 %f32vec2_01 -%dot2_3 = OpDot %f32 %f32vec2_12 %f32vec2_12 -%dot3_1 = OpDot %f32 %f32vec3_012 %f32vec3_123 -%dot3_2 = OpDot %f32 %f32vec3_012 %f32vec3_012 -%dot3_3 = OpDot %f32 %f32vec3_123 %f32vec3_123 -%dot4_1 = OpDot %f32 %f32vec4_0123 %f32vec4_1234 -%dot4_2 = OpDot %f32 %f32vec4_0123 %f32vec4_0123 -%dot4_3 = OpDot %f32 %f32vec4_1234 %f32vec4_1234 -)"); -} - -TEST_P(MarkvTest, F32VectorCompositeConstruct) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%cc1 = OpCompositeConstruct %f32vec4 %f32vec2_01 %f32vec2_12 -%cc2 = OpCompositeConstruct %f32vec3 %f32vec2_01 %f32_2 -%cc3 = OpCompositeConstruct %f32vec2 %f32_1 %f32_2 -%cc4 = OpCompositeConstruct %f32vec4 %f32_1 %f32_2 %cc3 -)"); -} - -TEST_P(MarkvTest, U32VectorCompositeConstruct) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%cc1 = OpCompositeConstruct %u32vec4 %u32vec2_01 %u32vec2_12 -%cc2 = OpCompositeConstruct %u32vec3 %u32vec2_01 %u32_2 -%cc3 = OpCompositeConstruct %u32vec2 %u32_1 %u32_2 -%cc4 = OpCompositeConstruct %u32vec4 %u32_1 %u32_2 %cc3 -)"); -} - -TEST_P(MarkvTest, S32VectorCompositeConstruct) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%cc1 = OpCompositeConstruct %u32vec4 %u32vec2_01 %u32vec2_12 -%cc2 = OpCompositeConstruct %u32vec3 %u32vec2_01 %u32_2 -%cc3 = OpCompositeConstruct %u32vec2 %u32_1 %u32_2 -%cc4 = OpCompositeConstruct %u32vec4 %u32_1 %u32_2 %cc3 -)"); -} - -TEST_P(MarkvTest, F32VectorCompositeExtract) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%f32vec3_013 = OpCompositeExtract %f32vec3 %f32vec4_0123 0 1 3 -)"); -} - -TEST_P(MarkvTest, F32VectorComparison) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%c1 = OpFOrdEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c2 = OpFUnordEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c3 = OpFOrdNotEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c4 = OpFUnordNotEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c5 = OpFOrdLessThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c6 = OpFUnordLessThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c7 = OpFOrdGreaterThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c8 = OpFUnordGreaterThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c9 = OpFOrdLessThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c10 = OpFUnordLessThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c11 = OpFOrdGreaterThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c12 = OpFUnordGreaterThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -)"); -} - -TEST_P(MarkvTest, VectorShuffle) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%sh1 = OpVectorShuffle %f32vec2 %f32vec4_0123 %f32vec4_3210 3 6 -%sh2 = OpVectorShuffle %f32vec3 %f32vec2_01 %f32vec4_3210 0 3 4 -)"); -} - -TEST_P(MarkvTest, VectorTimesScalar) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%res1 = OpVectorTimesScalar %f32vec4 %f32vec4_0123 %f32_2 -%res2 = OpVectorTimesScalar %f32vec4 %f32vec4_3210 %f32_2 -)"); -} - -TEST_P(MarkvTest, SpirvSpecSample) { - TestEncodeDecode(GetParam(), R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" %31 %33 %42 %57 - OpExecutionMode %4 OriginLowerLeft - -; Debug information - OpSource GLSL 450 - OpName %4 "main" - OpName %9 "scale" - OpName %17 "S" - OpMemberName %17 0 "b" - OpMemberName %17 1 "v" - OpMemberName %17 2 "i" - OpName %18 "blockName" - OpMemberName %18 0 "s" - OpMemberName %18 1 "cond" - OpName %20 "" - OpName %31 "color" - OpName %33 "color1" - OpName %42 "color2" - OpName %48 "i" - OpName %57 "multiplier" - -; Annotations (non-debug) - OpDecorate %15 ArrayStride 16 - OpMemberDecorate %17 0 Offset 0 - OpMemberDecorate %17 1 Offset 16 - OpMemberDecorate %17 2 Offset 96 - OpMemberDecorate %18 0 Offset 0 - OpMemberDecorate %18 1 Offset 112 - OpDecorate %18 Block - OpDecorate %20 DescriptorSet 0 - OpDecorate %42 NoPerspective - -; All types, variables, and constants - %2 = OpTypeVoid - %3 = OpTypeFunction %2 ; void () - %6 = OpTypeFloat 32 ; 32-bit float - %7 = OpTypeVector %6 4 ; vec4 - %8 = OpTypePointer Function %7 ; function-local vec4* - %10 = OpConstant %6 1 - %11 = OpConstant %6 2 - %12 = OpConstantComposite %7 %10 %10 %11 %10 ; vec4(1.0, 1.0, 2.0, 1.0) - %13 = OpTypeInt 32 0 ; 32-bit int, sign-less - %14 = OpConstant %13 5 - %15 = OpTypeArray %7 %14 - %16 = OpTypeInt 32 1 - %17 = OpTypeStruct %13 %15 %16 - %18 = OpTypeStruct %17 %13 - %19 = OpTypePointer Uniform %18 - %20 = OpVariable %19 Uniform - %21 = OpConstant %16 1 - %22 = OpTypePointer Uniform %13 - %25 = OpTypeBool - %26 = OpConstant %13 0 - %30 = OpTypePointer Output %7 - %31 = OpVariable %30 Output - %32 = OpTypePointer Input %7 - %33 = OpVariable %32 Input - %35 = OpConstant %16 0 - %36 = OpConstant %16 2 - %37 = OpTypePointer Uniform %7 - %42 = OpVariable %32 Input - %47 = OpTypePointer Function %16 - %55 = OpConstant %16 4 - %57 = OpVariable %32 Input - -; All functions - %4 = OpFunction %2 None %3 ; main() - %5 = OpLabel - %9 = OpVariable %8 Function - %48 = OpVariable %47 Function - OpStore %9 %12 - %23 = OpAccessChain %22 %20 %21 ; location of cond - %24 = OpLoad %13 %23 ; load 32-bit int from cond - %27 = OpINotEqual %25 %24 %26 ; convert to bool - OpSelectionMerge %29 None ; structured if - OpBranchConditional %27 %28 %41 ; if cond - %28 = OpLabel ; then - %34 = OpLoad %7 %33 - %38 = OpAccessChain %37 %20 %35 %21 %36 ; s.v[2] - %39 = OpLoad %7 %38 - %40 = OpFAdd %7 %34 %39 - OpStore %31 %40 - OpBranch %29 - %41 = OpLabel ; else - %43 = OpLoad %7 %42 - %44 = OpExtInst %7 %1 Sqrt %43 ; extended instruction sqrt - %45 = OpLoad %7 %9 - %46 = OpFMul %7 %44 %45 - OpStore %31 %46 - OpBranch %29 - %29 = OpLabel ; endif - OpStore %48 %35 - OpBranch %49 - %49 = OpLabel - OpLoopMerge %51 %52 None ; structured loop - OpBranch %53 - %53 = OpLabel - %54 = OpLoad %16 %48 - %56 = OpSLessThan %25 %54 %55 ; i < 4 ? - OpBranchConditional %56 %50 %51 ; body or break - %50 = OpLabel ; body - %58 = OpLoad %7 %57 - %59 = OpLoad %7 %31 - %60 = OpFMul %7 %59 %58 - OpStore %31 %60 - OpBranch %52 - %52 = OpLabel ; continue target - %61 = OpLoad %16 %48 - %62 = OpIAdd %16 %61 %21 ; ++i - OpStore %48 %62 - OpBranch %49 ; loop back - %51 = OpLabel ; loop merge point - OpReturn - OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, SampleFromDeadBranchEliminationTest) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %gl_FragColor "gl_FragColor" -%void = OpTypeVoid -%5 = OpTypeFunction %void -%bool = OpTypeBool -%true = OpConstantTrue %bool -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%float_0 = OpConstant %float 0 -%12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 -%float_1 = OpConstant %float 1 -%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_v4float = OpTypePointer Input %v4float -%main = OpFunction %void None %5 -%17 = OpLabel -OpSelectionMerge %18 None -OpBranchConditional %true %19 %20 -%19 = OpLabel -OpBranch %18 -%20 = OpLabel -OpBranch %18 -%18 = OpLabel -%21 = OpPhi %v4float %12 %19 %14 %20 -OpStore %gl_FragColor %21 -OpReturn -OpFunctionEnd -)"); -} - -INSTANTIATE_TEST_SUITE_P(AllMarkvModels, MarkvTest, - ::testing::ValuesIn(std::vector{ - kMarkvModelShaderLite, - kMarkvModelShaderMid, - kMarkvModelShaderMax, - })); - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt new file mode 100644 index 000000000..88635c734 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt @@ -0,0 +1,36 @@ +# 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. + +if (${SPIRV_BUILD_FUZZER}) + + set(SOURCES + fuzz_test_util.h + + fuzzer_test.cpp + fuzz_test_util.cpp + transformation_add_constant_boolean_test.cpp + transformation_add_constant_scalar_test.cpp + transformation_add_dead_break_test.cpp + transformation_add_type_boolean_test.cpp + transformation_add_type_float_test.cpp + transformation_add_type_int_test.cpp + transformation_move_block_down_test.cpp + transformation_replace_boolean_constant_with_constant_binary_test.cpp + transformation_split_block_test.cpp) + + add_spvtools_unittest(TARGET fuzz + SRCS ${SOURCES} + LIBS SPIRV-Tools-fuzz + ) +endif() diff --git a/3rdparty/spirv-tools/test/fuzz/fuzz_test_util.cpp b/3rdparty/spirv-tools/test/fuzz/fuzz_test_util.cpp new file mode 100644 index 000000000..545512f9a --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/fuzz_test_util.cpp @@ -0,0 +1,89 @@ +// 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 "test/fuzz/fuzz_test_util.h" + +#include + +namespace spvtools { +namespace fuzz { + +bool IsEqual(const spv_target_env env, + const std::vector& expected_binary, + const std::vector& actual_binary) { + if (expected_binary == actual_binary) { + return true; + } + SpirvTools t(env); + std::string expected_disassembled; + std::string actual_disassembled; + if (!t.Disassemble(expected_binary, &expected_disassembled, + kFuzzDisassembleOption)) { + return false; + } + if (!t.Disassemble(actual_binary, &actual_disassembled, + kFuzzDisassembleOption)) { + return false; + } + // Using expect gives us a string diff if the strings are not the same. + EXPECT_EQ(expected_disassembled, actual_disassembled); + // We then return the result of the equality comparison, to be used by an + // assertion in the test root function. + return expected_disassembled == actual_disassembled; +} + +bool IsEqual(const spv_target_env env, const std::string& expected_text, + const std::vector& actual_binary) { + std::vector expected_binary; + SpirvTools t(env); + if (!t.Assemble(expected_text, &expected_binary, kFuzzAssembleOption)) { + return false; + } + return IsEqual(env, expected_binary, actual_binary); +} + +bool IsEqual(const spv_target_env env, const std::string& expected_text, + const opt::IRContext* actual_ir) { + std::vector actual_binary; + actual_ir->module()->ToBinary(&actual_binary, false); + return IsEqual(env, expected_text, actual_binary); +} + +bool IsEqual(const spv_target_env env, const opt::IRContext* ir_1, + const opt::IRContext* ir_2) { + std::vector binary_1; + ir_1->module()->ToBinary(&binary_1, false); + std::vector binary_2; + ir_2->module()->ToBinary(&binary_2, false); + return IsEqual(env, binary_1, binary_2); +} + +bool IsValid(spv_target_env env, const opt::IRContext* ir) { + std::vector binary; + ir->module()->ToBinary(&binary, false); + SpirvTools t(env); + return t.Validate(binary); +} + +std::string ToString(spv_target_env env, const opt::IRContext* ir) { + std::vector binary; + ir->module()->ToBinary(&binary, false); + SpirvTools t(env); + std::string result; + t.Disassemble(binary, &result, kFuzzDisassembleOption); + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/fuzz_test_util.h b/3rdparty/spirv-tools/test/fuzz/fuzz_test_util.h new file mode 100644 index 000000000..202622c85 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/fuzz_test_util.h @@ -0,0 +1,65 @@ +// 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 TEST_FUZZ_FUZZ_TEST_UTIL_H_ +#define TEST_FUZZ_FUZZ_TEST_UTIL_H_ + +#include "gtest/gtest.h" + +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace fuzz { + +// Returns true if and only if the given binaries are bit-wise equal. +bool IsEqual(spv_target_env env, const std::vector& expected_binary, + const std::vector& actual_binary); + +// Assembles the given text and returns true if and only if the resulting binary +// is bit-wise equal to the given binary. +bool IsEqual(spv_target_env env, const std::string& expected_text, + const std::vector& actual_binary); + +// Assembles the given text and turns the given IR into binary, then returns +// true if and only if the resulting binaries are bit-wise equal. +bool IsEqual(spv_target_env env, const std::string& expected_text, + const opt::IRContext* actual_ir); + +// Turns the given IRs into binaries, then returns true if and only if the +// resulting binaries are bit-wise equal. +bool IsEqual(spv_target_env env, const opt::IRContext* ir_1, + const opt::IRContext* ir_2); + +// Assembles the given IR context and returns true if and only if +// the resulting binary is valid. +bool IsValid(spv_target_env env, const opt::IRContext* ir); + +// Assembles the given IR context, then returns its disassembly as a string. +// Useful for debugging. +std::string ToString(spv_target_env env, const opt::IRContext* ir); + +// Assembly options for writing fuzzer tests. It simplifies matters if +// numeric ids do not change. +const uint32_t kFuzzAssembleOption = + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS; +// Disassembly options for writing fuzzer tests. +const uint32_t kFuzzDisassembleOption = + SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_INDENT; + +} // namespace fuzz +} // namespace spvtools + +#endif // TEST_FUZZ_FUZZ_TEST_UTIL_H_ diff --git a/3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp b/3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp new file mode 100644 index 000000000..069777ff3 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp @@ -0,0 +1,464 @@ +// 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.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +// 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. +void RunFuzzer(const std::string& shader, uint32_t initial_seed, + uint32_t num_runs) { + const auto env = SPV_ENV_UNIVERSAL_1_3; + + std::vector binary_in; + SpirvTools t(env); + ASSERT_TRUE(t.Assemble(shader, &binary_in, kFuzzAssembleOption)); + ASSERT_TRUE(t.Validate(binary_in)); + + for (uint32_t seed = initial_seed; seed < initial_seed + num_runs; seed++) { + protobufs::FactSequence initial_facts; + std::vector binary_out; + protobufs::TransformationSequence transformation_sequence_out; + spvtools::FuzzerOptions fuzzer_options; + spvFuzzerOptionsSetRandomSeed(fuzzer_options, seed); + + Fuzzer fuzzer(env); + fuzzer.Run(binary_in, initial_facts, &binary_out, + &transformation_sequence_out, fuzzer_options); + ASSERT_TRUE(t.Validate(binary_out)); + } +} + +TEST(FuzzerTest, Miscellaneous1) { + // The SPIR-V came from this GLSL: + // + // #version 310 es + // + // void foo() { + // int x; + // x = 2; + // for (int i = 0; i < 100; i++) { + // x += i; + // x = x * 2; + // } + // return; + // } + // + // void main() { + // foo(); + // for (int i = 0; i < 10; i++) { + // int j = 20; + // while(j > 0) { + // foo(); + // j--; + // } + // do { + // i++; + // } while(i < 4); + // } + // } + + 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 %6 "foo(" + OpName %10 "x" + OpName %12 "i" + OpName %33 "i" + OpName %42 "j" + OpDecorate %10 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %24 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %28 RelaxedPrecision + OpDecorate %30 RelaxedPrecision + OpDecorate %33 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %42 RelaxedPrecision + OpDecorate %49 RelaxedPrecision + OpDecorate %52 RelaxedPrecision + OpDecorate %53 RelaxedPrecision + OpDecorate %58 RelaxedPrecision + OpDecorate %59 RelaxedPrecision + OpDecorate %60 RelaxedPrecision + OpDecorate %63 RelaxedPrecision + OpDecorate %64 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 2 + %13 = OpConstant %8 0 + %20 = OpConstant %8 100 + %21 = OpTypeBool + %29 = OpConstant %8 1 + %40 = OpConstant %8 10 + %43 = OpConstant %8 20 + %61 = OpConstant %8 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %33 = OpVariable %9 Function + %42 = OpVariable %9 Function + %32 = OpFunctionCall %2 %6 + OpStore %33 %13 + OpBranch %34 + %34 = OpLabel + OpLoopMerge %36 %37 None + OpBranch %38 + %38 = OpLabel + %39 = OpLoad %8 %33 + %41 = OpSLessThan %21 %39 %40 + OpBranchConditional %41 %35 %36 + %35 = OpLabel + OpStore %42 %43 + OpBranch %44 + %44 = OpLabel + OpLoopMerge %46 %47 None + OpBranch %48 + %48 = OpLabel + %49 = OpLoad %8 %42 + %50 = OpSGreaterThan %21 %49 %13 + OpBranchConditional %50 %45 %46 + %45 = OpLabel + %51 = OpFunctionCall %2 %6 + %52 = OpLoad %8 %42 + %53 = OpISub %8 %52 %29 + OpStore %42 %53 + OpBranch %47 + %47 = OpLabel + OpBranch %44 + %46 = OpLabel + OpBranch %54 + %54 = OpLabel + OpLoopMerge %56 %57 None + OpBranch %55 + %55 = OpLabel + %58 = OpLoad %8 %33 + %59 = OpIAdd %8 %58 %29 + OpStore %33 %59 + OpBranch %57 + %57 = OpLabel + %60 = OpLoad %8 %33 + %62 = OpSLessThan %21 %60 %61 + OpBranchConditional %62 %54 %56 + %56 = OpLabel + OpBranch %37 + %37 = OpLabel + %63 = OpLoad %8 %33 + %64 = OpIAdd %8 %63 %29 + OpStore %33 %64 + OpBranch %34 + %36 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + %12 = OpVariable %9 Function + OpStore %10 %11 + OpStore %12 %13 + OpBranch %14 + %14 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + %19 = OpLoad %8 %12 + %22 = OpSLessThan %21 %19 %20 + OpBranchConditional %22 %15 %16 + %15 = OpLabel + %23 = OpLoad %8 %12 + %24 = OpLoad %8 %10 + %25 = OpIAdd %8 %24 %23 + OpStore %10 %25 + %26 = OpLoad %8 %10 + %27 = OpIMul %8 %26 %11 + OpStore %10 %27 + OpBranch %17 + %17 = OpLabel + %28 = OpLoad %8 %12 + %30 = OpIAdd %8 %28 %29 + OpStore %12 %30 + OpBranch %14 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + // Do 10 fuzzer runs, starting from an initial seed of 0 (seed value chosen + // arbitrarily). + RunFuzzer(shader, 0, 10); +} + +TEST(FuzzerTest, Miscellaneous2) { + // The SPIR-V came from this GLSL, which was then optimized using spirv-opt + // with the -O argument: + // + // #version 310 es + // + // precision highp float; + // + // layout(location = 0) out vec4 _GLF_color; + // + // layout(set = 0, binding = 0) uniform buf0 { + // vec2 injectionSwitch; + // }; + // layout(set = 0, binding = 1) uniform buf1 { + // vec2 resolution; + // }; + // bool checkSwap(float a, float b) + // { + // return gl_FragCoord.y < resolution.y / 2.0 ? a > b : a < b; + // } + // void main() + // { + // float data[10]; + // for(int i = 0; i < 10; i++) + // { + // data[i] = float(10 - i) * injectionSwitch.y; + // } + // for(int i = 0; i < 9; i++) + // { + // for(int j = 0; j < 10; j++) + // { + // if(j < i + 1) + // { + // continue; + // } + // bool doSwap = checkSwap(data[i], data[j]); + // if(doSwap) + // { + // float temp = data[i]; + // data[i] = data[j]; + // data[j] = temp; + // } + // } + // } + // if(gl_FragCoord.x < resolution.x / 2.0) + // { + // _GLF_color = vec4(data[0] / 10.0, data[5] / 10.0, data[9] / 10.0, 1.0); + // } + // else + // { + // _GLF_color = vec4(data[5] / 10.0, data[9] / 10.0, data[0] / 10.0, 1.0); + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %16 %139 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %16 "gl_FragCoord" + OpName %23 "buf1" + OpMemberName %23 0 "resolution" + OpName %25 "" + OpName %61 "data" + OpName %66 "buf0" + OpMemberName %66 0 "injectionSwitch" + OpName %68 "" + OpName %139 "_GLF_color" + OpDecorate %16 BuiltIn FragCoord + OpMemberDecorate %23 0 Offset 0 + OpDecorate %23 Block + OpDecorate %25 DescriptorSet 0 + OpDecorate %25 Binding 1 + OpDecorate %64 RelaxedPrecision + OpMemberDecorate %66 0 Offset 0 + OpDecorate %66 Block + OpDecorate %68 DescriptorSet 0 + OpDecorate %68 Binding 0 + OpDecorate %75 RelaxedPrecision + OpDecorate %95 RelaxedPrecision + OpDecorate %126 RelaxedPrecision + OpDecorate %128 RelaxedPrecision + OpDecorate %139 Location 0 + OpDecorate %182 RelaxedPrecision + OpDecorate %183 RelaxedPrecision + OpDecorate %184 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %8 = OpTypeBool + %14 = OpTypeVector %6 4 + %15 = OpTypePointer Input %14 + %16 = OpVariable %15 Input + %17 = OpTypeInt 32 0 + %18 = OpConstant %17 1 + %19 = OpTypePointer Input %6 + %22 = OpTypeVector %6 2 + %23 = OpTypeStruct %22 + %24 = OpTypePointer Uniform %23 + %25 = OpVariable %24 Uniform + %26 = OpTypeInt 32 1 + %27 = OpConstant %26 0 + %28 = OpTypePointer Uniform %6 + %56 = OpConstant %26 10 + %58 = OpConstant %17 10 + %59 = OpTypeArray %6 %58 + %60 = OpTypePointer Function %59 + %66 = OpTypeStruct %22 + %67 = OpTypePointer Uniform %66 + %68 = OpVariable %67 Uniform + %74 = OpConstant %26 1 + %83 = OpConstant %26 9 + %129 = OpConstant %17 0 + %138 = OpTypePointer Output %14 + %139 = OpVariable %138 Output + %144 = OpConstant %26 5 + %151 = OpConstant %6 1 + %194 = OpConstant %6 0.5 + %195 = OpConstant %6 0.100000001 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %61 = OpVariable %60 Function + OpBranch %50 + %50 = OpLabel + %182 = OpPhi %26 %27 %5 %75 %51 + %57 = OpSLessThan %8 %182 %56 + OpLoopMerge %52 %51 None + OpBranchConditional %57 %51 %52 + %51 = OpLabel + %64 = OpISub %26 %56 %182 + %65 = OpConvertSToF %6 %64 + %69 = OpAccessChain %28 %68 %27 %18 + %70 = OpLoad %6 %69 + %71 = OpFMul %6 %65 %70 + %72 = OpAccessChain %7 %61 %182 + OpStore %72 %71 + %75 = OpIAdd %26 %182 %74 + OpBranch %50 + %52 = OpLabel + OpBranch %77 + %77 = OpLabel + %183 = OpPhi %26 %27 %52 %128 %88 + %84 = OpSLessThan %8 %183 %83 + OpLoopMerge %79 %88 None + OpBranchConditional %84 %78 %79 + %78 = OpLabel + OpBranch %86 + %86 = OpLabel + %184 = OpPhi %26 %27 %78 %126 %89 + %92 = OpSLessThan %8 %184 %56 + OpLoopMerge %88 %89 None + OpBranchConditional %92 %87 %88 + %87 = OpLabel + %95 = OpIAdd %26 %183 %74 + %96 = OpSLessThan %8 %184 %95 + OpSelectionMerge %98 None + OpBranchConditional %96 %97 %98 + %97 = OpLabel + OpBranch %89 + %98 = OpLabel + %104 = OpAccessChain %7 %61 %183 + %105 = OpLoad %6 %104 + %107 = OpAccessChain %7 %61 %184 + %108 = OpLoad %6 %107 + %166 = OpAccessChain %19 %16 %18 + %167 = OpLoad %6 %166 + %168 = OpAccessChain %28 %25 %27 %18 + %169 = OpLoad %6 %168 + %170 = OpFMul %6 %169 %194 + %171 = OpFOrdLessThan %8 %167 %170 + OpSelectionMerge %172 None + OpBranchConditional %171 %173 %174 + %173 = OpLabel + %177 = OpFOrdGreaterThan %8 %105 %108 + OpBranch %172 + %174 = OpLabel + %180 = OpFOrdLessThan %8 %105 %108 + OpBranch %172 + %172 = OpLabel + %186 = OpPhi %8 %177 %173 %180 %174 + OpSelectionMerge %112 None + OpBranchConditional %186 %111 %112 + %111 = OpLabel + %116 = OpLoad %6 %104 + %120 = OpLoad %6 %107 + OpStore %104 %120 + OpStore %107 %116 + OpBranch %112 + %112 = OpLabel + OpBranch %89 + %89 = OpLabel + %126 = OpIAdd %26 %184 %74 + OpBranch %86 + %88 = OpLabel + %128 = OpIAdd %26 %183 %74 + OpBranch %77 + %79 = OpLabel + %130 = OpAccessChain %19 %16 %129 + %131 = OpLoad %6 %130 + %132 = OpAccessChain %28 %25 %27 %129 + %133 = OpLoad %6 %132 + %134 = OpFMul %6 %133 %194 + %135 = OpFOrdLessThan %8 %131 %134 + OpSelectionMerge %137 None + OpBranchConditional %135 %136 %153 + %136 = OpLabel + %140 = OpAccessChain %7 %61 %27 + %141 = OpLoad %6 %140 + %143 = OpFMul %6 %141 %195 + %145 = OpAccessChain %7 %61 %144 + %146 = OpLoad %6 %145 + %147 = OpFMul %6 %146 %195 + %148 = OpAccessChain %7 %61 %83 + %149 = OpLoad %6 %148 + %150 = OpFMul %6 %149 %195 + %152 = OpCompositeConstruct %14 %143 %147 %150 %151 + OpStore %139 %152 + OpBranch %137 + %153 = OpLabel + %154 = OpAccessChain %7 %61 %144 + %155 = OpLoad %6 %154 + %156 = OpFMul %6 %155 %195 + %157 = OpAccessChain %7 %61 %83 + %158 = OpLoad %6 %157 + %159 = OpFMul %6 %158 %195 + %160 = OpAccessChain %7 %61 %27 + %161 = OpLoad %6 %160 + %162 = OpFMul %6 %161 %195 + %163 = OpCompositeConstruct %14 %156 %159 %162 %151 + OpStore %139 %163 + OpBranch %137 + %137 = OpLabel + OpReturn + OpFunctionEnd + )"; + + // Do 10 fuzzer runs, starting from an initial seed of 10 (seed value chosen + // arbitrarily). + RunFuzzer(shader, 10, 10); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp new file mode 100644 index 000000000..96dab6407 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp @@ -0,0 +1,155 @@ +// 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_constant_boolean.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddConstantBooleanTest, NeitherPresentInitiallyAddBoth) { + 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 + %6 = OpTypeBool + %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, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // True and false can both be added as neither is present. + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddConstantBoolean(7, true), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddConstantBoolean(7, false), + context.get(), fact_manager)); + + // Id 5 is already taken. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddConstantBoolean(5, true), + context.get(), fact_manager)); + + auto add_true = transformation::MakeTransformationAddConstantBoolean(7, true); + auto add_false = + transformation::MakeTransformationAddConstantBoolean(8, false); + + ASSERT_TRUE( + transformation::IsApplicable(add_true, context.get(), fact_manager)); + transformation::Apply(add_true, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Having added true, we cannot add it again with the same id. + ASSERT_FALSE( + transformation::IsApplicable(add_true, context.get(), fact_manager)); + // But we can add it with a different id. + auto add_true_again = + transformation::MakeTransformationAddConstantBoolean(100, true); + ASSERT_TRUE(transformation::IsApplicable(add_true_again, context.get(), + fact_manager)); + transformation::Apply(add_true_again, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE( + transformation::IsApplicable(add_false, context.get(), fact_manager)); + transformation::Apply(add_false, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Having added false, we cannot add it again with the same id. + ASSERT_FALSE( + transformation::IsApplicable(add_false, context.get(), fact_manager)); + // But we can add it with a different id. + auto add_false_again = + transformation::MakeTransformationAddConstantBoolean(101, false); + ASSERT_TRUE(transformation::IsApplicable(add_false_again, context.get(), + fact_manager)); + transformation::Apply(add_false_again, 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 + %6 = OpTypeBool + %3 = OpTypeFunction %2 + %7 = OpConstantTrue %6 + %100 = OpConstantTrue %6 + %8 = OpConstantFalse %6 + %101 = OpConstantFalse %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddConstantBooleanTest, NoOpTypeBoolPresent) { + 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 + %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, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Neither true nor false can be added as OpTypeBool is not present. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddConstantBoolean(6, true), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddConstantBoolean(6, false), + context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp new file mode 100644 index 000000000..5d4bac65f --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp @@ -0,0 +1,209 @@ +// 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_constant_scalar.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddConstantScalarTest, 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 "x" + OpName %12 "y" + OpName %16 "z" + OpDecorate %8 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpTypeInt 32 0 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 2 + %14 = OpTypeFloat 32 + %15 = OpTypePointer Function %14 + %17 = OpConstant %14 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %16 = OpVariable %15 Function + OpStore %8 %9 + OpStore %12 %13 + OpStore %16 %17 + 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; + + const float float_values[2] = {3.0, 30.0}; + uint32_t uint_for_float[2]; + memcpy(uint_for_float, float_values, sizeof(float_values)); + + auto add_signed_int_1 = + transformation::MakeTransformationAddConstantScalar(100, 6, {1}); + auto add_signed_int_10 = + transformation::MakeTransformationAddConstantScalar(101, 6, {10}); + auto add_unsigned_int_2 = + transformation::MakeTransformationAddConstantScalar(102, 10, {2}); + auto add_unsigned_int_20 = + transformation::MakeTransformationAddConstantScalar(103, 10, {20}); + auto add_float_3 = transformation::MakeTransformationAddConstantScalar( + 104, 14, {uint_for_float[0]}); + auto add_float_30 = transformation::MakeTransformationAddConstantScalar( + 105, 14, {uint_for_float[1]}); + auto bad_add_float_30_id_already_used = + transformation::MakeTransformationAddConstantScalar(104, 14, + {uint_for_float[1]}); + auto bad_id_already_used = + transformation::MakeTransformationAddConstantScalar(1, 6, {1}); + auto bad_no_data = + transformation::MakeTransformationAddConstantScalar(100, 6, {}); + auto bad_too_much_data = + transformation::MakeTransformationAddConstantScalar(100, 6, {1, 2}); + auto bad_type_id_does_not_exist = + transformation::MakeTransformationAddConstantScalar(108, 2020, + {uint_for_float[0]}); + auto bad_type_id_is_not_a_type = + transformation::MakeTransformationAddConstantScalar(109, 9, {0}); + auto bad_type_id_is_void = + transformation::MakeTransformationAddConstantScalar(110, 2, {0}); + auto bad_type_id_is_pointer = + transformation::MakeTransformationAddConstantScalar(111, 11, {0}); + + // Id is already in use. + ASSERT_FALSE(transformation::IsApplicable(bad_id_already_used, context.get(), + fact_manager)); + + // At least one word of data must be provided. + ASSERT_FALSE( + transformation::IsApplicable(bad_no_data, context.get(), fact_manager)); + + // Cannot give two data words for a 32-bit type. + ASSERT_FALSE(transformation::IsApplicable(bad_too_much_data, context.get(), + fact_manager)); + + // Type id does not exist + ASSERT_FALSE(transformation::IsApplicable(bad_type_id_does_not_exist, + context.get(), fact_manager)); + + // Type id is not a type + ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_not_a_type, + context.get(), fact_manager)); + + // Type id is void + ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_void, context.get(), + fact_manager)); + + // Type id is pointer + ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_pointer, + context.get(), fact_manager)); + + ASSERT_TRUE(transformation::IsApplicable(add_signed_int_1, context.get(), + fact_manager)); + transformation::Apply(add_signed_int_1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(add_signed_int_10, context.get(), + fact_manager)); + transformation::Apply(add_signed_int_10, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(add_unsigned_int_2, context.get(), + fact_manager)); + transformation::Apply(add_unsigned_int_2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(add_unsigned_int_20, context.get(), + fact_manager)); + transformation::Apply(add_unsigned_int_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE( + transformation::IsApplicable(add_float_3, context.get(), fact_manager)); + transformation::Apply(add_float_3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE( + transformation::IsApplicable(add_float_30, context.get(), fact_manager)); + transformation::Apply(add_float_30, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_FALSE(transformation::IsApplicable(bad_add_float_30_id_already_used, + 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 "x" + OpName %12 "y" + OpName %16 "z" + OpDecorate %8 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpTypeInt 32 0 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 2 + %14 = OpTypeFloat 32 + %15 = OpTypePointer Function %14 + %17 = OpConstant %14 3 + %100 = OpConstant %6 1 + %101 = OpConstant %6 10 + %102 = OpConstant %10 2 + %103 = OpConstant %10 20 + %104 = OpConstant %14 3 + %105 = OpConstant %14 30 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %16 = OpVariable %15 Function + OpStore %8 %9 + OpStore %12 %13 + OpStore %16 %17 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp new file mode 100644 index 000000000..b664a5991 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp @@ -0,0 +1,2261 @@ +// 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_dead_break.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddDeadBreakTest, BreaksOutOfSimpleIf) { + // For a simple if-then-else, checks that some dead break scenarios are + // possible, and sanity-checks that some illegal scenarios are indeed not + // allowed. + + // The SPIR-V for this test is adapted from the following GLSL, by separating + // some assignments into their own basic blocks, and adding constants for true + // and false: + // + // void main() { + // int x; + // int y; + // x = 1; + // if (x < y) { + // x = 2; + // x = 3; + // } else { + // y = 2; + // y = 3; + // } + // x = y; + // } + + 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 %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %25 = OpConstantTrue %13 + %26 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %19 + %15 = OpLabel + OpStore %8 %17 + OpBranch %21 + %21 = OpLabel + OpStore %8 %18 + OpBranch %22 + %22 = OpLabel + OpBranch %16 + %19 = OpLabel + OpStore %11 %17 + OpBranch %23 + %23 = OpLabel + OpStore %11 %18 + OpBranch %24 + %24 = OpLabel + OpBranch %16 + %16 = OpLabel + %20 = OpLoad %6 %11 + OpStore %8 %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; + + const uint32_t merge_block = 16; + + // These are all possibilities. + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(15, merge_block, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(15, merge_block, false, + {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(21, merge_block, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(21, merge_block, false, + {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(22, merge_block, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(22, merge_block, false, + {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(19, merge_block, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(19, merge_block, false, + {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, merge_block, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, merge_block, false, + {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(24, merge_block, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(24, merge_block, false, + {}), + context.get(), fact_manager)); + + // Inapplicable: 100 is not a block id. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(100, merge_block, true, + {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(15, 100, true, {}), + context.get(), fact_manager)); + + // Inapplicable: 24 is not a merge block. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(15, 24, true, {}), + context.get(), fact_manager)); + + // These are the transformations we will apply. + auto transformation1 = + transformation::MakeTransformationAddDeadBreak(15, merge_block, true, {}); + auto transformation2 = transformation::MakeTransformationAddDeadBreak( + 21, merge_block, false, {}); + auto transformation3 = + transformation::MakeTransformationAddDeadBreak(22, merge_block, true, {}); + auto transformation4 = transformation::MakeTransformationAddDeadBreak( + 19, merge_block, false, {}); + auto transformation5 = + transformation::MakeTransformationAddDeadBreak(23, merge_block, true, {}); + auto transformation6 = transformation::MakeTransformationAddDeadBreak( + 24, merge_block, false, {}); + + ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(), + fact_manager)); + transformation::Apply(transformation1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(), + fact_manager)); + transformation::Apply(transformation2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(), + fact_manager)); + transformation::Apply(transformation3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(), + fact_manager)); + transformation::Apply(transformation4, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(), + fact_manager)); + transformation::Apply(transformation5, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(), + fact_manager)); + transformation::Apply(transformation6, 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 %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %25 = OpConstantTrue %13 + %26 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %19 + %15 = OpLabel + OpStore %8 %17 + OpBranchConditional %25 %21 %16 + %21 = OpLabel + OpStore %8 %18 + OpBranchConditional %26 %16 %22 + %22 = OpLabel + OpBranchConditional %25 %16 %16 + %19 = OpLabel + OpStore %11 %17 + OpBranchConditional %26 %16 %23 + %23 = OpLabel + OpStore %11 %18 + OpBranchConditional %25 %24 %16 + %24 = OpLabel + OpBranchConditional %26 %16 %16 + %16 = OpLabel + %20 = OpLoad %6 %11 + OpStore %8 %20 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, BreakOutOfNestedIfs) { + // Checks some allowed and disallowed scenarios for nests of ifs. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // int x; + // int y; + // x = 1; + // if (x < y) { + // x = 2; + // x = 3; + // if (x == y) { + // y = 3; + // } + // } else { + // y = 2; + // y = 3; + // } + // if (x == y) { + // x = 2; + // } + // x = y; + // } + + 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 %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %31 = OpConstantTrue %13 + %32 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %24 + %15 = OpLabel + OpStore %8 %17 + OpBranch %33 + %33 = OpLabel + OpStore %8 %18 + %19 = OpLoad %6 %8 + OpBranch %34 + %34 = OpLabel + %20 = OpLoad %6 %11 + %21 = OpIEqual %13 %19 %20 + OpSelectionMerge %23 None + OpBranchConditional %21 %22 %23 + %22 = OpLabel + OpStore %11 %18 + OpBranch %35 + %35 = OpLabel + OpBranch %23 + %23 = OpLabel + OpBranch %16 + %24 = OpLabel + OpStore %11 %17 + OpBranch %36 + %36 = OpLabel + OpStore %11 %18 + OpBranch %16 + %16 = OpLabel + %25 = OpLoad %6 %8 + OpBranch %37 + %37 = OpLabel + %26 = OpLoad %6 %11 + %27 = OpIEqual %13 %25 %26 + OpSelectionMerge %29 None + OpBranchConditional %27 %28 %29 + %28 = OpLabel + OpStore %8 %17 + OpBranch %38 + %38 = OpLabel + OpBranch %29 + %29 = OpLabel + %30 = OpLoad %6 %11 + OpStore %8 %30 + 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; + + // The header and merge blocks + const uint32_t header_inner = 34; + const uint32_t merge_inner = 23; + const uint32_t header_outer = 5; + const uint32_t merge_outer = 16; + const uint32_t header_after = 37; + const uint32_t merge_after = 29; + + // The non-merge-nor-header blocks in each construct + const uint32_t inner_block_1 = 22; + const uint32_t inner_block_2 = 35; + const uint32_t outer_block_1 = 15; + const uint32_t outer_block_2 = 33; + const uint32_t outer_block_3 = 24; + const uint32_t outer_block_4 = 36; + const uint32_t after_block_1 = 28; + const uint32_t after_block_2 = 38; + + // Fine to break from a construct to its merge + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(inner_block_1, merge_inner, + true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(inner_block_2, merge_inner, + false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_1, merge_outer, + true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_2, merge_outer, + false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_3, merge_outer, + true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_4, merge_outer, + false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(after_block_1, merge_after, + true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(after_block_2, merge_after, + false, {}), + context.get(), fact_manager)); + + // Not OK to break to the wrong merge (whether enclosing or not) + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(inner_block_1, merge_outer, + true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(inner_block_2, merge_after, + false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_1, merge_inner, + true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_2, merge_after, + false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(after_block_1, merge_inner, + true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(after_block_2, merge_outer, + false, {}), + context.get(), fact_manager)); + + // Not OK to break from header (as it does not branch unconditionally) + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_inner, merge_inner, + true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_outer, merge_outer, + false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_after, merge_after, + true, {}), + context.get(), fact_manager)); + + // Not OK to break to non-merge + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(inner_block_1, + inner_block_2, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_2, + after_block_1, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(outer_block_1, + header_after, true, {}), + context.get(), fact_manager)); + + auto transformation1 = transformation::MakeTransformationAddDeadBreak( + inner_block_1, merge_inner, true, {}); + auto transformation2 = transformation::MakeTransformationAddDeadBreak( + inner_block_2, merge_inner, false, {}); + auto transformation3 = transformation::MakeTransformationAddDeadBreak( + outer_block_1, merge_outer, true, {}); + auto transformation4 = transformation::MakeTransformationAddDeadBreak( + outer_block_2, merge_outer, false, {}); + auto transformation5 = transformation::MakeTransformationAddDeadBreak( + outer_block_3, merge_outer, true, {}); + auto transformation6 = transformation::MakeTransformationAddDeadBreak( + outer_block_4, merge_outer, false, {}); + auto transformation7 = transformation::MakeTransformationAddDeadBreak( + after_block_1, merge_after, true, {}); + auto transformation8 = transformation::MakeTransformationAddDeadBreak( + after_block_2, merge_after, false, {}); + + ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(), + fact_manager)); + transformation::Apply(transformation1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(), + fact_manager)); + transformation::Apply(transformation2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(), + fact_manager)); + transformation::Apply(transformation3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(), + fact_manager)); + transformation::Apply(transformation4, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(), + fact_manager)); + transformation::Apply(transformation5, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(), + fact_manager)); + transformation::Apply(transformation6, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation7, context.get(), + fact_manager)); + transformation::Apply(transformation7, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation8, context.get(), + fact_manager)); + transformation::Apply(transformation8, 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 %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %31 = OpConstantTrue %13 + %32 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %24 + %15 = OpLabel + OpStore %8 %17 + OpBranchConditional %31 %33 %16 + %33 = OpLabel + OpStore %8 %18 + %19 = OpLoad %6 %8 + OpBranchConditional %32 %16 %34 + %34 = OpLabel + %20 = OpLoad %6 %11 + %21 = OpIEqual %13 %19 %20 + OpSelectionMerge %23 None + OpBranchConditional %21 %22 %23 + %22 = OpLabel + OpStore %11 %18 + OpBranchConditional %31 %35 %23 + %35 = OpLabel + OpBranchConditional %32 %23 %23 + %23 = OpLabel + OpBranch %16 + %24 = OpLabel + OpStore %11 %17 + OpBranchConditional %31 %36 %16 + %36 = OpLabel + OpStore %11 %18 + OpBranchConditional %32 %16 %16 + %16 = OpLabel + %25 = OpLoad %6 %8 + OpBranch %37 + %37 = OpLabel + %26 = OpLoad %6 %11 + %27 = OpIEqual %13 %25 %26 + OpSelectionMerge %29 None + OpBranchConditional %27 %28 %29 + %28 = OpLabel + OpStore %8 %17 + OpBranchConditional %31 %38 %29 + %38 = OpLabel + OpBranchConditional %32 %29 %29 + %29 = OpLabel + %30 = OpLoad %6 %11 + OpStore %8 %30 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, BreakOutOfNestedSwitches) { + // Checks some allowed and disallowed scenarios for nests of switches. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // int x; + // int y; + // x = 1; + // if (x < y) { + // switch (x) { + // case 0: + // case 1: + // if (x == y) { + // } + // x = 2; + // break; + // case 3: + // if (y == 4) { + // y = 2; + // x = 3; + // } + // case 10: + // break; + // default: + // switch (y) { + // case 1: + // break; + // case 2: + // x = 4; + // y = 2; + // default: + // x = 3; + // break; + // } + // } + // } else { + // switch (y) { + // case 1: + // x = 4; + // case 2: + // y = 3; + // default: + // x = y; + // break; + // } + // } + // } + + 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 %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %29 = OpConstant %6 2 + %32 = OpConstant %6 4 + %36 = OpConstant %6 3 + %60 = OpConstantTrue %13 + %61 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %47 + %15 = OpLabel + %17 = OpLoad %6 %8 + OpSelectionMerge %22 None + OpSwitch %17 %21 0 %18 1 %18 3 %19 10 %20 + %21 = OpLabel + %38 = OpLoad %6 %11 + OpSelectionMerge %42 None + OpSwitch %38 %41 1 %39 2 %40 + %41 = OpLabel + OpStore %8 %36 + OpBranch %42 + %39 = OpLabel + OpBranch %42 + %40 = OpLabel + OpStore %8 %32 + OpStore %11 %29 + OpBranch %41 + %42 = OpLabel + OpBranch %22 + %18 = OpLabel + %23 = OpLoad %6 %8 + OpBranch %63 + %63 = OpLabel + %24 = OpLoad %6 %11 + %25 = OpIEqual %13 %23 %24 + OpSelectionMerge %27 None + OpBranchConditional %25 %26 %27 + %26 = OpLabel + OpBranch %27 + %27 = OpLabel + OpStore %8 %29 + OpBranch %22 + %19 = OpLabel + %31 = OpLoad %6 %11 + %33 = OpIEqual %13 %31 %32 + OpSelectionMerge %35 None + OpBranchConditional %33 %34 %35 + %34 = OpLabel + OpStore %11 %29 + OpBranch %62 + %62 = OpLabel + OpStore %8 %36 + OpBranch %35 + %35 = OpLabel + OpBranch %20 + %20 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %16 + %47 = OpLabel + %48 = OpLoad %6 %11 + OpSelectionMerge %52 None + OpSwitch %48 %51 1 %49 2 %50 + %51 = OpLabel + %53 = OpLoad %6 %11 + OpStore %8 %53 + OpBranch %52 + %49 = OpLabel + OpStore %8 %32 + OpBranch %50 + %50 = OpLabel + OpStore %11 %36 + OpBranch %51 + %52 = OpLabel + OpBranch %16 + %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; + + // The header and merge blocks + const uint32_t header_outer_if = 5; + const uint32_t merge_outer_if = 16; + const uint32_t header_then_outer_switch = 15; + const uint32_t merge_then_outer_switch = 22; + const uint32_t header_then_inner_switch = 21; + const uint32_t merge_then_inner_switch = 42; + const uint32_t header_else_switch = 47; + const uint32_t merge_else_switch = 52; + const uint32_t header_inner_if_1 = 19; + const uint32_t merge_inner_if_1 = 35; + const uint32_t header_inner_if_2 = 63; + const uint32_t merge_inner_if_2 = 27; + + // The non-merge-nor-header blocks in each construct + const uint32_t then_outer_switch_block_1 = 18; + const uint32_t then_inner_switch_block_1 = 39; + const uint32_t then_inner_switch_block_2 = 40; + const uint32_t then_inner_switch_block_3 = 41; + const uint32_t else_switch_block_1 = 49; + const uint32_t else_switch_block_2 = 50; + const uint32_t else_switch_block_3 = 51; + const uint32_t inner_if_1_block_1 = 34; + const uint32_t inner_if_1_block_2 = 62; + const uint32_t inner_if_2_block_1 = 26; + + // Fine to branch straight to direct merge block for a construct + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + then_outer_switch_block_1, merge_then_outer_switch, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + then_inner_switch_block_1, merge_then_inner_switch, false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + then_inner_switch_block_2, merge_then_inner_switch, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + then_inner_switch_block_3, merge_then_inner_switch, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + else_switch_block_1, merge_else_switch, false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + else_switch_block_2, merge_else_switch, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + else_switch_block_3, merge_else_switch, false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + inner_if_1_block_1, merge_inner_if_1, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + inner_if_1_block_2, merge_inner_if_1, false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + inner_if_2_block_1, merge_inner_if_2, true, {}), + context.get(), fact_manager)); + + // Not OK to break out of a switch from a selection construct inside the + // switch. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + inner_if_1_block_1, merge_then_outer_switch, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + inner_if_1_block_2, merge_then_outer_switch, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + inner_if_2_block_1, merge_then_outer_switch, true, {}), + context.get(), fact_manager)); + + // Some miscellaneous inapplicable cases. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_outer_if, + merge_outer_if, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + header_inner_if_1, inner_if_1_block_2, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + header_then_inner_switch, header_then_outer_switch, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + header_else_switch, then_inner_switch_block_3, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + header_inner_if_2, header_inner_if_2, false, {}), + context.get(), fact_manager)); + + auto transformation1 = transformation::MakeTransformationAddDeadBreak( + then_outer_switch_block_1, merge_then_outer_switch, true, {}); + auto transformation2 = transformation::MakeTransformationAddDeadBreak( + then_inner_switch_block_1, merge_then_inner_switch, false, {}); + auto transformation3 = transformation::MakeTransformationAddDeadBreak( + then_inner_switch_block_2, merge_then_inner_switch, true, {}); + auto transformation4 = transformation::MakeTransformationAddDeadBreak( + then_inner_switch_block_3, merge_then_inner_switch, true, {}); + auto transformation5 = transformation::MakeTransformationAddDeadBreak( + else_switch_block_1, merge_else_switch, false, {}); + auto transformation6 = transformation::MakeTransformationAddDeadBreak( + else_switch_block_2, merge_else_switch, true, {}); + auto transformation7 = transformation::MakeTransformationAddDeadBreak( + else_switch_block_3, merge_else_switch, false, {}); + auto transformation8 = transformation::MakeTransformationAddDeadBreak( + inner_if_1_block_1, merge_inner_if_1, true, {}); + auto transformation9 = transformation::MakeTransformationAddDeadBreak( + inner_if_1_block_2, merge_inner_if_1, false, {}); + auto transformation10 = transformation::MakeTransformationAddDeadBreak( + inner_if_2_block_1, merge_inner_if_2, true, {}); + + ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(), + fact_manager)); + transformation::Apply(transformation1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(), + fact_manager)); + transformation::Apply(transformation2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(), + fact_manager)); + transformation::Apply(transformation3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(), + fact_manager)); + transformation::Apply(transformation4, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(), + fact_manager)); + transformation::Apply(transformation5, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(), + fact_manager)); + transformation::Apply(transformation6, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation7, context.get(), + fact_manager)); + transformation::Apply(transformation7, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation8, context.get(), + fact_manager)); + transformation::Apply(transformation8, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation9, context.get(), + fact_manager)); + transformation::Apply(transformation9, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation10, context.get(), + fact_manager)); + transformation::Apply(transformation10, 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 %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %29 = OpConstant %6 2 + %32 = OpConstant %6 4 + %36 = OpConstant %6 3 + %60 = OpConstantTrue %13 + %61 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %47 + %15 = OpLabel + %17 = OpLoad %6 %8 + OpSelectionMerge %22 None + OpSwitch %17 %21 0 %18 1 %18 3 %19 10 %20 + %21 = OpLabel + %38 = OpLoad %6 %11 + OpSelectionMerge %42 None + OpSwitch %38 %41 1 %39 2 %40 + %41 = OpLabel + OpStore %8 %36 + OpBranchConditional %60 %42 %42 + %39 = OpLabel + OpBranchConditional %61 %42 %42 + %40 = OpLabel + OpStore %8 %32 + OpStore %11 %29 + OpBranchConditional %60 %41 %42 + %42 = OpLabel + OpBranch %22 + %18 = OpLabel + %23 = OpLoad %6 %8 + OpBranchConditional %60 %63 %22 + %63 = OpLabel + %24 = OpLoad %6 %11 + %25 = OpIEqual %13 %23 %24 + OpSelectionMerge %27 None + OpBranchConditional %25 %26 %27 + %26 = OpLabel + OpBranchConditional %60 %27 %27 + %27 = OpLabel + OpStore %8 %29 + OpBranch %22 + %19 = OpLabel + %31 = OpLoad %6 %11 + %33 = OpIEqual %13 %31 %32 + OpSelectionMerge %35 None + OpBranchConditional %33 %34 %35 + %34 = OpLabel + OpStore %11 %29 + OpBranchConditional %60 %62 %35 + %62 = OpLabel + OpStore %8 %36 + OpBranchConditional %61 %35 %35 + %35 = OpLabel + OpBranch %20 + %20 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %16 + %47 = OpLabel + %48 = OpLoad %6 %11 + OpSelectionMerge %52 None + OpSwitch %48 %51 1 %49 2 %50 + %51 = OpLabel + %53 = OpLoad %6 %11 + OpStore %8 %53 + OpBranchConditional %61 %52 %52 + %49 = OpLabel + OpStore %8 %32 + OpBranchConditional %61 %52 %50 + %50 = OpLabel + OpStore %11 %36 + OpBranchConditional %60 %51 %52 + %52 = OpLabel + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, BreakOutOfLoopNest) { + // Checks some allowed and disallowed scenarios for a nest of loops, including + // breaking from an if or switch right out of a loop. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // int x, y; + // do { + // x++; + // for (int j = 0; j < 100; j++) { + // y++; + // if (x == y) { + // x++; + // if (x == 2) { + // y++; + // } + // switch (x) { + // case 0: + // x = 2; + // default: + // break; + // } + // } + // } + // } while (x > y); + // + // for (int i = 0; i < 100; i++) { + // x++; + // } + // } + + 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 %12 "x" + OpName %16 "j" + OpName %27 "y" + OpName %55 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %14 = OpConstant %10 1 + %17 = OpConstant %10 0 + %24 = OpConstant %10 100 + %25 = OpTypeBool + %38 = OpConstant %10 2 + %67 = OpConstantTrue %25 + %68 = OpConstantFalse %25 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %11 Function + %16 = OpVariable %11 Function + %27 = OpVariable %11 Function + %55 = OpVariable %11 Function + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + %13 = OpLoad %10 %12 + %15 = OpIAdd %10 %13 %14 + OpStore %12 %15 + OpStore %16 %17 + OpBranch %18 + %18 = OpLabel + OpLoopMerge %20 %21 None + OpBranch %22 + %22 = OpLabel + %23 = OpLoad %10 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %28 = OpLoad %10 %27 + %29 = OpIAdd %10 %28 %14 + OpStore %27 %29 + %30 = OpLoad %10 %12 + %31 = OpLoad %10 %27 + %32 = OpIEqual %25 %30 %31 + OpSelectionMerge %34 None + OpBranchConditional %32 %33 %34 + %33 = OpLabel + %35 = OpLoad %10 %12 + %36 = OpIAdd %10 %35 %14 + OpStore %12 %36 + %37 = OpLoad %10 %12 + %39 = OpIEqual %25 %37 %38 + OpSelectionMerge %41 None + OpBranchConditional %39 %40 %41 + %40 = OpLabel + %42 = OpLoad %10 %27 + %43 = OpIAdd %10 %42 %14 + OpStore %27 %43 + OpBranch %41 + %41 = OpLabel + %44 = OpLoad %10 %12 + OpSelectionMerge %47 None + OpSwitch %44 %46 0 %45 + %46 = OpLabel + OpBranch %47 + %45 = OpLabel + OpStore %12 %38 + OpBranch %46 + %47 = OpLabel + OpBranch %34 + %34 = OpLabel + OpBranch %21 + %21 = OpLabel + %50 = OpLoad %10 %16 + %51 = OpIAdd %10 %50 %14 + OpStore %16 %51 + OpBranch %18 + %20 = OpLabel + OpBranch %9 + %9 = OpLabel + %52 = OpLoad %10 %12 + %53 = OpLoad %10 %27 + %54 = OpSGreaterThan %25 %52 %53 + OpBranchConditional %54 %6 %8 + %8 = OpLabel + OpStore %55 %17 + OpBranch %56 + %56 = OpLabel + OpLoopMerge %58 %59 None + OpBranch %60 + %60 = OpLabel + %61 = OpLoad %10 %55 + %62 = OpSLessThan %25 %61 %24 + OpBranchConditional %62 %57 %58 + %57 = OpLabel + %63 = OpLoad %10 %12 + %64 = OpIAdd %10 %63 %14 + OpStore %12 %64 + OpBranch %59 + %59 = OpLabel + %65 = OpLoad %10 %55 + %66 = OpIAdd %10 %65 %14 + OpStore %55 %66 + OpBranch %56 + %58 = 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; + + // The header and merge blocks + const uint32_t header_do_while = 6; + const uint32_t merge_do_while = 8; + const uint32_t header_for_j = 18; + const uint32_t merge_for_j = 20; + const uint32_t header_for_i = 56; + const uint32_t merge_for_i = 58; + const uint32_t header_switch = 41; + const uint32_t merge_switch = 47; + const uint32_t header_if_x_eq_y = 19; + const uint32_t merge_if_x_eq_y = 34; + const uint32_t header_if_x_eq_2 = 33; + const uint32_t merge_if_x_eq_2 = 41; + + // Loop continue targets + const uint32_t continue_do_while = 9; + const uint32_t continue_for_j = 21; + const uint32_t continue_for_i = 59; + + // Some blocks in these constructs + const uint32_t block_in_inner_if = 40; + const uint32_t block_switch_case = 46; + const uint32_t block_switch_default = 45; + const uint32_t block_in_for_i_loop = 57; + + // Fine to break from any loop header to its merge + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_do_while, + merge_do_while, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_for_i, merge_for_i, + false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_for_j, merge_for_j, + true, {}), + context.get(), fact_manager)); + + // Fine to break from any of the blocks in constructs in the "for j" loop to + // that loop's merge + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_in_inner_if, + merge_for_j, false, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_switch_case, + merge_for_j, true, {}), + context.get(), fact_manager)); + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_switch_default, + merge_for_j, false, {}), + context.get(), fact_manager)); + + // Fine to break from the body of the "for i" loop to that loop's merge + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_in_for_i_loop, + merge_for_i, true, {}), + context.get(), fact_manager)); + + // Not OK to break from multiple loops + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_in_inner_if, + merge_do_while, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_switch_case, + merge_do_while, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_switch_default, + merge_do_while, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_for_j, + merge_do_while, true, {}), + context.get(), fact_manager)); + + // Not OK to break loop from its continue construct + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(continue_do_while, + merge_do_while, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(continue_for_j, + merge_for_j, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(continue_for_i, + merge_for_i, true, {}), + context.get(), fact_manager)); + + // Not OK to break out of multiple non-loop constructs if not breaking to a + // loop merge + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + block_in_inner_if, merge_if_x_eq_y, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(block_switch_case, + merge_if_x_eq_y, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + block_switch_default, merge_if_x_eq_y, false, {}), + context.get(), fact_manager)); + + // Some miscellaneous inapplicable transformations + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + header_if_x_eq_2, header_if_x_eq_y, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(merge_if_x_eq_2, + merge_switch, false, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(header_switch, + header_switch, false, {}), + context.get(), fact_manager)); + + auto transformation1 = transformation::MakeTransformationAddDeadBreak( + header_do_while, merge_do_while, true, {}); + auto transformation2 = transformation::MakeTransformationAddDeadBreak( + header_for_i, merge_for_i, false, {}); + auto transformation3 = transformation::MakeTransformationAddDeadBreak( + header_for_j, merge_for_j, true, {}); + auto transformation4 = transformation::MakeTransformationAddDeadBreak( + block_in_inner_if, merge_for_j, false, {}); + auto transformation5 = transformation::MakeTransformationAddDeadBreak( + block_switch_case, merge_for_j, true, {}); + auto transformation6 = transformation::MakeTransformationAddDeadBreak( + block_switch_default, merge_for_j, false, {}); + auto transformation7 = transformation::MakeTransformationAddDeadBreak( + block_in_for_i_loop, merge_for_i, true, {}); + + ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(), + fact_manager)); + transformation::Apply(transformation1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(), + fact_manager)); + transformation::Apply(transformation2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(), + fact_manager)); + transformation::Apply(transformation3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(), + fact_manager)); + transformation::Apply(transformation4, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(), + fact_manager)); + transformation::Apply(transformation5, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(), + fact_manager)); + transformation::Apply(transformation6, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation7, context.get(), + fact_manager)); + transformation::Apply(transformation7, 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 %12 "x" + OpName %16 "j" + OpName %27 "y" + OpName %55 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %14 = OpConstant %10 1 + %17 = OpConstant %10 0 + %24 = OpConstant %10 100 + %25 = OpTypeBool + %38 = OpConstant %10 2 + %67 = OpConstantTrue %25 + %68 = OpConstantFalse %25 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %11 Function + %16 = OpVariable %11 Function + %27 = OpVariable %11 Function + %55 = OpVariable %11 Function + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranchConditional %67 %7 %8 + %7 = OpLabel + %13 = OpLoad %10 %12 + %15 = OpIAdd %10 %13 %14 + OpStore %12 %15 + OpStore %16 %17 + OpBranch %18 + %18 = OpLabel + OpLoopMerge %20 %21 None + OpBranchConditional %67 %22 %20 + %22 = OpLabel + %23 = OpLoad %10 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %28 = OpLoad %10 %27 + %29 = OpIAdd %10 %28 %14 + OpStore %27 %29 + %30 = OpLoad %10 %12 + %31 = OpLoad %10 %27 + %32 = OpIEqual %25 %30 %31 + OpSelectionMerge %34 None + OpBranchConditional %32 %33 %34 + %33 = OpLabel + %35 = OpLoad %10 %12 + %36 = OpIAdd %10 %35 %14 + OpStore %12 %36 + %37 = OpLoad %10 %12 + %39 = OpIEqual %25 %37 %38 + OpSelectionMerge %41 None + OpBranchConditional %39 %40 %41 + %40 = OpLabel + %42 = OpLoad %10 %27 + %43 = OpIAdd %10 %42 %14 + OpStore %27 %43 + OpBranchConditional %68 %20 %41 + %41 = OpLabel + %44 = OpLoad %10 %12 + OpSelectionMerge %47 None + OpSwitch %44 %46 0 %45 + %46 = OpLabel + OpBranchConditional %67 %47 %20 + %45 = OpLabel + OpStore %12 %38 + OpBranchConditional %68 %20 %46 + %47 = OpLabel + OpBranch %34 + %34 = OpLabel + OpBranch %21 + %21 = OpLabel + %50 = OpLoad %10 %16 + %51 = OpIAdd %10 %50 %14 + OpStore %16 %51 + OpBranch %18 + %20 = OpLabel + OpBranch %9 + %9 = OpLabel + %52 = OpLoad %10 %12 + %53 = OpLoad %10 %27 + %54 = OpSGreaterThan %25 %52 %53 + OpBranchConditional %54 %6 %8 + %8 = OpLabel + OpStore %55 %17 + OpBranch %56 + %56 = OpLabel + OpLoopMerge %58 %59 None + OpBranchConditional %68 %58 %60 + %60 = OpLabel + %61 = OpLoad %10 %55 + %62 = OpSLessThan %25 %61 %24 + OpBranchConditional %62 %57 %58 + %57 = OpLabel + %63 = OpLoad %10 %12 + %64 = OpIAdd %10 %63 %14 + OpStore %12 %64 + OpBranchConditional %67 %59 %58 + %59 = OpLabel + %65 = OpLoad %10 %55 + %66 = OpIAdd %10 %65 %14 + OpStore %55 %66 + OpBranch %56 + %58 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, NoBreakFromContinueConstruct) { + // Checks that it is illegal to break straight from a continue construct. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // for (int i = 0; i < 100; i++) { + // } + // } + + 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" + OpDecorate %8 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %21 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %22 = OpConstantTrue %17 + %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 + OpBranch %23 + %23 = OpLabel + OpStore %8 %21 + 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); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not OK to break loop from its continue construct + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(13, 12, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 12, true, {}), + context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, SelectionInContinueConstruct) { + // Considers some scenarios where there is a selection construct in a loop's + // continue construct. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // for (int i = 0; i < 100; i = (i < 50 ? i + 2 : i + 1)) { + // } + // } + + 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 + %99 = OpConstantTrue %17 + %20 = OpConstant %6 50 + %26 = OpConstant %6 2 + %30 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %22 = 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 = OpSLessThan %17 %19 %20 + OpSelectionMerge %24 None + OpBranchConditional %21 %23 %28 + %23 = OpLabel + %25 = OpLoad %6 %8 + OpBranch %100 + %100 = OpLabel + %27 = OpIAdd %6 %25 %26 + OpStore %22 %27 + OpBranch %24 + %28 = OpLabel + %29 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + %31 = OpIAdd %6 %29 %30 + OpStore %22 %31 + OpBranch %24 + %24 = OpLabel + %32 = OpLoad %6 %22 + OpStore %8 %32 + 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); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + const uint32_t loop_merge = 12; + const uint32_t selection_merge = 24; + const uint32_t in_selection_1 = 23; + const uint32_t in_selection_2 = 100; + const uint32_t in_selection_3 = 28; + const uint32_t in_selection_4 = 101; + + // Not OK to jump from the selection to the loop merge, as this would break + // from the loop's continue construct. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(in_selection_1, loop_merge, + true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(in_selection_2, loop_merge, + true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(in_selection_3, loop_merge, + true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(in_selection_4, loop_merge, + true, {}), + context.get(), fact_manager)); + + // But fine to jump from the selection to its merge. + + auto transformation1 = transformation::MakeTransformationAddDeadBreak( + in_selection_1, selection_merge, true, {}); + auto transformation2 = transformation::MakeTransformationAddDeadBreak( + in_selection_2, selection_merge, true, {}); + auto transformation3 = transformation::MakeTransformationAddDeadBreak( + in_selection_3, selection_merge, true, {}); + auto transformation4 = transformation::MakeTransformationAddDeadBreak( + in_selection_4, selection_merge, true, {}); + + ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(), + fact_manager)); + transformation::Apply(transformation1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(), + fact_manager)); + transformation::Apply(transformation2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(), + fact_manager)); + transformation::Apply(transformation3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(), + fact_manager)); + transformation::Apply(transformation4, 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 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %99 = OpConstantTrue %17 + %20 = OpConstant %6 50 + %26 = OpConstant %6 2 + %30 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %22 = 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 = OpSLessThan %17 %19 %20 + OpSelectionMerge %24 None + OpBranchConditional %21 %23 %28 + %23 = OpLabel + %25 = OpLoad %6 %8 + OpBranchConditional %99 %100 %24 + %100 = OpLabel + %27 = OpIAdd %6 %25 %26 + OpStore %22 %27 + OpBranchConditional %99 %24 %24 + %28 = OpLabel + %29 = OpLoad %6 %8 + OpBranchConditional %99 %101 %24 + %101 = OpLabel + %31 = OpIAdd %6 %29 %30 + OpStore %22 %31 + OpBranchConditional %99 %24 %24 + %24 = OpLabel + %32 = OpLoad %6 %22 + OpStore %8 %32 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, LoopInContinueConstruct) { + // Considers some scenarios where there is a loop in a loop's continue + // construct. + + // The SPIR-V for this test is adapted from the following GLSL, with inlining + // applied so that the loop from foo is in the main loop's continue construct: + // + // int foo() { + // int result = 0; + // for (int j = 0; j < 10; j++) { + // result++; + // } + // return result; + // } + // + // void main() { + // for (int i = 0; i < 100; i += foo()) { + // } + // } + + 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 %31 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %20 = OpConstant %6 10 + %21 = OpTypeBool + %100 = OpConstantTrue %21 + %24 = OpConstant %6 1 + %38 = OpConstant %6 100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %43 = OpVariable %10 Function + %44 = OpVariable %10 Function + %45 = OpVariable %10 Function + %31 = OpVariable %10 Function + OpStore %31 %12 + OpBranch %32 + %32 = OpLabel + OpLoopMerge %34 %35 None + OpBranch %36 + %36 = OpLabel + %37 = OpLoad %6 %31 + %39 = OpSLessThan %21 %37 %38 + OpBranchConditional %39 %33 %34 + %33 = OpLabel + OpBranch %35 + %35 = OpLabel + OpStore %43 %12 + OpStore %44 %12 + OpBranch %46 + %46 = OpLabel + OpLoopMerge %47 %48 None + OpBranch %49 + %49 = OpLabel + %50 = OpLoad %6 %44 + %51 = OpSLessThan %21 %50 %20 + OpBranchConditional %51 %52 %47 + %52 = OpLabel + %53 = OpLoad %6 %43 + OpBranch %101 + %101 = OpLabel + %54 = OpIAdd %6 %53 %24 + OpStore %43 %54 + OpBranch %48 + %48 = OpLabel + %55 = OpLoad %6 %44 + %56 = OpIAdd %6 %55 %24 + OpStore %44 %56 + OpBranch %46 + %47 = OpLabel + %57 = OpLoad %6 %43 + OpStore %45 %57 + %40 = OpLoad %6 %45 + %41 = OpLoad %6 %31 + %42 = OpIAdd %6 %41 %40 + OpStore %31 %42 + OpBranch %32 + %34 = 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; + + const uint32_t outer_loop_merge = 34; + const uint32_t outer_loop_block = 33; + const uint32_t inner_loop_merge = 47; + const uint32_t inner_loop_block = 52; + + // Some inapplicable cases + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + inner_loop_block, outer_loop_merge, true, {}), + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak( + outer_loop_block, inner_loop_merge, true, {}), + context.get(), fact_manager)); + + auto transformation1 = transformation::MakeTransformationAddDeadBreak( + inner_loop_block, inner_loop_merge, true, {}); + auto transformation2 = transformation::MakeTransformationAddDeadBreak( + outer_loop_block, outer_loop_merge, true, {}); + + ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(), + fact_manager)); + transformation::Apply(transformation1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(), + fact_manager)); + transformation::Apply(transformation2, 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 %31 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %20 = OpConstant %6 10 + %21 = OpTypeBool + %100 = OpConstantTrue %21 + %24 = OpConstant %6 1 + %38 = OpConstant %6 100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %43 = OpVariable %10 Function + %44 = OpVariable %10 Function + %45 = OpVariable %10 Function + %31 = OpVariable %10 Function + OpStore %31 %12 + OpBranch %32 + %32 = OpLabel + OpLoopMerge %34 %35 None + OpBranch %36 + %36 = OpLabel + %37 = OpLoad %6 %31 + %39 = OpSLessThan %21 %37 %38 + OpBranchConditional %39 %33 %34 + %33 = OpLabel + OpBranchConditional %100 %35 %34 + %35 = OpLabel + OpStore %43 %12 + OpStore %44 %12 + OpBranch %46 + %46 = OpLabel + OpLoopMerge %47 %48 None + OpBranch %49 + %49 = OpLabel + %50 = OpLoad %6 %44 + %51 = OpSLessThan %21 %50 %20 + OpBranchConditional %51 %52 %47 + %52 = OpLabel + %53 = OpLoad %6 %43 + OpBranchConditional %100 %101 %47 + %101 = OpLabel + %54 = OpIAdd %6 %53 %24 + OpStore %43 %54 + OpBranch %48 + %48 = OpLabel + %55 = OpLoad %6 %44 + %56 = OpIAdd %6 %55 %24 + OpStore %44 %56 + OpBranch %46 + %47 = OpLabel + %57 = OpLoad %6 %43 + OpStore %45 %57 + %40 = OpLoad %6 %45 + %41 = OpLoad %6 %31 + %42 = OpIAdd %6 %41 %40 + OpStore %31 %42 + OpBranch %32 + %34 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, PhiInstructions) { + // Checks that the transformation works in the presence of phi instructions. + + // The SPIR-V for this test is adapted from the following GLSL, with a bit of + // extra and artificial work to get some interesting uses of OpPhi: + // + // void main() { + // int x; int y; + // float f; + // x = 2; + // f = 3.0; + // if (x > y) { + // x = 3; + // f = 4.0; + // } else { + // x = x + 2; + // f = f + 10.0; + // } + // while (x < y) { + // x = x + 1; + // f = f + 1.0; + // } + // y = x; + // f = f + 3.0; + // } + + 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 %12 "f" + OpName %15 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %10 = OpTypeFloat 32 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 3 + %17 = OpTypeBool + %80 = OpConstantTrue %17 + %21 = OpConstant %6 3 + %22 = OpConstant %10 4 + %27 = OpConstant %10 10 + %38 = OpConstant %6 1 + %41 = OpConstant %10 1 + %46 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %15 = OpVariable %7 Function + OpStore %8 %9 + OpStore %12 %13 + %18 = OpSGreaterThan %17 %9 %46 + OpSelectionMerge %20 None + OpBranchConditional %18 %19 %23 + %19 = OpLabel + OpStore %8 %21 + OpStore %12 %22 + OpBranch %20 + %23 = OpLabel + %25 = OpIAdd %6 %9 %9 + OpStore %8 %25 + OpBranch %70 + %70 = OpLabel + %28 = OpFAdd %10 %13 %27 + OpStore %12 %28 + OpBranch %20 + %20 = OpLabel + %52 = OpPhi %10 %22 %19 %28 %70 + %48 = OpPhi %6 %21 %19 %25 %70 + OpBranch %29 + %29 = OpLabel + %51 = OpPhi %10 %52 %20 %42 %32 + %47 = OpPhi %6 %48 %20 %39 %32 + OpLoopMerge %31 %32 None + OpBranch %33 + %33 = OpLabel + %36 = OpSLessThan %17 %47 %46 + OpBranchConditional %36 %30 %31 + %30 = OpLabel + %39 = OpIAdd %6 %47 %38 + OpStore %8 %39 + OpBranch %75 + %75 = OpLabel + %42 = OpFAdd %10 %51 %41 + OpStore %12 %42 + OpBranch %32 + %32 = OpLabel + OpBranch %29 + %31 = OpLabel + %71 = OpPhi %6 %47 %33 + %72 = OpPhi %10 %51 %33 + OpStore %15 %71 + %45 = OpFAdd %10 %72 %13 + OpStore %12 %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; + + // Some inapplicable transformations + // Not applicable because there is already an edge 19->20, so the OpPhis at 20 + // do not need to be updated + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(19, 20, true, {13, 21}), + context.get(), fact_manager)); + // Not applicable because two OpPhis (not zero) need to be updated at 20 + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 20, true, {}), + context.get(), fact_manager)); + // Not applicable because two OpPhis (not just one) need to be updated at 20 + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 20, true, {13}), + context.get(), fact_manager)); + // Not applicable because only two OpPhis (not three) need to be updated at 20 + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 20, true, + {13, 21, 22}), + context.get(), fact_manager)); + // Not applicable because the given ids do not have types that match the + // OpPhis at 20, in order + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 20, true, {21, 13}), + context.get(), fact_manager)); + // Not applicable because id 23 is a label + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 20, true, {21, 23}), + context.get(), fact_manager)); + // Not applicable because 101 is not an id + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 20, true, {21, 101}), + context.get(), fact_manager)); + // Not applicable because ids 51 and 47 are not available at the end of block + // 23 + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(23, 20, true, {51, 47}), + context.get(), fact_manager)); + + // Not applicable because OpConstantFalse is not present in the module + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddDeadBreak(19, 20, false, {}), + context.get(), fact_manager)); + + auto transformation1 = + transformation::MakeTransformationAddDeadBreak(19, 20, true, {}); + auto transformation2 = + transformation::MakeTransformationAddDeadBreak(23, 20, true, {13, 21}); + auto transformation3 = + transformation::MakeTransformationAddDeadBreak(70, 20, true, {}); + auto transformation4 = + transformation::MakeTransformationAddDeadBreak(30, 31, true, {21, 13}); + auto transformation5 = + transformation::MakeTransformationAddDeadBreak(75, 31, true, {47, 51}); + + ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(), + fact_manager)); + transformation::Apply(transformation1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(), + fact_manager)); + transformation::Apply(transformation2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(), + fact_manager)); + transformation::Apply(transformation3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(), + fact_manager)); + transformation::Apply(transformation4, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(), + fact_manager)); + transformation::Apply(transformation5, 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 %12 "f" + OpName %15 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %10 = OpTypeFloat 32 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 3 + %17 = OpTypeBool + %80 = OpConstantTrue %17 + %21 = OpConstant %6 3 + %22 = OpConstant %10 4 + %27 = OpConstant %10 10 + %38 = OpConstant %6 1 + %41 = OpConstant %10 1 + %46 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %15 = OpVariable %7 Function + OpStore %8 %9 + OpStore %12 %13 + %18 = OpSGreaterThan %17 %9 %46 + OpSelectionMerge %20 None + OpBranchConditional %18 %19 %23 + %19 = OpLabel + OpStore %8 %21 + OpStore %12 %22 + OpBranchConditional %80 %20 %20 + %23 = OpLabel + %25 = OpIAdd %6 %9 %9 + OpStore %8 %25 + OpBranchConditional %80 %70 %20 + %70 = OpLabel + %28 = OpFAdd %10 %13 %27 + OpStore %12 %28 + OpBranchConditional %80 %20 %20 + %20 = OpLabel + %52 = OpPhi %10 %22 %19 %28 %70 %13 %23 + %48 = OpPhi %6 %21 %19 %25 %70 %21 %23 + OpBranch %29 + %29 = OpLabel + %51 = OpPhi %10 %52 %20 %42 %32 + %47 = OpPhi %6 %48 %20 %39 %32 + OpLoopMerge %31 %32 None + OpBranch %33 + %33 = OpLabel + %36 = OpSLessThan %17 %47 %46 + OpBranchConditional %36 %30 %31 + %30 = OpLabel + %39 = OpIAdd %6 %47 %38 + OpStore %8 %39 + OpBranchConditional %80 %75 %31 + %75 = OpLabel + %42 = OpFAdd %10 %51 %41 + OpStore %12 %42 + OpBranchConditional %80 %32 %31 + %32 = OpLabel + OpBranch %29 + %31 = OpLabel + %71 = OpPhi %6 %47 %33 %21 %30 %47 %75 + %72 = OpPhi %10 %51 %33 %13 %30 %51 %75 + OpStore %15 %71 + %45 = OpFAdd %10 %72 %13 + OpStore %12 %45 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp new file mode 100644 index 000000000..9d13d7363 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp @@ -0,0 +1,83 @@ +// 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_type_boolean.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeBooleanTest, 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" + %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, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not applicable because id 1 is already in use. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddTypeBoolean(1), context.get(), + fact_manager)); + + auto add_type_bool = transformation::MakeTransformationAddTypeBoolean(100); + ASSERT_TRUE( + transformation::IsApplicable(add_type_bool, context.get(), fact_manager)); + transformation::Apply(add_type_bool, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Not applicable as we already have this type now. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddTypeBoolean(101), 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 + %100 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp new file mode 100644 index 000000000..4c574189b --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp @@ -0,0 +1,84 @@ +// 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_type_float.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeFloatTest, 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" + %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, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not applicable because id 1 is already in use. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddTypeFloat(1, 32), context.get(), + fact_manager)); + + auto add_type_float_32 = + transformation::MakeTransformationAddTypeFloat(100, 32); + ASSERT_TRUE(transformation::IsApplicable(add_type_float_32, context.get(), + fact_manager)); + transformation::Apply(add_type_float_32, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Not applicable as we already have this type now. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddTypeFloat(101, 32), 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 + %100 = OpTypeFloat 32 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp new file mode 100644 index 000000000..a46e5ccee --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp @@ -0,0 +1,98 @@ +// 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_type_int.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeIntTest, 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" + %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, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not applicable because id 1 is already in use. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationAddTypeInt(1, 32, false), context.get(), + fact_manager)); + + auto add_type_signed_int_32 = + transformation::MakeTransformationAddTypeInt(100, 32, true); + auto add_type_unsigned_int_32 = + transformation::MakeTransformationAddTypeInt(101, 32, false); + auto add_type_signed_int_32_again = + transformation::MakeTransformationAddTypeInt(102, 32, true); + auto add_type_unsigned_int_32_again = + transformation::MakeTransformationAddTypeInt(103, 32, false); + + ASSERT_TRUE(transformation::IsApplicable(add_type_signed_int_32, + context.get(), fact_manager)); + transformation::Apply(add_type_signed_int_32, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation::IsApplicable(add_type_unsigned_int_32, + context.get(), fact_manager)); + transformation::Apply(add_type_unsigned_int_32, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Not applicable as we already have these types now. + ASSERT_FALSE(transformation::IsApplicable(add_type_signed_int_32_again, + context.get(), fact_manager)); + ASSERT_FALSE(transformation::IsApplicable(add_type_unsigned_int_32_again, + 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 + %100 = OpTypeInt 32 1 + %101 = OpTypeInt 32 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp new file mode 100644 index 000000000..122d007ae --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp @@ -0,0 +1,830 @@ +// 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_move_block_down.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationMoveBlockDownTest, NoMovePossible1) { + // Block 11 cannot be moved down as it dominates block 12. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %11 + %11 = OpLabel + OpStore %8 %9 + OpBranch %12 + %12 = OpLabel + OpStore %8 %10 + 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; + + auto transformation = transformation::MakeTransformationMoveBlockDown(11); + ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(), + fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, NoMovePossible2) { + // Block 5 cannot be moved down as it is the entry block. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpStore %8 %10 + OpReturn + %11 = 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; + + auto transformation = transformation::MakeTransformationMoveBlockDown(5); + ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(), + fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, NoMovePossible3) { + // Block 100 does not exist, so cannot be moved down. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %11 + %11 = OpLabel + OpStore %8 %9 + OpBranch %12 + %12 = OpLabel + OpStore %8 %10 + 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; + + auto transformation = transformation::MakeTransformationMoveBlockDown(100); + ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(), + fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, NoMovePossible4) { + // Block 12 is the last block in its function, so cannot be moved down. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %11 + %11 = OpLabel + OpStore %8 %9 + OpBranch %12 + %12 = OpLabel + OpStore %8 %10 + OpReturn + OpFunctionEnd + %13 = OpFunction %2 None %3 + %14 = 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; + + auto transformation = transformation::MakeTransformationMoveBlockDown(12); + ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(), + fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, MovePossible) { + // Block 11 can be moved down as it does not dominate block 12 (both are + // unreachable). + std::string before_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpStore %8 %10 + OpReturn + %11 = OpLabel + OpReturn + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + 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 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpStore %8 %10 + OpReturn + %12 = OpLabel + OpReturn + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, before_transformation, kFuzzAssembleOption); + + FactManager fact_manager; + + auto transformation = transformation::MakeTransformationMoveBlockDown(11); + ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(), + fact_manager)); + transformation::Apply(transformation, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationMoveBlockDownTest, ManyMovesPossible) { + // The SPIR-V arising from this shader has lots of opportunities for moving + // blocks around. + // + // void main() { + // int x; + // int y; + // if (x < y) { + // x = 1; + // if (y == x) { + // x = 3; + // } else { + // x = 4; + // } + // } else { + // if (y < x) { + // x = 5; + // } else { + // x = 6; + // } + // } + // } + + std::string before_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" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %17 RelaxedPrecision + OpDecorate %18 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpConstant %6 1 + %22 = OpConstant %6 3 + %24 = OpConstant %6 4 + %31 = OpConstant %6 5 + %33 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %13 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + OpStore %8 %16 + %17 = OpLoad %6 %10 + %18 = OpLoad %6 %8 + %19 = OpIEqual %12 %17 %18 + OpSelectionMerge %21 None + OpBranchConditional %19 %20 %23 + %20 = OpLabel + OpStore %8 %22 + OpBranch %21 + %23 = OpLabel + OpStore %8 %24 + OpBranch %21 + %21 = OpLabel + OpBranch %15 + %25 = OpLabel + %26 = OpLoad %6 %10 + %27 = OpLoad %6 %8 + %28 = OpSLessThan %12 %26 %27 + OpSelectionMerge %30 None + OpBranchConditional %28 %29 %32 + %29 = OpLabel + OpStore %8 %31 + OpBranch %30 + %32 = OpLabel + OpStore %8 %33 + OpBranch %30 + %30 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, before_transformation, kFuzzAssembleOption); + + FactManager fact_manager; + + // The block ids are: 5 14 20 23 21 25 29 32 30 15 + // We make a transformation to move each of them down, plus a transformation + // to move a non-block, 27, down. + auto move_down_5 = transformation::MakeTransformationMoveBlockDown(5); + auto move_down_14 = transformation::MakeTransformationMoveBlockDown(14); + auto move_down_20 = transformation::MakeTransformationMoveBlockDown(20); + auto move_down_23 = transformation::MakeTransformationMoveBlockDown(23); + auto move_down_21 = transformation::MakeTransformationMoveBlockDown(21); + auto move_down_25 = transformation::MakeTransformationMoveBlockDown(25); + auto move_down_29 = transformation::MakeTransformationMoveBlockDown(29); + auto move_down_32 = transformation::MakeTransformationMoveBlockDown(32); + auto move_down_30 = transformation::MakeTransformationMoveBlockDown(30); + auto move_down_15 = transformation::MakeTransformationMoveBlockDown(15); + auto move_down_27 = transformation::MakeTransformationMoveBlockDown(27); + + // Dominance is as follows: + // 5 dominates everything else + // 14 dominates 20, 23, 21 + // 20 dominates nothing + // 23 dominates nothing + // 21 dominates nothing + // 25 dominates 29, 32, 30 + // 29 dominates nothing + // 32 dominates nothing + // 30 dominates nothing + // 15 dominates nothing + + // Current ordering: 5 14 20 23 21 25 29 32 30 15 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + + // Let's bubble 20 all the way down. + + transformation::Apply(move_down_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 20 21 25 29 32 30 15 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + + transformation::Apply(move_down_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 20 25 29 32 30 15 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + + transformation::Apply(move_down_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 20 29 32 30 15 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + + transformation::Apply(move_down_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 29 20 32 30 15 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + + transformation::Apply(move_down_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 29 32 20 30 15 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + + transformation::Apply(move_down_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 29 32 30 20 15 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + + transformation::Apply(move_down_20, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_bubbling_20_down = 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 %9 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %17 RelaxedPrecision + OpDecorate %18 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpConstant %6 1 + %22 = OpConstant %6 3 + %24 = OpConstant %6 4 + %31 = OpConstant %6 5 + %33 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %13 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + OpStore %8 %16 + %17 = OpLoad %6 %10 + %18 = OpLoad %6 %8 + %19 = OpIEqual %12 %17 %18 + OpSelectionMerge %21 None + OpBranchConditional %19 %20 %23 + %23 = OpLabel + OpStore %8 %24 + OpBranch %21 + %21 = OpLabel + OpBranch %15 + %25 = OpLabel + %26 = OpLoad %6 %10 + %27 = OpLoad %6 %8 + %28 = OpSLessThan %12 %26 %27 + OpSelectionMerge %30 None + OpBranchConditional %28 %29 %32 + %29 = OpLabel + OpStore %8 %31 + OpBranch %30 + %32 = OpLabel + OpStore %8 %33 + OpBranch %30 + %30 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + %20 = OpLabel + OpStore %8 %22 + OpBranch %21 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_bubbling_20_down, context.get())); + + // Current ordering: 5 14 23 21 25 29 32 30 15 20 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + + transformation::Apply(move_down_23, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 21 23 25 29 32 30 15 20 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + + transformation::Apply(move_down_23, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 21 25 23 29 32 30 15 20 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + + transformation::Apply(move_down_21, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 25 21 23 29 32 30 15 20 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); + + transformation::Apply(move_down_14, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_more_shuffling = 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 %9 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %17 RelaxedPrecision + OpDecorate %18 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpConstant %6 1 + %22 = OpConstant %6 3 + %24 = OpConstant %6 4 + %31 = OpConstant %6 5 + %33 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %13 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %25 = OpLabel + %26 = OpLoad %6 %10 + %27 = OpLoad %6 %8 + %28 = OpSLessThan %12 %26 %27 + OpSelectionMerge %30 None + OpBranchConditional %28 %29 %32 + %14 = OpLabel + OpStore %8 %16 + %17 = OpLoad %6 %10 + %18 = OpLoad %6 %8 + %19 = OpIEqual %12 %17 %18 + OpSelectionMerge %21 None + OpBranchConditional %19 %20 %23 + %21 = OpLabel + OpBranch %15 + %23 = OpLabel + OpStore %8 %24 + OpBranch %21 + %29 = OpLabel + OpStore %8 %31 + OpBranch %30 + %32 = OpLabel + OpStore %8 %33 + OpBranch %30 + %30 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + %20 = OpLabel + OpStore %8 %22 + OpBranch %21 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_more_shuffling, context.get())); + + // Final ordering: 5 25 14 21 23 29 32 30 15 20 + ASSERT_FALSE( + transformation::IsApplicable(move_down_5, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_25, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_14, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_21, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_23, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_29, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_32, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_30, context.get(), fact_manager)); + ASSERT_TRUE( + transformation::IsApplicable(move_down_15, context.get(), fact_manager)); + ASSERT_FALSE( + transformation::IsApplicable(move_down_20, context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp new file mode 100644 index 000000000..8472633ee --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp @@ -0,0 +1,630 @@ +// 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_boolean_constant_with_constant_binary.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/id_use_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, + BasicReplacements) { + // The test came from the following pseudo-GLSL, where int64 and uint64 denote + // 64-bit integer types (they were replaced with int and uint during + // translation to SPIR-V, and the generated SPIR-V has been doctored to + // accommodate them). + // + // #version 450 + // + // void main() { + // double d1, d2; + // d1 = 1.0; + // d2 = 2.0; + // float f1, f2; + // f1 = 4.0; + // f2 = 8.0; + // int i1, i2; + // i1 = 100; + // i2 = 200; + // + // uint u1, u2; + // u1 = 300u; + // u2 = 400u; + // + // int64 i64_1, i64_2; + // i64_1 = 500; + // i64_2 = 600; + // + // uint64 u64_1, u64_2; + // u64_1 = 700u; + // u64_2 = 800u; + // + // bool b, c, d, e; + // b = true; + // c = false; + // d = true || c; + // c = c && false; + // } + std::string shader = R"( + OpCapability Shader + OpCapability Float64 + OpCapability Int64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "d1" + OpName %10 "d2" + OpName %14 "f1" + OpName %16 "f2" + OpName %20 "i1" + OpName %22 "i2" + OpName %26 "u1" + OpName %28 "u2" + OpName %30 "i64_1" + OpName %32 "i64_2" + OpName %34 "u64_1" + OpName %36 "u64_2" + OpName %40 "b" + OpName %42 "c" + OpName %44 "d" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 64 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeFloat 32 + %13 = OpTypePointer Function %12 + %15 = OpConstant %12 4 + %17 = OpConstant %12 8 + %18 = OpTypeInt 32 1 + %60 = OpTypeInt 64 1 + %61 = OpTypePointer Function %60 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 -100 + %23 = OpConstant %18 200 + %24 = OpTypeInt 32 0 + %62 = OpTypeInt 64 0 + %63 = OpTypePointer Function %62 + %25 = OpTypePointer Function %24 + %27 = OpConstant %24 300 + %29 = OpConstant %24 400 + %31 = OpConstant %60 -600 + %33 = OpConstant %60 -500 + %35 = OpConstant %62 700 + %37 = OpConstant %62 800 + %38 = OpTypeBool + %39 = OpTypePointer Function %38 + %41 = OpConstantTrue %38 + %43 = OpConstantFalse %38 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %16 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %28 = OpVariable %25 Function + %30 = OpVariable %61 Function + %32 = OpVariable %61 Function + %34 = OpVariable %63 Function + %36 = OpVariable %63 Function + %40 = OpVariable %39 Function + %42 = OpVariable %39 Function + %44 = OpVariable %39 Function + OpStore %8 %9 + OpStore %10 %11 + OpStore %14 %15 + OpStore %16 %17 + OpStore %20 %21 + OpStore %22 %23 + OpStore %26 %27 + OpStore %28 %29 + OpStore %30 %31 + OpStore %32 %33 + OpStore %34 %35 + OpStore %36 %37 + OpStore %40 %41 + OpStore %42 %43 + %45 = OpLoad %38 %42 + %46 = OpLogicalOr %38 %41 %45 + OpStore %44 %46 + %47 = OpLoad %38 %42 + %48 = OpLogicalAnd %38 %47 %43 + OpStore %42 %48 + 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; + + std::vector uses_of_true = { + transformation::MakeIdUseDescriptor(41, SpvOpStore, 1, 44, 12), + transformation::MakeIdUseDescriptor(41, SpvOpLogicalOr, 0, 46, 0)}; + + std::vector uses_of_false = { + transformation::MakeIdUseDescriptor(43, SpvOpStore, 1, 44, 13), + transformation::MakeIdUseDescriptor(43, SpvOpLogicalAnd, 1, 48, 0)}; + + const uint32_t fresh_id = 100; + + std::vector fp_gt_opcodes = { + SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan, + SpvOpFUnordGreaterThanEqual}; + + std::vector fp_lt_opcodes = {SpvOpFOrdLessThan, SpvOpFOrdLessThanEqual, + SpvOpFUnordLessThan, + SpvOpFUnordLessThanEqual}; + + std::vector int_gt_opcodes = {SpvOpSGreaterThan, + SpvOpSGreaterThanEqual}; + + std::vector int_lt_opcodes = {SpvOpSLessThan, SpvOpSLessThanEqual}; + + std::vector uint_gt_opcodes = {SpvOpUGreaterThan, + SpvOpUGreaterThanEqual}; + + std::vector uint_lt_opcodes = {SpvOpULessThan, SpvOpULessThanEqual}; + +#define CHECK_OPERATOR(USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \ + ASSERT_TRUE(transformation::IsApplicable( \ + transformation:: \ + MakeTransformationReplaceBooleanConstantWithConstantBinary( \ + USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID), \ + context.get(), fact_manager)); \ + ASSERT_FALSE(transformation::IsApplicable( \ + transformation:: \ + MakeTransformationReplaceBooleanConstantWithConstantBinary( \ + USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID), \ + context.get(), fact_manager)); + +#define CHECK_TRANSFORMATION_APPLICABILITY(GT_OPCODES, LT_OPCODES, SMALL_ID, \ + LARGE_ID) \ + for (auto gt_opcode : GT_OPCODES) { \ + for (auto& true_use : uses_of_true) { \ + CHECK_OPERATOR(true_use, LARGE_ID, SMALL_ID, gt_opcode, fresh_id); \ + } \ + for (auto& false_use : uses_of_false) { \ + CHECK_OPERATOR(false_use, SMALL_ID, LARGE_ID, gt_opcode, fresh_id); \ + } \ + } \ + for (auto lt_opcode : LT_OPCODES) { \ + for (auto& true_use : uses_of_true) { \ + CHECK_OPERATOR(true_use, SMALL_ID, LARGE_ID, lt_opcode, fresh_id); \ + } \ + for (auto& false_use : uses_of_false) { \ + CHECK_OPERATOR(false_use, LARGE_ID, SMALL_ID, lt_opcode, fresh_id); \ + } \ + } + + // Float + { CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 15, 17); } + + // Double + { CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 9, 11); } + + // Int32 + { + CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 21, 23); + } + + // Int64 + { + CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 31, 33); + } + + // Uint32 + { + CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 27, + 29); + } + + // Uint64 + { + CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 35, + 37); + } + + // Target id is not fresh + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15), + context.get(), fact_manager)); + + // LHS id does not exist + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200), + context.get(), fact_manager)); + + // RHS id does not exist + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200), + context.get(), fact_manager)); + + // LHS and RHS ids do not match type + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200), + context.get(), fact_manager)); + + // Opcode not appropriate + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 15, 17, SpvOpFDiv, 200), + context.get(), fact_manager)); + + auto replace_true_with_double_comparison = transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 9, SpvOpFUnordGreaterThan, 100); + auto replace_true_with_uint32_comparison = transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[1], 27, 29, SpvOpULessThanEqual, 101); + auto replace_false_with_float_comparison = transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_false[0], 17, 15, SpvOpFOrdLessThan, 102); + auto replace_false_with_sint64_comparison = transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_false[1], 33, 31, SpvOpSLessThan, 103); + + ASSERT_TRUE(transformation::IsApplicable(replace_true_with_double_comparison, + context.get(), fact_manager)); + transformation::Apply(replace_true_with_double_comparison, context.get(), + &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(transformation::IsApplicable(replace_true_with_uint32_comparison, + context.get(), fact_manager)); + transformation::Apply(replace_true_with_uint32_comparison, context.get(), + &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(transformation::IsApplicable(replace_false_with_float_comparison, + context.get(), fact_manager)); + transformation::Apply(replace_false_with_float_comparison, context.get(), + &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(transformation::IsApplicable(replace_false_with_sint64_comparison, + context.get(), fact_manager)); + transformation::Apply(replace_false_with_sint64_comparison, context.get(), + &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after = R"( + OpCapability Shader + OpCapability Float64 + OpCapability Int64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "d1" + OpName %10 "d2" + OpName %14 "f1" + OpName %16 "f2" + OpName %20 "i1" + OpName %22 "i2" + OpName %26 "u1" + OpName %28 "u2" + OpName %30 "i64_1" + OpName %32 "i64_2" + OpName %34 "u64_1" + OpName %36 "u64_2" + OpName %40 "b" + OpName %42 "c" + OpName %44 "d" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 64 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeFloat 32 + %13 = OpTypePointer Function %12 + %15 = OpConstant %12 4 + %17 = OpConstant %12 8 + %18 = OpTypeInt 32 1 + %60 = OpTypeInt 64 1 + %61 = OpTypePointer Function %60 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 -100 + %23 = OpConstant %18 200 + %24 = OpTypeInt 32 0 + %62 = OpTypeInt 64 0 + %63 = OpTypePointer Function %62 + %25 = OpTypePointer Function %24 + %27 = OpConstant %24 300 + %29 = OpConstant %24 400 + %31 = OpConstant %60 -600 + %33 = OpConstant %60 -500 + %35 = OpConstant %62 700 + %37 = OpConstant %62 800 + %38 = OpTypeBool + %39 = OpTypePointer Function %38 + %41 = OpConstantTrue %38 + %43 = OpConstantFalse %38 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %16 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %28 = OpVariable %25 Function + %30 = OpVariable %61 Function + %32 = OpVariable %61 Function + %34 = OpVariable %63 Function + %36 = OpVariable %63 Function + %40 = OpVariable %39 Function + %42 = OpVariable %39 Function + %44 = OpVariable %39 Function + OpStore %8 %9 + OpStore %10 %11 + OpStore %14 %15 + OpStore %16 %17 + OpStore %20 %21 + OpStore %22 %23 + OpStore %26 %27 + OpStore %28 %29 + OpStore %30 %31 + OpStore %32 %33 + OpStore %34 %35 + OpStore %36 %37 + %100 = OpFUnordGreaterThan %38 %11 %9 + OpStore %40 %100 + %102 = OpFOrdLessThan %38 %17 %15 + OpStore %42 %102 + %45 = OpLoad %38 %42 + %101 = OpULessThanEqual %38 %27 %29 + %46 = OpLogicalOr %38 %101 %45 + OpStore %44 %46 + %47 = OpLoad %38 %42 + %103 = OpSLessThan %38 %33 %31 + %48 = OpLogicalAnd %38 %47 %103 + OpStore %42 %48 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after, context.get())); + + if (std::numeric_limits::has_quiet_NaN) { + double quiet_nan_double = std::numeric_limits::quiet_NaN(); + uint32_t words[2]; + memcpy(words, &quiet_nan_double, sizeof(double)); + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 6, 200, operands)); + fuzzerutil::UpdateModuleIdBound(context.get(), 200); + ASSERT_TRUE(IsValid(env, context.get())); + // The transformation is not applicable because %200 is NaN. + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300), + context.get(), fact_manager)); + } + if (std::numeric_limits::has_infinity) { + double positive_infinity_double = std::numeric_limits::infinity(); + uint32_t words[2]; + memcpy(words, &positive_infinity_double, sizeof(double)); + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 6, 201, operands)); + fuzzerutil::UpdateModuleIdBound(context.get(), 201); + ASSERT_TRUE(IsValid(env, context.get())); + // Even though the double constant %11 is less than the infinity %201, the + // transformation is restricted to only apply to finite values. + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300), + context.get(), fact_manager)); + } + if (std::numeric_limits::has_infinity) { + float positive_infinity_float = std::numeric_limits::infinity(); + float negative_infinity_float = -1 * positive_infinity_float; + uint32_t words_positive_infinity[1]; + uint32_t words_negative_infinity[1]; + memcpy(words_positive_infinity, &positive_infinity_float, sizeof(float)); + memcpy(words_negative_infinity, &negative_infinity_float, sizeof(float)); + opt::Instruction::OperandList operands_positive_infinity = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_positive_infinity[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 12, 202, operands_positive_infinity)); + fuzzerutil::UpdateModuleIdBound(context.get(), 202); + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_negative_infinity[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 12, 203, operands)); + fuzzerutil::UpdateModuleIdBound(context.get(), 203); + ASSERT_TRUE(IsValid(env, context.get())); + // Even though the negative infinity at %203 is less than the positive + // infinity %202, the transformation is restricted to only apply to finite + // values. + ASSERT_FALSE(transformation::IsApplicable( + transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300), + context.get(), fact_manager)); + } +} + +TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, + MergeInstructions) { + // The test came from the following GLSL: + // + // void main() { + // int x = 1; + // int y = 2; + // if (true) { + // x = 2; + // } + // while(false) { + // y = 2; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeBool + %13 = OpConstantTrue %12 + %21 = OpConstantFalse %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %15 + %14 = OpLabel + OpStore %8 %11 + OpBranch %15 + %15 = OpLabel + OpBranch %16 + %16 = OpLabel + OpLoopMerge %18 %19 None + OpBranchConditional %21 %17 %18 + %17 = OpLabel + OpStore %10 %11 + OpBranch %19 + %19 = OpLabel + OpBranch %16 + %18 = 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 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 replacement_1 = transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + use_of_true_in_if, 9, 11, SpvOpSLessThan, 100); + auto replacement_2 = transformation:: + MakeTransformationReplaceBooleanConstantWithConstantBinary( + use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101); + + ASSERT_TRUE( + transformation::IsApplicable(replacement_1, context.get(), fact_manager)); + transformation::Apply(replacement_1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE( + transformation::IsApplicable(replacement_2, context.get(), fact_manager)); + transformation::Apply(replacement_2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeBool + %13 = OpConstantTrue %12 + %21 = OpConstantFalse %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + %100 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %100 %14 %15 + %14 = OpLabel + OpStore %8 %11 + OpBranch %15 + %15 = OpLabel + OpBranch %16 + %16 = OpLabel + %101 = OpSGreaterThanEqual %12 %9 %11 + OpLoopMerge %18 %19 None + OpBranchConditional %101 %17 %18 + %17 = OpLabel + OpStore %10 %11 + OpBranch %19 + %19 = OpLabel + OpBranch %16 + %18 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp new file mode 100644 index 000000000..976e81a88 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp @@ -0,0 +1,773 @@ +// 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_split_block.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationSplitBlockTest, NotApplicable) { + // The SPIR-V in this test came from the following fragment shader, with + // local store elimination applied to get some OpPhi instructions. + // + // void main() { + // int x; + // int i; + // for (i = 0; i < 100; i++) { + // x += i; + // } + // } + + 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" + OpName %19 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %22 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %24 = OpConstant %6 1 + %28 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + %27 = OpPhi %6 %28 %5 %22 %13 + %26 = OpPhi %6 %9 %5 %25 %13 + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %18 = OpSLessThan %17 %26 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %22 = OpIAdd %6 %27 %26 + OpStore %19 %22 + OpBranch %13 + %13 = OpLabel + %25 = OpIAdd %6 %26 %24 + OpStore %8 %25 + 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; + + // No split before OpVariable + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(8, 0, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(8, 1, 100), context.get(), + fact_manager)); + + // No split before OpLabel + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(14, 0, 100), context.get(), + fact_manager)); + + // No split if base instruction is outside a function + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(1, 0, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(1, 4, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(1, 35, 100), context.get(), + fact_manager)); + + // No split if block is loop header + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(27, 0, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(27, 1, 100), context.get(), + fact_manager)); + + // No split if base instruction does not exist + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(88, 0, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(88, 22, 100), context.get(), + fact_manager)); + + // No split if offset is too large (goes into another block) + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(18, 3, 100), context.get(), + fact_manager)); + + // No split if id in use + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(18, 0, 27), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(18, 0, 14), context.get(), + fact_manager)); +} + +TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) { + // The SPIR-V in this test came from the following fragment shader: + // + // void main() { + // int a; + // int b; + // a = 1; + // b = a; + // a = b; + // b = 2; + // b++; + // } + + 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" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + 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; + + auto split_1 = transformation::MakeTransformationSplitBlock(5, 3, 100); + ASSERT_TRUE( + transformation::IsApplicable(split_1, context.get(), fact_manager)); + transformation::Apply(split_1, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split_1 = 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" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpBranch %100 + %100 = OpLabel + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split_1, context.get())); + + auto split_2 = transformation::MakeTransformationSplitBlock(11, 1, 101); + ASSERT_TRUE( + transformation::IsApplicable(split_2, context.get(), fact_manager)); + transformation::Apply(split_2, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split_2 = 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" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpBranch %100 + %100 = OpLabel + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split_2, context.get())); + + auto split_3 = transformation::MakeTransformationSplitBlock(14, 0, 102); + ASSERT_TRUE( + transformation::IsApplicable(split_3, context.get(), fact_manager)); + transformation::Apply(split_3, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split_3 = 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" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpBranch %100 + %100 = OpLabel + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + OpBranch %102 + %102 = OpLabel + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split_3, context.get())); +} + +TEST(TransformationSplitBlockTest, SplitBlockBeforeSelectBranch) { + // The SPIR-V in this test came from the following fragment shader: + // + // void main() { + // int x, y; + // x = 2; + // if (x < y) { + // y = 3; + // } else { + // y = 4; + // } + // } + + 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 %11 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %13 = OpTypeBool + %17 = OpConstant %6 3 + %19 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %18 + %15 = OpLabel + OpStore %11 %17 + OpBranch %16 + %18 = OpLabel + OpStore %11 %19 + OpBranch %16 + %16 = 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; + + // Illegal to split between the merge and the conditional branch. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(14, 2, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(12, 3, 100), context.get(), + fact_manager)); + + auto split = transformation::MakeTransformationSplitBlock(14, 1, 100); + ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager)); + transformation::Apply(split, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split = 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 %11 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %13 = OpTypeBool + %17 = OpConstant %6 3 + %19 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %18 + %15 = OpLabel + OpStore %11 %17 + OpBranch %16 + %18 = OpLabel + OpStore %11 %19 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split, context.get())); +} + +TEST(TransformationSplitBlockTest, SplitBlockBeforeSwitchBranch) { + // The SPIR-V in this test came from the following fragment shader: + // + // void main() { + // int x, y; + // switch (y) { + // case 1: + // x = 2; + // case 2: + // break; + // case 3: + // x = 4; + // default: + // x = 6; + // } + // } + + 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 "y" + OpName %15 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %16 = OpConstant %6 2 + %18 = OpConstant %6 4 + %19 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %15 = OpVariable %7 Function + %9 = OpLoad %6 %8 + OpSelectionMerge %14 None + OpSwitch %9 %13 1 %10 2 %11 3 %12 + %13 = OpLabel + OpStore %15 %19 + OpBranch %14 + %10 = OpLabel + OpStore %15 %16 + OpBranch %11 + %11 = OpLabel + OpBranch %14 + %12 = OpLabel + OpStore %15 %18 + OpBranch %13 + %14 = 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; + + // Illegal to split between the merge and the conditional branch. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(9, 2, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(15, 3, 100), context.get(), + fact_manager)); + + auto split = transformation::MakeTransformationSplitBlock(9, 1, 100); + ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager)); + transformation::Apply(split, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split = 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 "y" + OpName %15 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %16 = OpConstant %6 2 + %18 = OpConstant %6 4 + %19 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %15 = OpVariable %7 Function + %9 = OpLoad %6 %8 + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %14 None + OpSwitch %9 %13 1 %10 2 %11 3 %12 + %13 = OpLabel + OpStore %15 %19 + OpBranch %14 + %10 = OpLabel + OpStore %15 %16 + OpBranch %11 + %11 = OpLabel + OpBranch %14 + %12 = OpLabel + OpStore %15 %18 + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split, context.get())); +} + +TEST(TransformationSplitBlockTest, NoSplitDuringOpPhis) { + // The SPIR-V in this test came from the following fragment shader, with + // local store elimination applied to get some OpPhi instructions. + // + // void main() { + // int x; + // int i; + // for (i = 0; i < 100; i++) { + // x += i; + // } + // } + + 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" + OpName %19 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %22 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %24 = OpConstant %6 1 + %28 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + %27 = OpPhi %6 %28 %5 %22 %13 + %26 = OpPhi %6 %9 %5 %25 %13 + OpBranch %50 + %50 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %18 = OpSLessThan %17 %26 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %22 = OpIAdd %6 %27 %26 + OpStore %19 %22 + OpBranch %13 + %13 = OpLabel + %25 = OpIAdd %6 %26 %24 + OpStore %8 %25 + OpBranch %50 + %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; + + // We cannot split before OpPhi instructions, since the number of incoming + // blocks may not appropriately match after splitting. + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(26, 0, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(27, 0, 100), context.get(), + fact_manager)); + ASSERT_FALSE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(27, 1, 100), context.get(), + fact_manager)); +} + +TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) { + 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, kFuzzAssembleOption); + + FactManager fact_manager; + + ASSERT_TRUE(transformation::IsApplicable( + transformation::MakeTransformationSplitBlock(21, 0, 100), context.get(), + fact_manager)); + auto split = transformation::MakeTransformationSplitBlock(20, 1, 100); + ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager)); + transformation::Apply(split, context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split = 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 + OpBranch %100 + %100 = OpLabel + %21 = OpPhi %6 %11 %20 + OpStore %10 %21 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzzers/BUILD.gn b/3rdparty/spirv-tools/test/fuzzers/BUILD.gn index 69659c661..c565e113b 100644 --- a/3rdparty/spirv-tools/test/fuzzers/BUILD.gn +++ b/3rdparty/spirv-tools/test/fuzzers/BUILD.gn @@ -37,7 +37,10 @@ if (!build_with_chromium || use_fuzzing_engine) { ":spvtools_opt_legalization_fuzzer", ":spvtools_opt_performance_fuzzer", ":spvtools_opt_size_fuzzer", + ":spvtools_opt_webgputovulkan_fuzzer", + ":spvtools_opt_vulkantowebgpu_fuzzer", ":spvtools_val_fuzzer", + ":spvtools_val_webgpu_fuzzer", ] } } @@ -87,12 +90,31 @@ spvtools_fuzzer("spvtools_opt_size_fuzzer_src") { ] } + +spvtools_fuzzer("spvtools_opt_webgputovulkan_fuzzer_src") { + sources = [ + "spvtools_opt_webgputovulkan_fuzzer.cpp", + ] +} + +spvtools_fuzzer("spvtools_opt_vulkantowebgpu_fuzzer_src") { + sources = [ + "spvtools_opt_vulkantowebgpu_fuzzer.cpp", + ] +} + spvtools_fuzzer("spvtools_val_fuzzer_src") { sources = [ "spvtools_val_fuzzer.cpp", ] } +spvtools_fuzzer("spvtools_val_webgpu_fuzzer_src") { + sources = [ + "spvtools_val_webgpu_fuzzer.cpp", + ] +} + if (!build_with_chromium || use_fuzzing_engine) { fuzzer_test("spvtools_binary_parser_fuzzer") { sources = [] @@ -127,6 +149,22 @@ if (!build_with_chromium || use_fuzzing_engine) { seed_corpus = "corpora/spv" } + fuzzer_test("spvtools_opt_webgputovulkan_fuzzer") { + sources = [] + deps = [ + ":spvtools_opt_webgputovulkan_fuzzer_src", + ] + seed_corpus = "corpora/spv" + } + + fuzzer_test("spvtools_opt_vulkantowebgpu_fuzzer") { + sources = [] + deps = [ + ":spvtools_opt_vulkantowebgpu_fuzzer_src", + ] + seed_corpus = "corpora/spv" + } + fuzzer_test("spvtools_val_fuzzer") { sources = [] deps = [ @@ -134,4 +172,12 @@ if (!build_with_chromium || use_fuzzing_engine) { ] seed_corpus = "corpora/spv" } + + fuzzer_test("spvtools_val_webgpu_fuzzer") { + sources = [] + deps = [ + ":spvtools_val_webgpu_fuzzer_src", + ] + seed_corpus = "corpora/spv" + } } diff --git a/3rdparty/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp b/3rdparty/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp new file mode 100644 index 000000000..0b2ecc322 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp @@ -0,0 +1,38 @@ +// 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 +#include + +#include "spirv-tools/optimizer.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0); + optimizer.SetMessageConsumer([](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}); + + std::vector input; + input.resize(size >> 2); + + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + optimizer.RegisterVulkanToWebGPUPasses(); + optimizer.Run(input.data(), input.size(), &input); + + return 0; +} diff --git a/3rdparty/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp b/3rdparty/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp new file mode 100644 index 000000000..1e44857dc --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp @@ -0,0 +1,38 @@ +// 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 +#include + +#include "spirv-tools/optimizer.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1); + optimizer.SetMessageConsumer([](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}); + + std::vector input; + input.resize(size >> 2); + + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + optimizer.RegisterWebGPUToVulkanPasses(); + optimizer.Run(input.data(), input.size(), &input); + + return 0; +} diff --git a/3rdparty/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp b/3rdparty/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp new file mode 100644 index 000000000..bed6e1a21 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp @@ -0,0 +1,36 @@ +// 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 +#include + +#include "spirv-tools/libspirv.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + spvtools::SpirvTools tools(SPV_ENV_WEBGPU_0); + tools.SetMessageConsumer([](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}); + + std::vector input; + input.resize(size >> 2); + + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + tools.Validate(input); + return 0; +} diff --git a/3rdparty/spirv-tools/test/huffman_codec.cpp b/3rdparty/spirv-tools/test/huffman_codec.cpp deleted file mode 100644 index 58a781061..000000000 --- a/3rdparty/spirv-tools/test/huffman_codec.cpp +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (c) 2017 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 -#include -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/bit_stream.h" -#include "source/comp/huffman_codec.h" - -namespace spvtools { -namespace comp { -namespace { - -const std::map& GetTestSet() { - static const std::map hist = { - {"a", 4}, {"e", 7}, {"f", 3}, {"h", 2}, {"i", 3}, - {"m", 2}, {"n", 2}, {"s", 2}, {"t", 2}, {"l", 1}, - {"o", 2}, {"p", 1}, {"r", 1}, {"u", 1}, {"x", 1}, - }; - - return hist; -} - -class TestBitReader { - public: - TestBitReader(const std::string& bits) : bits_(bits) {} - - bool ReadBit(bool* bit) { - if (pos_ < bits_.length()) { - *bit = bits_[pos_++] == '0' ? false : true; - return true; - } - return false; - } - - private: - std::string bits_; - size_t pos_ = 0; -}; - -TEST(Huffman, PrintTree) { - HuffmanCodec huffman(GetTestSet()); - std::stringstream ss; - huffman.PrintTree(ss); - - // clang-format off - const std::string expected = std::string(R"( -15-----7------e - 8------4------a - 4------2------m - 2------n -19-----8------4------2------o - 2------s - 4------2------t - 2------1------l - 1------p - 11-----5------2------1------r - 1------u - 3------f - 6------3------i - 3------1------x - 2------h -)").substr(1); - // clang-format on - - EXPECT_EQ(expected, ss.str()); -} - -TEST(Huffman, PrintTable) { - HuffmanCodec huffman(GetTestSet()); - std::stringstream ss; - huffman.PrintTable(ss); - - const std::string expected = std::string(R"( -e 7 11 -a 4 101 -i 3 0001 -f 3 0010 -t 2 0101 -s 2 0110 -o 2 0111 -n 2 1000 -m 2 1001 -h 2 00000 -x 1 00001 -u 1 00110 -r 1 00111 -p 1 01000 -l 1 01001 -)") - .substr(1); - - EXPECT_EQ(expected, ss.str()); -} - -TEST(Huffman, TestValidity) { - HuffmanCodec huffman(GetTestSet()); - const auto& encoding_table = huffman.GetEncodingTable(); - std::vector codes; - for (const auto& entry : encoding_table) { - codes.push_back(BitsToStream(entry.second.first, entry.second.second)); - } - - std::sort(codes.begin(), codes.end()); - - ASSERT_LT(codes.size(), 20u) << "Inefficient test ahead"; - - for (size_t i = 0; i < codes.size(); ++i) { - for (size_t j = i + 1; j < codes.size(); ++j) { - ASSERT_FALSE(codes[i] == codes[j].substr(0, codes[i].length())) - << codes[i] << " is prefix of " << codes[j]; - } - } -} - -TEST(Huffman, TestEncode) { - HuffmanCodec huffman(GetTestSet()); - - uint64_t bits = 0; - size_t num_bits = 0; - - EXPECT_TRUE(huffman.Encode("e", &bits, &num_bits)); - EXPECT_EQ(2u, num_bits); - EXPECT_EQ("11", BitsToStream(bits, num_bits)); - - EXPECT_TRUE(huffman.Encode("a", &bits, &num_bits)); - EXPECT_EQ(3u, num_bits); - EXPECT_EQ("101", BitsToStream(bits, num_bits)); - - EXPECT_TRUE(huffman.Encode("x", &bits, &num_bits)); - EXPECT_EQ(5u, num_bits); - EXPECT_EQ("00001", BitsToStream(bits, num_bits)); - - EXPECT_FALSE(huffman.Encode("y", &bits, &num_bits)); -} - -TEST(Huffman, TestDecode) { - HuffmanCodec huffman(GetTestSet()); - TestBitReader bit_reader( - "01001" - "0001" - "1000" - "00110" - "00001" - "00"); - auto read_bit = [&bit_reader](bool* bit) { return bit_reader.ReadBit(bit); }; - - std::string decoded; - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("l", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("i", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("n", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("u", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("x", decoded); - - ASSERT_FALSE(huffman.DecodeFromStream(read_bit, &decoded)); -} - -TEST(Huffman, TestDecodeNumbers) { - const std::map hist = {{1, 10}, {2, 5}, {3, 15}}; - HuffmanCodec huffman(hist); - - TestBitReader bit_reader( - "1" - "1" - "01" - "00" - "01" - "1"); - auto read_bit = [&bit_reader](bool* bit) { return bit_reader.ReadBit(bit); }; - - uint32_t decoded; - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(3u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(3u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(2u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(1u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(2u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(3u, decoded); -} - -TEST(Huffman, SerializeToTextU64) { - const std::map hist = {{1001, 10}, {1002, 5}, {1003, 15}}; - HuffmanCodec huffman(hist); - - const std::string code = huffman.SerializeToText(2); - - const std::string expected = R"((5, { - {0, 0, 0}, - {1001, 0, 0}, - {1002, 0, 0}, - {1003, 0, 0}, - {0, 1, 2}, - {0, 4, 3}, - }))"; - - ASSERT_EQ(expected, code); -} - -TEST(Huffman, SerializeToTextString) { - const std::map hist = { - {"aaa", 10}, {"bbb", 20}, {"ccc", 15}}; - HuffmanCodec huffman(hist); - - const std::string code = huffman.SerializeToText(4); - - const std::string expected = R"((5, { - {"", 0, 0}, - {"aaa", 0, 0}, - {"bbb", 0, 0}, - {"ccc", 0, 0}, - {"", 3, 1}, - {"", 4, 2}, - }))"; - - ASSERT_EQ(expected, code); -} - -TEST(Huffman, CreateFromTextString) { - std::vector::Node> nodes = { - {}, - {"root", 2, 3}, - {"left", 0, 0}, - {"right", 0, 0}, - }; - - HuffmanCodec huffman(1, std::move(nodes)); - - std::stringstream ss; - huffman.PrintTree(ss); - - const std::string expected = std::string(R"( -0------right -0------left -)") - .substr(1); - - EXPECT_EQ(expected, ss.str()); -} - -TEST(Huffman, CreateFromTextU64) { - HuffmanCodec huffman(5, { - {0, 0, 0}, - {1001, 0, 0}, - {1002, 0, 0}, - {1003, 0, 0}, - {0, 1, 2}, - {0, 4, 3}, - }); - - std::stringstream ss; - huffman.PrintTree(ss); - - const std::string expected = std::string(R"( -0------1003 -0------0------1002 - 0------1001 -)") - .substr(1); - - EXPECT_EQ(expected, ss.str()); - - TestBitReader bit_reader("01"); - auto read_bit = [&bit_reader](bool* bit) { return bit_reader.ReadBit(bit); }; - - uint64_t decoded = 0; - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(1002u, decoded); - - uint64_t bits = 0; - size_t num_bits = 0; - - EXPECT_TRUE(huffman.Encode(1001, &bits, &num_bits)); - EXPECT_EQ(2u, num_bits); - EXPECT_EQ("00", BitsToStream(bits, num_bits)); -} - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/link/CMakeLists.txt b/3rdparty/spirv-tools/test/link/CMakeLists.txt index 06aeb9164..ee41b9161 100644 --- a/3rdparty/spirv-tools/test/link/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/link/CMakeLists.txt @@ -23,5 +23,6 @@ add_spvtools_unittest(TARGET link memory_model_test.cpp partial_linkage_test.cpp unique_ids_test.cpp + type_match_test.cpp LIBS SPIRV-Tools-opt SPIRV-Tools-link ) diff --git a/3rdparty/spirv-tools/test/link/linker_fixture.h b/3rdparty/spirv-tools/test/link/linker_fixture.h index 303f1bfd5..7bb122354 100644 --- a/3rdparty/spirv-tools/test/link/linker_fixture.h +++ b/3rdparty/spirv-tools/test/link/linker_fixture.h @@ -19,6 +19,8 @@ #include #include +#include "effcee/effcee.h" +#include "re2/re2.h" #include "source/spirv_constant.h" #include "spirv-tools/linker.hpp" #include "test/unit_spirv.h" @@ -80,6 +82,101 @@ class LinkerTest : public ::testing::Test { return spvtools::Link(context_, binaries, linked_binary, options); } + // Assembles and links a vector of SPIR-V bodies based on the |templateBody|. + // Template arguments to be replaced are written as {a,b,...}. + // SPV_ERROR_INVALID_TEXT is returned if the assembling failed for any of the + // resulting bodies (or errors in the template), and SPV_ERROR_INVALID_POINTER + // if |linked_binary| is a null pointer. + spv_result_t ExpandAndLink( + const std::string& templateBody, spvtest::Binary* linked_binary, + spvtools::LinkerOptions options = spvtools::LinkerOptions()) { + if (!linked_binary) return SPV_ERROR_INVALID_POINTER; + + // Find out how many template arguments there are, we assume they all have + // the same number. We'll error later if they don't. + re2::StringPiece temp(templateBody); + re2::StringPiece x; + int cnt = 0; + if (!RE2::FindAndConsume(&temp, "{")) return SPV_ERROR_INVALID_TEXT; + while (RE2::FindAndConsume(&temp, "([,}])", &x) && x[0] == ',') cnt++; + cnt++; + if (cnt <= 1) return SPV_ERROR_INVALID_TEXT; + + // Construct a regex for a single common strip and template expansion. + std::string regex("([^{]*){"); + for (int i = 0; i < cnt; i++) regex += (i > 0) ? ",([^,]*)" : "([^,]*)"; + regex += "}"; + RE2 pattern(regex); + + // Prepare the RE2::Args for processing. + re2::StringPiece common; + std::vector variants(cnt); + std::vector args(cnt + 1); + args[0] = RE2::Arg(&common); + std::vector pargs(cnt + 1); + pargs[0] = &args[0]; + for (int i = 0; i < cnt; i++) { + args[i + 1] = RE2::Arg(&variants[i]); + pargs[i + 1] = &args[i + 1]; + } + + // Reset and construct the bodies bit by bit. + std::vector bodies(cnt); + re2::StringPiece temp2(templateBody); + while (RE2::ConsumeN(&temp2, pattern, pargs.data(), cnt + 1)) { + for (int i = 0; i < cnt; i++) { + bodies[i].append(common.begin(), common.end()); + bodies[i].append(variants[i].begin(), variants[i].end()); + } + } + RE2::Consume(&temp2, "([^{]*)", &common); + for (int i = 0; i < cnt; i++) + bodies[i].append(common.begin(), common.end()); + + // Run through the assemble and link stages of the process. + return AssembleAndLink(bodies, linked_binary, options); + } + + // Expand the |templateBody| and link the results as with ExpandAndLink, + // then disassemble and test that the result matches the |expected|. + void ExpandAndCheck( + const std::string& templateBody, const std::string& expected, + const spvtools::LinkerOptions options = spvtools::LinkerOptions()) { + spvtest::Binary linked_binary; + spv_result_t res = ExpandAndLink(templateBody, &linked_binary, options); + EXPECT_EQ(SPV_SUCCESS, res) << GetErrorMessage() << "\nExpanded from:\n" + << templateBody; + if (res == SPV_SUCCESS) { + std::string result; + EXPECT_TRUE( + tools_.Disassemble(linked_binary, &result, disassemble_options_)) + << GetErrorMessage(); + EXPECT_EQ(expected, result); + } + } + + // An alternative to ExpandAndCheck, which uses the |templateBody| as the + // match pattern for the disassembled linked result. + void ExpandAndMatch( + const std::string& templateBody, + const spvtools::LinkerOptions options = spvtools::LinkerOptions()) { + spvtest::Binary linked_binary; + spv_result_t res = ExpandAndLink(templateBody, &linked_binary, options); + EXPECT_EQ(SPV_SUCCESS, res) << GetErrorMessage() << "\nExpanded from:\n" + << templateBody; + if (res == SPV_SUCCESS) { + std::string result; + EXPECT_TRUE( + tools_.Disassemble(linked_binary, &result, disassemble_options_)) + << GetErrorMessage(); + auto match_res = effcee::Match(result, templateBody); + EXPECT_EQ(effcee::Result::Status::Ok, match_res.status()) + << match_res.message() << "\nExpanded from:\n" + << templateBody << "\nChecking result:\n" + << result; + } + } + // Links the given SPIR-V binaries together; SPV_ERROR_INVALID_POINTER is // returned if |linked_binary| is a null pointer. spv_result_t Link( diff --git a/3rdparty/spirv-tools/test/link/type_match_test.cpp b/3rdparty/spirv-tools/test/link/type_match_test.cpp new file mode 100644 index 000000000..c12ffb300 --- /dev/null +++ b/3rdparty/spirv-tools/test/link/type_match_test.cpp @@ -0,0 +1,144 @@ +// Copyright (c) 2019 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" +#include "test/link/linker_fixture.h" + +namespace spvtools { +namespace { + +using TypeMatch = spvtest::LinkerTest; + +// Basic types +#define PartInt(D, N) D(N) " = OpTypeInt 32 0" +#define PartFloat(D, N) D(N) " = OpTypeFloat 32" +#define PartOpaque(D, N) D(N) " = OpTypeOpaque \"bar\"" +#define PartSampler(D, N) D(N) " = OpTypeSampler" +#define PartEvent(D, N) D(N) " = OpTypeEvent" +#define PartDeviceEvent(D, N) D(N) " = OpTypeDeviceEvent" +#define PartReserveId(D, N) D(N) " = OpTypeReserveId" +#define PartQueue(D, N) D(N) " = OpTypeQueue" +#define PartPipe(D, N) D(N) " = OpTypePipe ReadWrite" +#define PartPipeStorage(D, N) D(N) " = OpTypePipeStorage" +#define PartNamedBarrier(D, N) D(N) " = OpTypeNamedBarrier" + +// Compound types +#define PartVector(DR, DA, N, T) DR(N) " = OpTypeVector " DA(T) " 3" +#define PartMatrix(DR, DA, N, T) DR(N) " = OpTypeMatrix " DA(T) " 4" +#define PartImage(DR, DA, N, T) \ + DR(N) " = OpTypeImage " DA(T) " 2D 0 0 0 0 Rgba32f" +#define PartSampledImage(DR, DA, N, T) DR(N) " = OpTypeSampledImage " DA(T) +#define PartArray(DR, DA, N, T) DR(N) " = OpTypeArray " DA(T) " " DA(const) +#define PartRuntimeArray(DR, DA, N, T) DR(N) " = OpTypeRuntimeArray " DA(T) +#define PartStruct(DR, DA, N, T) DR(N) " = OpTypeStruct " DA(T) " " DA(T) +#define PartPointer(DR, DA, N, T) DR(N) " = OpTypePointer Workgroup " DA(T) +#define PartFunction(DR, DA, N, T) DR(N) " = OpTypeFunction " DA(T) " " DA(T) + +#define CheckDecoRes(S) "[[" #S ":%\\w+]]" +#define CheckDecoArg(S) "[[" #S "]]" +#define InstDeco(S) "%" #S + +#define MatchPart1(F, N) \ + "; CHECK: " Part##F(CheckDecoRes, N) "\n" Part##F(InstDeco, N) "\n" +#define MatchPart2(F, N, T) \ + "; CHECK: " Part##F(CheckDecoRes, CheckDecoArg, N, T) "\n" Part##F( \ + InstDeco, InstDeco, N, T) "\n" + +#define MatchF(N, CODE) \ + TEST_F(TypeMatch, N) { \ + const std::string base = \ + "OpCapability Linkage\n" \ + "OpCapability NamedBarrier\n" \ + "OpCapability PipeStorage\n" \ + "OpCapability Pipes\n" \ + "OpCapability DeviceEnqueue\n" \ + "OpCapability Kernel\n" \ + "OpCapability Shader\n" \ + "OpCapability Addresses\n" \ + "OpDecorate %var LinkageAttributes \"foo\" " \ + "{Import,Export}\n" \ + "; CHECK: [[baseint:%\\w+]] = OpTypeInt 32 1\n" \ + "%baseint = OpTypeInt 32 1\n" \ + "; CHECK: [[const:%\\w+]] = OpConstant [[baseint]] 3\n" \ + "%const = OpConstant %baseint 3\n" CODE \ + "; CHECK: OpVariable [[type]] Uniform\n" \ + "%var = OpVariable %type Uniform"; \ + ExpandAndMatch(base); \ + } + +#define Match1(T) MatchF(Type##T, MatchPart1(T, type)) +#define Match2(T, A) \ + MatchF(T##OfType##A, MatchPart1(A, a) MatchPart2(T, type, a)) +#define Match3(T, A, B) \ + MatchF(T##Of##A##Of##B, \ + MatchPart1(B, b) MatchPart2(A, a, b) MatchPart2(T, type, a)) + +// Basic types +Match1(Int); +Match1(Float); +Match1(Opaque); +Match1(Sampler); +Match1(Event); +Match1(DeviceEvent); +Match1(ReserveId); +Match1(Queue); +Match1(Pipe); +Match1(PipeStorage); +Match1(NamedBarrier); + +// Simpler (restricted) compound types +Match2(Vector, Float); +Match3(Matrix, Vector, Float); +Match2(Image, Float); + +// Unrestricted compound types +#define MatchCompounds1(A) \ + Match2(RuntimeArray, A); \ + Match2(Struct, A); \ + Match2(Pointer, A); \ + Match2(Function, A); \ + Match2(Array, A); +#define MatchCompounds2(A, B) \ + Match3(RuntimeArray, A, B); \ + Match3(Struct, A, B); \ + Match3(Pointer, A, B); \ + Match3(Function, A, B); \ + Match3(Array, A, B); + +MatchCompounds1(Float); +MatchCompounds2(Array, Float); +MatchCompounds2(RuntimeArray, Float); +MatchCompounds2(Struct, Float); +MatchCompounds2(Pointer, Float); +MatchCompounds2(Function, Float); + +// ForwardPointer tests, which don't fit into the previous mold +#define MatchFpF(N, CODE) \ + MatchF(N, \ + "; CHECK: OpTypeForwardPointer [[type:%\\w+]] Workgroup\n" \ + "OpTypeForwardPointer %type Workgroup\n" CODE \ + "; CHECK: [[type]] = OpTypePointer Workgroup [[realtype]]\n" \ + "%type = OpTypePointer Workgroup %realtype\n") +#define MatchFp1(T) MatchFpF(ForwardPointerOf##T, MatchPart1(T, realtype)) +#define MatchFp2(T, A) \ + MatchFpF(ForwardPointerOf##T, MatchPart1(A, a) MatchPart2(T, realtype, a)) + +MatchFp1(Float); +MatchFp2(Array, Float); +MatchFp2(RuntimeArray, Float); +MatchFp2(Struct, Float); +MatchFp2(Function, Float); + +} // namespace +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/move_to_front_test.cpp b/3rdparty/spirv-tools/test/move_to_front_test.cpp deleted file mode 100644 index c95d38656..000000000 --- a/3rdparty/spirv-tools/test/move_to_front_test.cpp +++ /dev/null @@ -1,828 +0,0 @@ -// Copyright (c) 2017 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 -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/move_to_front.h" - -namespace spvtools { -namespace comp { -namespace { - -// Class used to test the inner workings of MoveToFront. -class MoveToFrontTester : public MoveToFront { - public: - // Inserts the value in the internal tree data structure. For testing only. - void TestInsert(uint32_t val) { InsertNode(CreateNode(val, val)); } - - // Removes the value from the internal tree data structure. For testing only. - void TestRemove(uint32_t val) { - const auto it = value_to_node_.find(val); - assert(it != value_to_node_.end()); - RemoveNode(it->second); - } - - // Prints the internal tree data structure to |out|. For testing only. - void PrintTree(std::ostream& out, bool print_timestamp = false) const { - if (root_) PrintTreeInternal(out, root_, 1, print_timestamp); - } - - // Returns node handle corresponding to the value. The value may not be in the - // tree. - uint32_t GetNodeHandle(uint32_t value) const { - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) return 0; - - return it->second; - } - - // Returns total node count (both those in the tree and removed, - // but not the NIL singleton). - size_t GetTotalNodeCount() const { - assert(nodes_.size()); - return nodes_.size() - 1; - } - - uint32_t GetLastAccessedValue() const { return last_accessed_value_; } - - private: - // Prints the internal tree data structure for debug purposes in the following - // format: - // 10H3S4----5H1S1-----D2 - // 15H2S2----12H1S1----D3 - // Right links are horizontal, left links step down one line. - // 5H1S1 is read as value 5, height 1, size 1. Optionally node label can also - // contain timestamp (5H1S1T15). D3 stands for depth 3. - void PrintTreeInternal(std::ostream& out, uint32_t node, size_t depth, - bool print_timestamp) const; -}; - -void MoveToFrontTester::PrintTreeInternal(std::ostream& out, uint32_t node, - size_t depth, - bool print_timestamp) const { - if (!node) { - out << "D" << depth - 1 << std::endl; - return; - } - - const size_t kTextFieldWvaluethWithoutTimestamp = 10; - const size_t kTextFieldWvaluethWithTimestamp = 14; - const size_t text_field_wvalueth = print_timestamp - ? kTextFieldWvaluethWithTimestamp - : kTextFieldWvaluethWithoutTimestamp; - - std::stringstream label; - label << ValueOf(node) << "H" << HeightOf(node) << "S" << SizeOf(node); - if (print_timestamp) label << "T" << TimestampOf(node); - const size_t label_length = label.str().length(); - if (label_length < text_field_wvalueth) - label << std::string(text_field_wvalueth - label_length, '-'); - - out << label.str(); - - PrintTreeInternal(out, RightOf(node), depth + 1, print_timestamp); - - if (LeftOf(node)) { - out << std::string(depth * text_field_wvalueth, ' '); - PrintTreeInternal(out, LeftOf(node), depth + 1, print_timestamp); - } -} - -void CheckTree(const MoveToFrontTester& mtf, const std::string& expected, - bool print_timestamp = false) { - std::stringstream ss; - mtf.PrintTree(ss, print_timestamp); - EXPECT_EQ(expected, ss.str()); -} - -TEST(MoveToFront, EmptyTree) { - MoveToFrontTester mtf; - CheckTree(mtf, std::string()); -} - -TEST(MoveToFront, InsertLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(30); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -30H2S2----20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(10); - CheckTree(mtf, std::string(R"( -20H2S3----10H1S1----D2 - 30H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, InsertRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -10H2S2----D1 - 20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(30); - CheckTree(mtf, std::string(R"( -20H2S3----10H1S1----D2 - 30H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, InsertRightLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(30); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -30H2S2----20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(25); - CheckTree(mtf, std::string(R"( -25H2S3----20H1S1----D2 - 30H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, InsertLeftRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -10H2S2----D1 - 20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(15); - CheckTree(mtf, std::string(R"( -15H2S3----10H1S1----D2 - 20H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveSingleton) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - CheckTree(mtf, std::string(R"( -10H1S1----D1 -)") - .substr(1)); - - mtf.TestRemove(10); - CheckTree(mtf, ""); -} - -TEST(MoveToFront, RemoveRootWithScapegoat) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(5); - mtf.TestInsert(15); - CheckTree(mtf, std::string(R"( -10H2S3----5H1S1-----D2 - 15H1S1----D2 -)") - .substr(1)); - - mtf.TestRemove(10); - CheckTree(mtf, std::string(R"( -15H2S2----5H1S1-----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(5); - mtf.TestInsert(15); - mtf.TestInsert(20); - CheckTree(mtf, std::string(R"( -10H3S4----5H1S1-----D2 - 15H2S2----D2 - 20H1S1----D3 -)") - .substr(1)); - - mtf.TestRemove(5); - - CheckTree(mtf, std::string(R"( -15H2S3----10H1S1----D2 - 20H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(15); - mtf.TestInsert(5); - mtf.TestInsert(1); - CheckTree(mtf, std::string(R"( -10H3S4----5H2S2-----1H1S1-----D3 - 15H1S1----D2 -)") - .substr(1)); - - mtf.TestRemove(15); - - CheckTree(mtf, std::string(R"( -5H2S3-----1H1S1-----D2 - 10H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveLeftRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(15); - mtf.TestInsert(5); - mtf.TestInsert(12); - CheckTree(mtf, std::string(R"( -10H3S4----5H1S1-----D2 - 15H2S2----12H1S1----D3 -)") - .substr(1)); - - mtf.TestRemove(5); - - CheckTree(mtf, std::string(R"( -12H2S3----10H1S1----D2 - 15H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveRightLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(15); - mtf.TestInsert(5); - mtf.TestInsert(8); - CheckTree(mtf, std::string(R"( -10H3S4----5H2S2-----D2 - 8H1S1-----D3 - 15H1S1----D2 -)") - .substr(1)); - - mtf.TestRemove(15); - - CheckTree(mtf, std::string(R"( -8H2S3-----5H1S1-----D2 - 10H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, MultipleOperations) { - MoveToFrontTester mtf; - std::vector vals = {5, 11, 12, 16, 15, 6, 14, 2, - 7, 10, 4, 8, 9, 3, 1, 13}; - - for (uint32_t i : vals) { - mtf.TestInsert(i); - } - - CheckTree(mtf, std::string(R"( -11H5S16---5H4S10----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 7H3S5-----6H1S1-----D4 - 9H2S3-----8H1S1-----D5 - 10H1S1----D5 - 15H3S5----13H2S3----12H1S1----D4 - 14H1S1----D4 - 16H1S1----D3 -)") - .substr(1)); - - mtf.TestRemove(11); - - CheckTree(mtf, std::string(R"( -10H5S15---5H4S9-----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 7H3S4-----6H1S1-----D4 - 9H2S2-----8H1S1-----D5 - 15H3S5----13H2S3----12H1S1----D4 - 14H1S1----D4 - 16H1S1----D3 -)") - .substr(1)); - - mtf.TestInsert(11); - - CheckTree(mtf, std::string(R"( -10H5S16---5H4S9-----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 7H3S4-----6H1S1-----D4 - 9H2S2-----8H1S1-----D5 - 13H3S6----12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D4 - 16H1S1----D4 -)") - .substr(1)); - - mtf.TestRemove(5); - - CheckTree(mtf, std::string(R"( -10H5S15---6H4S8-----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 8H2S3-----7H1S1-----D4 - 9H1S1-----D4 - 13H3S6----12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D4 - 16H1S1----D4 -)") - .substr(1)); - - mtf.TestInsert(5); - - CheckTree(mtf, std::string(R"( -10H5S16---6H4S9-----3H3S5-----2H2S2-----1H1S1-----D5 - 4H2S2-----D4 - 5H1S1-----D5 - 8H2S3-----7H1S1-----D4 - 9H1S1-----D4 - 13H3S6----12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D4 - 16H1S1----D4 -)") - .substr(1)); - - mtf.TestRemove(2); - mtf.TestRemove(1); - mtf.TestRemove(4); - mtf.TestRemove(3); - mtf.TestRemove(6); - mtf.TestRemove(5); - mtf.TestRemove(7); - mtf.TestRemove(9); - - CheckTree(mtf, std::string(R"( -13H4S8----10H3S4----8H1S1-----D3 - 12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D3 - 16H1S1----D3 -)") - .substr(1)); -} - -TEST(MoveToFront, BiggerScaleTreeTest) { - MoveToFrontTester mtf; - std::set all_vals; - - const uint32_t kMagic1 = 2654435761; - const uint32_t kMagic2 = 10000; - - for (uint32_t i = 1; i < 1000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (!all_vals.count(val)) { - mtf.TestInsert(val); - all_vals.insert(val); - } - } - - for (uint32_t i = 1; i < 1000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (val % 2 == 0) { - mtf.TestRemove(val); - all_vals.erase(val); - } - } - - for (uint32_t i = 1000; i < 2000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (!all_vals.count(val)) { - mtf.TestInsert(val); - all_vals.insert(val); - } - } - - for (uint32_t i = 1; i < 2000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (val > 50) { - mtf.TestRemove(val); - all_vals.erase(val); - } - } - - EXPECT_EQ(all_vals, std::set({2, 4, 11, 13, 24, 33, 35, 37, 46})); - - CheckTree(mtf, std::string(R"( -33H4S9----11H3S5----2H2S2-----D3 - 4H1S1-----D4 - 13H2S2----D3 - 24H1S1----D4 - 37H2S3----35H1S1----D3 - 46H1S1----D3 -)") - .substr(1)); -} - -TEST(MoveToFront, RankFromValue) { - MoveToFrontTester mtf; - - uint32_t rank = 0; - EXPECT_FALSE(mtf.RankFromValue(1, &rank)); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_TRUE(mtf.Insert(2)); - EXPECT_TRUE(mtf.Insert(3)); - EXPECT_FALSE(mtf.Insert(2)); - CheckTree(mtf, - std::string(R"( -2H2S3T2-------1H1S1T1-------D2 - 3H1S1T3-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_FALSE(mtf.RankFromValue(4, &rank)); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(3u, rank); - - CheckTree(mtf, - std::string(R"( -3H2S3T3-------2H1S1T2-------D2 - 1H1S1T4-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(1u, rank); - - EXPECT_TRUE(mtf.RankFromValue(3, &rank)); - EXPECT_EQ(2u, rank); - - EXPECT_TRUE(mtf.RankFromValue(2, &rank)); - EXPECT_EQ(3u, rank); - - EXPECT_TRUE(mtf.Insert(40)); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(4u, rank); - - EXPECT_TRUE(mtf.Insert(50)); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(2u, rank); - - CheckTree(mtf, - std::string(R"( -2H3S5T6-------3H1S1T5-------D2 - 50H2S3T9------40H1S1T7------D3 - 1H1S1T10------D3 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.RankFromValue(50, &rank)); - EXPECT_EQ(2u, rank); - - EXPECT_EQ(5u, mtf.GetSize()); - CheckTree(mtf, - std::string(R"( -2H3S5T6-------3H1S1T5-------D2 - 1H2S3T10------40H1S1T7------D3 - 50H1S1T11-----D3 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_FALSE(mtf.RankFromValue(0, &rank)); - EXPECT_FALSE(mtf.RankFromValue(20, &rank)); -} - -TEST(MoveToFront, ValueFromRank) { - MoveToFrontTester mtf; - - uint32_t value = 0; - EXPECT_FALSE(mtf.ValueFromRank(0, &value)); - EXPECT_FALSE(mtf.ValueFromRank(1, &value)); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_EQ(1u, mtf.GetLastAccessedValue()); - EXPECT_TRUE(mtf.Insert(2)); - EXPECT_EQ(2u, mtf.GetLastAccessedValue()); - EXPECT_TRUE(mtf.Insert(3)); - EXPECT_EQ(3u, mtf.GetLastAccessedValue()); - - EXPECT_TRUE(mtf.ValueFromRank(3, &value)); - EXPECT_EQ(1u, value); - EXPECT_EQ(1u, mtf.GetLastAccessedValue()); - - EXPECT_TRUE(mtf.ValueFromRank(1, &value)); - EXPECT_EQ(1u, value); - EXPECT_EQ(1u, mtf.GetLastAccessedValue()); - - CheckTree(mtf, - std::string(R"( -3H2S3T3-------2H1S1T2-------D2 - 1H1S1T4-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.ValueFromRank(2, &value)); - EXPECT_EQ(3u, value); - - EXPECT_EQ(3u, mtf.GetSize()); - - CheckTree(mtf, - std::string(R"( -1H2S3T4-------2H1S1T2-------D2 - 3H1S1T5-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.ValueFromRank(3, &value)); - EXPECT_EQ(2u, value); - - CheckTree(mtf, - std::string(R"( -3H2S3T5-------1H1S1T4-------D2 - 2H1S1T6-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.Insert(10)); - CheckTree(mtf, - std::string(R"( -3H3S4T5-------1H1S1T4-------D2 - 2H2S2T6-------D2 - 10H1S1T7------D3 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.ValueFromRank(1, &value)); - EXPECT_EQ(10u, value); -} - -TEST(MoveToFront, Remove) { - MoveToFrontTester mtf; - - EXPECT_FALSE(mtf.Remove(1)); - EXPECT_EQ(0u, mtf.GetTotalNodeCount()); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_TRUE(mtf.Insert(2)); - EXPECT_TRUE(mtf.Insert(3)); - - CheckTree(mtf, - std::string(R"( -2H2S3T2-------1H1S1T1-------D2 - 3H1S1T3-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_EQ(1u, mtf.GetNodeHandle(1)); - EXPECT_EQ(3u, mtf.GetTotalNodeCount()); - EXPECT_TRUE(mtf.Remove(1)); - EXPECT_EQ(3u, mtf.GetTotalNodeCount()); - - CheckTree(mtf, - std::string(R"( -2H2S2T2-------D1 - 3H1S1T3-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - uint32_t value = 0; - EXPECT_TRUE(mtf.ValueFromRank(2, &value)); - EXPECT_EQ(2u, value); - - CheckTree(mtf, - std::string(R"( -3H2S2T3-------D1 - 2H1S1T4-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_EQ(1u, mtf.GetNodeHandle(1)); - EXPECT_EQ(3u, mtf.GetTotalNodeCount()); -} - -TEST(MoveToFront, LargerScale) { - MoveToFrontTester mtf; - uint32_t value = 0; - uint32_t rank = 0; - - for (uint32_t i = 1; i < 1000; ++i) { - ASSERT_TRUE(mtf.Insert(i)); - ASSERT_EQ(i, mtf.GetSize()); - - ASSERT_TRUE(mtf.RankFromValue(i, &rank)); - ASSERT_EQ(1u, rank); - - ASSERT_TRUE(mtf.ValueFromRank(1, &value)); - ASSERT_EQ(i, value); - } - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(1u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(2u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(3u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(4u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(5u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(6u, value); - - ASSERT_TRUE(mtf.ValueFromRank(101, &value)); - ASSERT_EQ(905u, value); - - ASSERT_TRUE(mtf.ValueFromRank(101, &value)); - ASSERT_EQ(906u, value); - - ASSERT_TRUE(mtf.ValueFromRank(101, &value)); - ASSERT_EQ(907u, value); - - ASSERT_TRUE(mtf.ValueFromRank(201, &value)); - ASSERT_EQ(805u, value); - - ASSERT_TRUE(mtf.ValueFromRank(201, &value)); - ASSERT_EQ(806u, value); - - ASSERT_TRUE(mtf.ValueFromRank(201, &value)); - ASSERT_EQ(807u, value); - - ASSERT_TRUE(mtf.ValueFromRank(301, &value)); - ASSERT_EQ(705u, value); - - ASSERT_TRUE(mtf.ValueFromRank(301, &value)); - ASSERT_EQ(706u, value); - - ASSERT_TRUE(mtf.ValueFromRank(301, &value)); - ASSERT_EQ(707u, value); - - ASSERT_TRUE(mtf.RankFromValue(605, &rank)); - ASSERT_EQ(401u, rank); - - ASSERT_TRUE(mtf.RankFromValue(606, &rank)); - ASSERT_EQ(401u, rank); - - ASSERT_TRUE(mtf.RankFromValue(607, &rank)); - ASSERT_EQ(401u, rank); - - ASSERT_TRUE(mtf.ValueFromRank(1, &value)); - ASSERT_EQ(607u, value); - - ASSERT_TRUE(mtf.ValueFromRank(2, &value)); - ASSERT_EQ(606u, value); - - ASSERT_TRUE(mtf.ValueFromRank(3, &value)); - ASSERT_EQ(605u, value); - - ASSERT_TRUE(mtf.ValueFromRank(4, &value)); - ASSERT_EQ(707u, value); - - ASSERT_TRUE(mtf.ValueFromRank(5, &value)); - ASSERT_EQ(706u, value); - - ASSERT_TRUE(mtf.ValueFromRank(6, &value)); - ASSERT_EQ(705u, value); - - ASSERT_TRUE(mtf.ValueFromRank(7, &value)); - ASSERT_EQ(807u, value); - - ASSERT_TRUE(mtf.ValueFromRank(8, &value)); - ASSERT_EQ(806u, value); - - ASSERT_TRUE(mtf.ValueFromRank(9, &value)); - ASSERT_EQ(805u, value); - - ASSERT_TRUE(mtf.ValueFromRank(10, &value)); - ASSERT_EQ(907u, value); - - ASSERT_TRUE(mtf.ValueFromRank(11, &value)); - ASSERT_EQ(906u, value); - - ASSERT_TRUE(mtf.ValueFromRank(12, &value)); - ASSERT_EQ(905u, value); - - ASSERT_TRUE(mtf.ValueFromRank(13, &value)); - ASSERT_EQ(6u, value); - - ASSERT_TRUE(mtf.ValueFromRank(14, &value)); - ASSERT_EQ(5u, value); - - ASSERT_TRUE(mtf.ValueFromRank(15, &value)); - ASSERT_EQ(4u, value); - - ASSERT_TRUE(mtf.ValueFromRank(16, &value)); - ASSERT_EQ(3u, value); - - ASSERT_TRUE(mtf.ValueFromRank(17, &value)); - ASSERT_EQ(2u, value); - - ASSERT_TRUE(mtf.ValueFromRank(18, &value)); - ASSERT_EQ(1u, value); - - ASSERT_TRUE(mtf.ValueFromRank(19, &value)); - ASSERT_EQ(999u, value); - - ASSERT_TRUE(mtf.ValueFromRank(20, &value)); - ASSERT_EQ(998u, value); - - ASSERT_TRUE(mtf.ValueFromRank(21, &value)); - ASSERT_EQ(997u, value); - - ASSERT_TRUE(mtf.RankFromValue(997, &rank)); - ASSERT_EQ(1u, rank); - - ASSERT_TRUE(mtf.RankFromValue(998, &rank)); - ASSERT_EQ(2u, rank); - - ASSERT_TRUE(mtf.RankFromValue(996, &rank)); - ASSERT_EQ(22u, rank); - - ASSERT_TRUE(mtf.Remove(995)); - - ASSERT_TRUE(mtf.RankFromValue(994, &rank)); - ASSERT_EQ(23u, rank); - - for (uint32_t i = 10; i < 1000; ++i) { - if (i != 995) { - ASSERT_TRUE(mtf.Remove(i)); - } else { - ASSERT_FALSE(mtf.Remove(i)); - } - } - - CheckTree(mtf, - std::string(R"( -6H4S9T1029----8H2S3T8-------7H1S1T7-------D3 - 9H1S1T9-------D3 - 2H3S5T1033----4H2S3T1031----5H1S1T1030----D4 - 3H1S1T1032----D4 - 1H1S1T1034----D3 -)") - .substr(1), - /* print_timestamp = */ true); - - ASSERT_TRUE(mtf.Insert(1000)); - ASSERT_TRUE(mtf.ValueFromRank(1, &value)); - ASSERT_EQ(1000u, value); -} - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/dead_branch_elim_test.cpp b/3rdparty/spirv-tools/test/opt/dead_branch_elim_test.cpp index eec11f258..640d4e8a9 100644 --- a/3rdparty/spirv-tools/test/opt/dead_branch_elim_test.cpp +++ b/3rdparty/spirv-tools/test/opt/dead_branch_elim_test.cpp @@ -2993,6 +2993,94 @@ OpFunctionEnd SinglePassRunAndMatch(spirv, true); } +// Fold a switch with a nested break. The only case should be the default. +TEST_F(DeadBranchElimTest, FoldSwitchWithNestedBreak) { + const std::string spirv = R"( +; CHECK: OpSwitch %int_3 [[case_bb:%\w+]]{{[[:space:]]}} +; CHECK: [[case_bb]] = OpLabel +; CHECK-NEXT: OpUndef +; CHECK-NEXT: OpSelectionMerge + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %2 "main" + OpSource GLSL 450 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_3 = OpConstant %int 3 + %int_1 = OpConstant %int 1 + %bool = OpTypeBool + %2 = OpFunction %void None %4 + %10 = OpLabel + OpSelectionMerge %11 None + OpSwitch %int_3 %12 3 %13 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + %14 = OpUndef %bool + OpSelectionMerge %15 None + OpBranchConditional %14 %16 %15 + %16 = OpLabel + OpBranch %11 + %15 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(DeadBranchElimTest, FoldBranchWithBreakToSwitch) { + const std::string spirv = R"( +; CHECK: OpSelectionMerge [[sel_merge:%\w+]] +; CHECK-NEXT: OpSwitch {{%\w+}} {{%\w+}} 3 [[bb:%\w+]] +; CHECK: [[bb]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NOT: OpSelectionMerge +; CHECK: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %2 "main" + OpSource GLSL 450 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_3 = OpConstant %int 3 + %int_1 = OpConstant %int 1 + %bool = OpTypeBool + %true = OpConstantTrue %bool + %2 = OpFunction %void None %4 + %10 = OpLabel + %undef_int = OpUndef %int + OpSelectionMerge %11 None + OpSwitch %undef_int %12 3 %13 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpSelectionMerge %15 None + OpBranchConditional %true %16 %15 + %16 = OpLabel + %14 = OpUndef %bool + OpBranchConditional %14 %11 %17 + %17 = OpLabel + OpBranch %15 + %15 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(spirv, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // More complex control flow diff --git a/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp b/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp index 12f0cd125..c96dc8c5a 100644 --- a/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp +++ b/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp @@ -325,6 +325,19 @@ INSTANTIATE_TEST_SUITE_P( "%inner = OpConstantComposite %inner_struct %bool_true %signed_one %undef", "%outer = OpSpecConstantComposite %outer_struct %inner %signed_one", }, + }, + // Fold an QuantizetoF16 instruction + { + // original + { + "%float_1 = OpConstant %float 1", + "%quant_float = OpSpecConstantOp %float QuantizeToF16 %float_1", + }, + // expected + { + "%float_1 = OpConstant %float 1", + "%quant_float = OpConstant %float 1", + }, } // clang-format on }))); @@ -1135,14 +1148,14 @@ INSTANTIATE_TEST_SUITE_P( "%outer = OpConstantComposite %outer_struct %inner %signed_one", "%extract_inner = OpSpecConstantOp %inner_struct CompositeExtract %outer 0", "%extract_int = OpSpecConstantOp %int CompositeExtract %outer 1", - "%extract_inner_float = OpSpecConstantOp %int CompositeExtract %outer 0 2", + "%extract_inner_float = OpSpecConstantOp %float CompositeExtract %outer 0 2", }, // expected { "%float_1 = OpConstant %float 1", "%inner = OpConstantComposite %inner_struct %bool_true %signed_null %float_1", "%outer = OpConstantComposite %outer_struct %inner %signed_one", - "%extract_inner = OpConstantComposite %flat_struct %bool_true %signed_null %float_1", + "%extract_inner = OpConstantComposite %inner_struct %bool_true %signed_null %float_1", "%extract_int = OpConstant %int 1", "%extract_inner_float = OpConstant %float 1", }, @@ -1256,13 +1269,9 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%60 = OpConstantNull %int", "%a = OpConstantComposite %v2int %signed_null %signed_null", - "%62 = OpConstantNull %int", "%b = OpConstantComposite %v2int %signed_zero %signed_one", - "%64 = OpConstantNull %int", "%c = OpConstantComposite %v2int %signed_three %signed_null", - "%66 = OpConstantNull %int", "%d = OpConstantComposite %v2int %signed_null %signed_null", } }, diff --git a/3rdparty/spirv-tools/test/opt/fold_test.cpp b/3rdparty/spirv-tools/test/opt/fold_test.cpp index d7b59171d..3ea320463 100644 --- a/3rdparty/spirv-tools/test/opt/fold_test.cpp +++ b/3rdparty/spirv-tools/test/opt/fold_test.cpp @@ -206,7 +206,14 @@ OpName %main "main" %float_2 = OpConstant %float 2 %float_3 = OpConstant %float 3 %float_4 = OpConstant %float 4 +%float_2049 = OpConstant %float 2049 +%float_n2049 = OpConstant %float -2049 %float_0p5 = OpConstant %float 0.5 +%float_pi = OpConstant %float 1.5555 +%float_1e16 = OpConstant %float 1e16 +%float_n1e16 = OpConstant %float -1e16 +%float_1en16 = OpConstant %float 1e-16 +%float_n1en16 = OpConstant %float -1e-16 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3 @@ -1273,7 +1280,11 @@ TEST_P(FloatInstructionFoldingTest, Case) { const_mrg->GetConstantFromInst(inst)->AsFloatConstant(); EXPECT_NE(result, nullptr); if (result != nullptr) { - EXPECT_EQ(result->GetFloatValue(), tc.expected_result); + if (!std::isnan(tc.expected_result)) { + EXPECT_EQ(result->GetFloatValue(), tc.expected_result); + } else { + EXPECT_TRUE(std::isnan(result->GetFloatValue())); + } } } } @@ -1388,7 +1399,89 @@ INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest, "%2 = OpFNegate %float %float_2\n" + "OpReturn\n" + "OpFunctionEnd", - 2, -2) + 2, -2), + // Test case 12: QuantizeToF16 1.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0), + // Test case 13: QuantizeToF16 positive non exact + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_2049\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2048), + // Test case 14: QuantizeToF16 negative non exact + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_n2049\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -2048), + // Test case 15: QuantizeToF16 large positive + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_1e16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, std::numeric_limits::infinity()), + // Test case 16: QuantizeToF16 large negative + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_n1e16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -std::numeric_limits::infinity()), + // Test case 17: QuantizeToF16 small positive + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_1en16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 18: QuantizeToF16 small negative + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_n1en16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 19: QuantizeToF16 nan + InstructionFoldingCase( + HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_nan\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, std::numeric_limits::quiet_NaN()), + // Test case 20: QuantizeToF16 inf + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFDiv %float %float_1 %float_0\n" + + "%3 = OpQuantizeToF16 %float %3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, std::numeric_limits::infinity()), + // Test case 21: QuantizeToF16 -inf + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFDiv %float %float_n1 %float_0\n" + + "%3 = OpQuantizeToF16 %float %3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -std::numeric_limits::infinity()) )); // clang-format on @@ -4051,7 +4144,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4068,7 +4161,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4102,7 +4195,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4119,7 +4212,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4136,7 +4229,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4218,7 +4311,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4236,7 +4329,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4287,7 +4380,7 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + - "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" + + "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4337,11 +4430,11 @@ INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4\n" + - "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" + - "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + - "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3\n" + + "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" + + "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" + + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + + "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" + "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" + "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4710,9 +4803,9 @@ INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + - "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + - "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" + + "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" + "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" + @@ -4730,9 +4823,9 @@ INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + - "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + - "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" + + "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" + "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" + @@ -5026,7 +5119,7 @@ INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpSDiv [[int]] [[ld]] [[int_n2]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -5044,7 +5137,7 @@ INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpSDiv [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -5324,7 +5417,7 @@ INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -5358,7 +5451,7 @@ INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + - "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" + + "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + diff --git a/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp b/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp index 94a37cfe2..4a0fde895 100644 --- a/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp +++ b/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp @@ -13,6 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Bindless Check Instrumentation Tests. +// Tests ending with V2 use version 2 record format. + #include #include @@ -4226,6 +4229,4053 @@ OpFunctionEnd true); } +TEST_F(InstBindlessTest, SimpleV2) { + // Texture2D g_tColor[128]; + // + // layout(push_constant) cbuffer PerViewConstantBuffer_t + // { + // uint g_nDataIdx; + // }; + // + // SamplerState g_sAniso; + // + // struct PS_INPUT + // { + // float2 vTextureCoords : TEXCOORD2; + // }; + // + // struct PS_OUTPUT + // { + // float4 vColor : SV_Target0; + // }; + // + // PS_OUTPUT MainPs(PS_INPUT i) + // { + // PS_OUTPUT ps_output; + // ps_output.vColor = + // g_tColor[ g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy); + // return ps_output; + // } + + const std::string entry_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +)"; + + const std::string entry_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +)"; + + const std::string names_annots = + R"(OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)"; + + const std::string new_annots = + R"(OpDecorate %_runtimearr_uint ArrayStride 4 +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 +)"; + + const std::string consts_types_vars = + R"(%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%16 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_16_uint_128 = OpTypeArray %16 %uint_128 +%_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 +%24 = OpTypeSampler +%_ptr_UniformConstant_24 = OpTypePointer UniformConstant %24 +%g_sAniso = OpVariable %_ptr_UniformConstant_24 UniformConstant +%26 = OpTypeSampledImage %16 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string new_consts_types_vars = + R"(%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%48 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_56 = OpConstant %uint 56 +%103 = OpConstantNull %v4float +)"; + + const std::string func_pt1 = + R"(%MainPs = OpFunction %void None %10 +%29 = OpLabel +%30 = OpLoad %v2float %i_vTextureCoords +%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%32 = OpLoad %uint %31 +%33 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %32 +%34 = OpLoad %16 %33 +%35 = OpLoad %24 %g_sAniso +%36 = OpSampledImage %26 %34 %35 +)"; + + const std::string func_pt2_before = + R"(%37 = OpImageSampleImplicitLod %v4float %36 %30 +OpStore %_entryPointOutput_vColor %37 +OpReturn +OpFunctionEnd +)"; + + const std::string func_pt2_after = + R"(%40 = OpULessThan %bool %32 %uint_128 +OpSelectionMerge %41 None +OpBranchConditional %40 %42 %43 +%42 = OpLabel +%44 = OpLoad %16 %33 +%45 = OpSampledImage %26 %44 %35 +%46 = OpImageSampleImplicitLod %v4float %45 %30 +OpBranch %41 +%43 = OpLabel +%102 = OpFunctionCall %void %47 %uint_56 %uint_0 %32 %uint_128 +OpBranch %41 +%41 = OpLabel +%104 = OpPhi %v4float %46 %42 %103 %43 +OpStore %_entryPointOutput_vColor %104 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%47 = OpFunction %void None %48 +%49 = OpFunctionParameter %uint +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpLabel +%59 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%62 = OpAtomicIAdd %uint %59 %uint_4 %uint_0 %uint_10 +%63 = OpIAdd %uint %62 %uint_10 +%64 = OpArrayLength %uint %57 1 +%65 = OpULessThanEqual %bool %63 %64 +OpSelectionMerge %66 None +OpBranchConditional %65 %67 %66 +%67 = OpLabel +%68 = OpIAdd %uint %62 %uint_0 +%70 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %68 +OpStore %70 %uint_10 +%72 = OpIAdd %uint %62 %uint_1 +%73 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %72 +OpStore %73 %uint_23 +%75 = OpIAdd %uint %62 %uint_2 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %49 +%78 = OpIAdd %uint %62 %uint_3 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %78 +OpStore %79 %uint_4 +%82 = OpLoad %v4float %gl_FragCoord +%84 = OpBitcast %v4uint %82 +%85 = OpCompositeExtract %uint %84 0 +%86 = OpIAdd %uint %62 %uint_4 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %86 +OpStore %87 %85 +%88 = OpCompositeExtract %uint %84 1 +%90 = OpIAdd %uint %62 %uint_5 +%91 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %90 +OpStore %91 %88 +%93 = OpIAdd %uint %62 %uint_7 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %93 +OpStore %94 %50 +%96 = OpIAdd %uint %62 %uint_8 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %96 +OpStore %97 %51 +%99 = OpIAdd %uint %62 %uint_9 +%100 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %99 +OpStore %100 %52 +OpBranch %66 +%66 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + entry_before + names_annots + consts_types_vars + func_pt1 + + func_pt2_before, + entry_after + names_annots + new_annots + consts_types_vars + + new_consts_types_vars + func_pt1 + func_pt2_after + output_func, + true, true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstrumentMultipleInstructionsV2) { + // Texture2D g_tColor[128]; + // + // layout(push_constant) cbuffer PerViewConstantBuffer_t + // { + // uint g_nDataIdx; + // uint g_nDataIdx2; + // }; + // + // SamplerState g_sAniso; + // + // struct PS_INPUT + // { + // float2 vTextureCoords : TEXCOORD2; + // }; + // + // struct PS_OUTPUT + // { + // float4 vColor : SV_Target0; + // }; + // + // PS_OUTPUT MainPs(PS_INPUT i) + // { + // PS_OUTPUT ps_output; + // + // float t = g_tColor[g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy); + // float t2 = g_tColor[g_nDataIdx2].Sample(g_sAniso, i.vTextureCoords.xy); + // ps_output.vColor = t + t2; + // return ps_output; + // } + + const std::string defs_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%17 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_17_uint_128 = OpTypeArray %17 %uint_128 +%_ptr_UniformConstant__arr_17_uint_128 = OpTypePointer UniformConstant %_arr_17_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_17_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%25 = OpTypeSampler +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 +%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant +%27 = OpTypeSampledImage %17 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%17 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_17_uint_128 = OpTypeArray %17 %uint_128 +%_ptr_UniformConstant__arr_17_uint_128 = OpTypePointer UniformConstant %_arr_17_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_17_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%25 = OpTypeSampler +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 +%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant +%27 = OpTypeSampledImage %17 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%56 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_58 = OpConstant %uint 58 +%111 = OpConstantNull %v4float +%uint_64 = OpConstant %uint 64 +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %10 +%30 = OpLabel +%31 = OpLoad %v2float %i_vTextureCoords +%32 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%33 = OpLoad %uint %32 +%34 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %33 +%35 = OpLoad %17 %34 +%36 = OpLoad %25 %g_sAniso +%37 = OpSampledImage %27 %35 %36 +%38 = OpImageSampleImplicitLod %v4float %37 %31 +%39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +%40 = OpLoad %uint %39 +%41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 +%42 = OpLoad %17 %41 +%43 = OpSampledImage %27 %42 %36 +%44 = OpImageSampleImplicitLod %v4float %43 %31 +%45 = OpFAdd %v4float %38 %44 +OpStore %_entryPointOutput_vColor %45 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %10 +%30 = OpLabel +%31 = OpLoad %v2float %i_vTextureCoords +%32 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%33 = OpLoad %uint %32 +%34 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %33 +%35 = OpLoad %17 %34 +%36 = OpLoad %25 %g_sAniso +%37 = OpSampledImage %27 %35 %36 +%48 = OpULessThan %bool %33 %uint_128 +OpSelectionMerge %49 None +OpBranchConditional %48 %50 %51 +%50 = OpLabel +%52 = OpLoad %17 %34 +%53 = OpSampledImage %27 %52 %36 +%54 = OpImageSampleImplicitLod %v4float %53 %31 +OpBranch %49 +%51 = OpLabel +%110 = OpFunctionCall %void %55 %uint_58 %uint_0 %33 %uint_128 +OpBranch %49 +%49 = OpLabel +%112 = OpPhi %v4float %54 %50 %111 %51 +%39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +%40 = OpLoad %uint %39 +%41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 +%42 = OpLoad %17 %41 +%43 = OpSampledImage %27 %42 %36 +%113 = OpULessThan %bool %40 %uint_128 +OpSelectionMerge %114 None +OpBranchConditional %113 %115 %116 +%115 = OpLabel +%117 = OpLoad %17 %41 +%118 = OpSampledImage %27 %117 %36 +%119 = OpImageSampleImplicitLod %v4float %118 %31 +OpBranch %114 +%116 = OpLabel +%121 = OpFunctionCall %void %55 %uint_64 %uint_0 %40 %uint_128 +OpBranch %114 +%114 = OpLabel +%122 = OpPhi %v4float %119 %115 %111 %116 +%45 = OpFAdd %v4float %112 %122 +OpStore %_entryPointOutput_vColor %45 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%55 = OpFunction %void None %56 +%57 = OpFunctionParameter %uint +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpLabel +%67 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%70 = OpAtomicIAdd %uint %67 %uint_4 %uint_0 %uint_10 +%71 = OpIAdd %uint %70 %uint_10 +%72 = OpArrayLength %uint %65 1 +%73 = OpULessThanEqual %bool %71 %72 +OpSelectionMerge %74 None +OpBranchConditional %73 %75 %74 +%75 = OpLabel +%76 = OpIAdd %uint %70 %uint_0 +%78 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %76 +OpStore %78 %uint_10 +%80 = OpIAdd %uint %70 %uint_1 +%81 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %80 +OpStore %81 %uint_23 +%83 = OpIAdd %uint %70 %uint_2 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %83 +OpStore %84 %57 +%86 = OpIAdd %uint %70 %uint_3 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %86 +OpStore %87 %uint_4 +%90 = OpLoad %v4float %gl_FragCoord +%92 = OpBitcast %v4uint %90 +%93 = OpCompositeExtract %uint %92 0 +%94 = OpIAdd %uint %70 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %93 +%96 = OpCompositeExtract %uint %92 1 +%98 = OpIAdd %uint %70 %uint_5 +%99 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %98 +OpStore %99 %96 +%101 = OpIAdd %uint %70 %uint_7 +%102 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %101 +OpStore %102 %58 +%104 = OpIAdd %uint %70 %uint_8 +%105 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %104 +OpStore %105 %59 +%107 = OpIAdd %uint %70 %uint_9 +%108 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %107 +OpStore %108 %60 +OpBranch %74 +%74 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstrumentOpImageV2) { + // This test verifies that the pass will correctly instrument shader + // using OpImage. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability StorageImageReadWithoutFormat +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%39 = OpTypeSampledImage %20 +%_arr_39_uint_128 = OpTypeArray %39 %uint_128 +%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability StorageImageReadWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_51 Block +OpMemberDecorate %_struct_51 0 Offset 0 +OpMemberDecorate %_struct_51 1 Offset 4 +OpDecorate %53 DescriptorSet 7 +OpDecorate %53 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%15 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%18 = OpTypeSampledImage %15 +%_arr_18_uint_128 = OpTypeArray %18 %uint_128 +%_ptr_UniformConstant__arr_18_uint_128 = OpTypePointer UniformConstant %_arr_18_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_18_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%44 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_51 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_51 = OpTypePointer StorageBuffer %_struct_51 +%53 = OpVariable %_ptr_StorageBuffer__struct_51 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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%99 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2int %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64 +%66 = OpLoad %39 %65 +%75 = OpImage %20 %66 +%71 = OpImageRead %v4float %75 %53 +OpStore %_entryPointOutput_vColor %71 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %9 +%26 = OpLabel +%27 = OpLoad %v2int %i_vTextureCoords +%28 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%29 = OpLoad %uint %28 +%30 = OpAccessChain %_ptr_UniformConstant_18 %g_tColor %29 +%31 = OpLoad %18 %30 +%32 = OpImage %15 %31 +%36 = OpULessThan %bool %29 %uint_128 +OpSelectionMerge %37 None +OpBranchConditional %36 %38 %39 +%38 = OpLabel +%40 = OpLoad %18 %30 +%41 = OpImage %15 %40 +%42 = OpImageRead %v4float %41 %27 +OpBranch %37 +%39 = OpLabel +%98 = OpFunctionCall %void %43 %uint_51 %uint_0 %29 %uint_128 +OpBranch %37 +%37 = OpLabel +%100 = OpPhi %v4float %42 %38 %99 %39 +OpStore %_entryPointOutput_vColor %100 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%43 = OpFunction %void None %44 +%45 = OpFunctionParameter %uint +%46 = OpFunctionParameter %uint +%47 = OpFunctionParameter %uint +%48 = OpFunctionParameter %uint +%49 = OpLabel +%55 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_0 +%58 = OpAtomicIAdd %uint %55 %uint_4 %uint_0 %uint_10 +%59 = OpIAdd %uint %58 %uint_10 +%60 = OpArrayLength %uint %53 1 +%61 = OpULessThanEqual %bool %59 %60 +OpSelectionMerge %62 None +OpBranchConditional %61 %63 %62 +%63 = OpLabel +%64 = OpIAdd %uint %58 %uint_0 +%66 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %64 +OpStore %66 %uint_10 +%68 = OpIAdd %uint %58 %uint_1 +%69 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %68 +OpStore %69 %uint_23 +%71 = OpIAdd %uint %58 %uint_2 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %71 +OpStore %72 %45 +%74 = OpIAdd %uint %58 %uint_3 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %74 +OpStore %75 %uint_4 +%78 = OpLoad %v4float %gl_FragCoord +%80 = OpBitcast %v4uint %78 +%81 = OpCompositeExtract %uint %80 0 +%82 = OpIAdd %uint %58 %uint_4 +%83 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %82 +OpStore %83 %81 +%84 = OpCompositeExtract %uint %80 1 +%86 = OpIAdd %uint %58 %uint_5 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %86 +OpStore %87 %84 +%89 = OpIAdd %uint %58 %uint_7 +%90 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %89 +OpStore %90 %46 +%92 = OpIAdd %uint %58 %uint_8 +%93 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %92 +OpStore %93 %47 +%95 = OpIAdd %uint %58 %uint_9 +%96 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %95 +OpStore %96 %48 +OpBranch %62 +%62 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstrumentSampledImageV2) { + // This test verifies that the pass will correctly instrument shader + // using sampled image. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%39 = OpTypeSampledImage %20 +%_arr_39_uint_128 = OpTypeArray %39 %uint_128 +%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_49 Block +OpMemberDecorate %_struct_49 0 Offset 0 +OpMemberDecorate %_struct_49 1 Offset 4 +OpDecorate %51 DescriptorSet 7 +OpDecorate %51 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%15 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%18 = OpTypeSampledImage %15 +%_arr_18_uint_128 = OpTypeArray %18 %uint_128 +%_ptr_UniformConstant__arr_18_uint_128 = OpTypePointer UniformConstant %_arr_18_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_18_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%42 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_49 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_49 = OpTypePointer StorageBuffer %_struct_49 +%51 = OpVariable %_ptr_StorageBuffer__struct_49 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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_49 = OpConstant %uint 49 +%97 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2float %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64 +%66 = OpLoad %39 %65 +%71 = OpImageSampleImplicitLod %v4float %66 %53 +OpStore %_entryPointOutput_vColor %71 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %9 +%26 = OpLabel +%27 = OpLoad %v2float %i_vTextureCoords +%28 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%29 = OpLoad %uint %28 +%30 = OpAccessChain %_ptr_UniformConstant_18 %g_tColor %29 +%31 = OpLoad %18 %30 +%35 = OpULessThan %bool %29 %uint_128 +OpSelectionMerge %36 None +OpBranchConditional %35 %37 %38 +%37 = OpLabel +%39 = OpLoad %18 %30 +%40 = OpImageSampleImplicitLod %v4float %39 %27 +OpBranch %36 +%38 = OpLabel +%96 = OpFunctionCall %void %41 %uint_49 %uint_0 %29 %uint_128 +OpBranch %36 +%36 = OpLabel +%98 = OpPhi %v4float %40 %37 %97 %38 +OpStore %_entryPointOutput_vColor %98 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%41 = OpFunction %void None %42 +%43 = OpFunctionParameter %uint +%44 = OpFunctionParameter %uint +%45 = OpFunctionParameter %uint +%46 = OpFunctionParameter %uint +%47 = OpLabel +%53 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_0 +%56 = OpAtomicIAdd %uint %53 %uint_4 %uint_0 %uint_10 +%57 = OpIAdd %uint %56 %uint_10 +%58 = OpArrayLength %uint %51 1 +%59 = OpULessThanEqual %bool %57 %58 +OpSelectionMerge %60 None +OpBranchConditional %59 %61 %60 +%61 = OpLabel +%62 = OpIAdd %uint %56 %uint_0 +%64 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %62 +OpStore %64 %uint_10 +%66 = OpIAdd %uint %56 %uint_1 +%67 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %66 +OpStore %67 %uint_23 +%69 = OpIAdd %uint %56 %uint_2 +%70 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %69 +OpStore %70 %43 +%72 = OpIAdd %uint %56 %uint_3 +%73 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %72 +OpStore %73 %uint_4 +%76 = OpLoad %v4float %gl_FragCoord +%78 = OpBitcast %v4uint %76 +%79 = OpCompositeExtract %uint %78 0 +%80 = OpIAdd %uint %56 %uint_4 +%81 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %80 +OpStore %81 %79 +%82 = OpCompositeExtract %uint %78 1 +%84 = OpIAdd %uint %56 %uint_5 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %84 +OpStore %85 %82 +%87 = OpIAdd %uint %56 %uint_7 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %87 +OpStore %88 %44 +%90 = OpIAdd %uint %56 %uint_8 +%91 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %90 +OpStore %91 %45 +%93 = OpIAdd %uint %56 %uint_9 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %93 +OpStore %94 %46 +OpBranch %60 +%60 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstrumentImageWriteV2) { + // This test verifies that the pass will correctly instrument shader + // doing bindless image write. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability StorageImageWriteWithoutFormat +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%80 = OpConstantNull %v4float +%_arr_20_uint_128 = OpTypeArray %20 %uint_128 +%_ptr_UniformConstant__arr_20_uint_128 = OpTypePointer UniformConstant %_arr_20_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_20_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability StorageImageWriteWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_48 Block +OpMemberDecorate %_struct_48 0 Offset 0 +OpMemberDecorate %_struct_48 1 Offset 4 +OpDecorate %50 DescriptorSet 7 +OpDecorate %50 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%16 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%19 = OpConstantNull %v4float +%_arr_16_uint_128 = OpTypeArray %16 %uint_128 +%_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%41 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_48 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_48 = OpTypePointer StorageBuffer %_struct_48 +%50 = OpVariable %_ptr_StorageBuffer__struct_48 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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2int %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64 +%66 = OpLoad %20 %65 +OpImageWrite %66 %53 %80 +OpStore %_entryPointOutput_vColor %80 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %9 +%27 = OpLabel +%28 = OpLoad %v2int %i_vTextureCoords +%29 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%30 = OpLoad %uint %29 +%31 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %30 +%32 = OpLoad %16 %31 +%35 = OpULessThan %bool %30 %uint_128 +OpSelectionMerge %36 None +OpBranchConditional %35 %37 %38 +%37 = OpLabel +%39 = OpLoad %16 %31 +OpImageWrite %39 %28 %19 +OpBranch %36 +%38 = OpLabel +%95 = OpFunctionCall %void %40 %uint_51 %uint_0 %30 %uint_128 +OpBranch %36 +%36 = OpLabel +OpStore %_entryPointOutput_vColor %19 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%40 = OpFunction %void None %41 +%42 = OpFunctionParameter %uint +%43 = OpFunctionParameter %uint +%44 = OpFunctionParameter %uint +%45 = OpFunctionParameter %uint +%46 = OpLabel +%52 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_0 +%55 = OpAtomicIAdd %uint %52 %uint_4 %uint_0 %uint_10 +%56 = OpIAdd %uint %55 %uint_10 +%57 = OpArrayLength %uint %50 1 +%58 = OpULessThanEqual %bool %56 %57 +OpSelectionMerge %59 None +OpBranchConditional %58 %60 %59 +%60 = OpLabel +%61 = OpIAdd %uint %55 %uint_0 +%63 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %61 +OpStore %63 %uint_10 +%65 = OpIAdd %uint %55 %uint_1 +%66 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %65 +OpStore %66 %uint_23 +%68 = OpIAdd %uint %55 %uint_2 +%69 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %68 +OpStore %69 %42 +%71 = OpIAdd %uint %55 %uint_3 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %71 +OpStore %72 %uint_4 +%75 = OpLoad %v4float %gl_FragCoord +%77 = OpBitcast %v4uint %75 +%78 = OpCompositeExtract %uint %77 0 +%79 = OpIAdd %uint %55 %uint_4 +%80 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %79 +OpStore %80 %78 +%81 = OpCompositeExtract %uint %77 1 +%83 = OpIAdd %uint %55 %uint_5 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %83 +OpStore %84 %81 +%86 = OpIAdd %uint %55 %uint_7 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %86 +OpStore %87 %43 +%89 = OpIAdd %uint %55 %uint_8 +%90 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %89 +OpStore %90 %44 +%92 = OpIAdd %uint %55 %uint_9 +%93 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %92 +OpStore %93 %45 +OpBranch %59 +%59 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstrumentVertexSimpleV2) { + // This test verifies that the pass will correctly instrument shader + // doing bindless image write. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %_ %coords2D +OpSource GLSL 450 +OpName %main "main" +OpName %lod "lod" +OpName %coords1D "coords1D" +OpName %gl_PerVertex "gl_PerVertex" +OpMemberName %gl_PerVertex 0 "gl_Position" +OpMemberName %gl_PerVertex 1 "gl_PointSize" +OpMemberName %gl_PerVertex 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex 3 "gl_CullDistance" +OpName %_ "" +OpName %texSampler1D "texSampler1D" +OpName %foo "foo" +OpMemberName %foo 0 "g_idx" +OpName %__0 "" +OpName %coords2D "coords2D" +OpMemberDecorate %gl_PerVertex 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex Block +OpDecorate %texSampler1D DescriptorSet 0 +OpDecorate %texSampler1D Binding 3 +OpMemberDecorate %foo 0 Offset 0 +OpDecorate %foo Block +OpDecorate %__0 DescriptorSet 0 +OpDecorate %__0 Binding 5 +OpDecorate %coords2D Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_3 = OpConstant %float 3 +%float_1_78900003 = OpConstant %float 1.78900003 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex +%_ = OpVariable %_ptr_Output_gl_PerVertex Output +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%21 = OpTypeImage %float 1D 0 0 0 1 Unknown +%22 = OpTypeSampledImage %21 +%uint_128 = OpConstant %uint 128 +%_arr_22_uint_128 = OpTypeArray %22 %uint_128 +%_ptr_UniformConstant__arr_22_uint_128 = OpTypePointer UniformConstant %_arr_22_uint_128 +%texSampler1D = OpVariable %_ptr_UniformConstant__arr_22_uint_128 UniformConstant +%foo = OpTypeStruct %int +%_ptr_Uniform_foo = OpTypePointer Uniform %foo +%__0 = OpVariable %_ptr_Uniform_foo Uniform +%_ptr_Uniform_int = OpTypePointer Uniform %int +%_ptr_UniformConstant_22 = OpTypePointer UniformConstant %22 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%coords2D = OpVariable %_ptr_Input_v2float Input +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Sampled1D +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexIndex %gl_InstanceIndex +OpSource GLSL 450 +OpName %main "main" +OpName %lod "lod" +OpName %coords1D "coords1D" +OpName %gl_PerVertex "gl_PerVertex" +OpMemberName %gl_PerVertex 0 "gl_Position" +OpMemberName %gl_PerVertex 1 "gl_PointSize" +OpMemberName %gl_PerVertex 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex 3 "gl_CullDistance" +OpName %_ "" +OpName %texSampler1D "texSampler1D" +OpName %foo "foo" +OpMemberName %foo 0 "g_idx" +OpName %__0 "" +OpName %coords2D "coords2D" +OpMemberDecorate %gl_PerVertex 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex Block +OpDecorate %texSampler1D DescriptorSet 0 +OpDecorate %texSampler1D Binding 3 +OpMemberDecorate %foo 0 Offset 0 +OpDecorate %foo Block +OpDecorate %__0 DescriptorSet 0 +OpDecorate %__0 Binding 5 +OpDecorate %coords2D Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_61 Block +OpMemberDecorate %_struct_61 0 Offset 0 +OpMemberDecorate %_struct_61 1 Offset 4 +OpDecorate %63 DescriptorSet 7 +OpDecorate %63 Binding 0 +OpDecorate %gl_VertexIndex BuiltIn VertexIndex +OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +%void = OpTypeVoid +%12 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_3 = OpConstant %float 3 +%float_1_78900003 = OpConstant %float 1.78900003 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex +%_ = OpVariable %_ptr_Output_gl_PerVertex Output +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%24 = OpTypeImage %float 1D 0 0 0 1 Unknown +%25 = OpTypeSampledImage %24 +%uint_128 = OpConstant %uint 128 +%_arr_25_uint_128 = OpTypeArray %25 %uint_128 +%_ptr_UniformConstant__arr_25_uint_128 = OpTypePointer UniformConstant %_arr_25_uint_128 +%texSampler1D = OpVariable %_ptr_UniformConstant__arr_25_uint_128 UniformConstant +%foo = OpTypeStruct %int +%_ptr_Uniform_foo = OpTypePointer Uniform %foo +%__0 = OpVariable %_ptr_Uniform_foo Uniform +%_ptr_Uniform_int = OpTypePointer Uniform %int +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%coords2D = OpVariable %_ptr_Input_v2float Input +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%54 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_61 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_61 = OpTypePointer StorageBuffer %_struct_61 +%63 = OpVariable %_ptr_StorageBuffer__struct_61 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_uint = OpTypePointer Input %uint +%gl_VertexIndex = OpVariable %_ptr_Input_uint Input +%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_74 = OpConstant %uint 74 +%106 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%lod = OpVariable %_ptr_Function_float Function +%coords1D = OpVariable %_ptr_Function_float Function +OpStore %lod %float_3 +OpStore %coords1D %float_1_78900003 +%31 = OpAccessChain %_ptr_Uniform_int %__0 %int_0 +%32 = OpLoad %int %31 +%34 = OpAccessChain %_ptr_UniformConstant_22 %texSampler1D %32 +%35 = OpLoad %22 %34 +%36 = OpLoad %float %coords1D +%37 = OpLoad %float %lod +%38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37 +%40 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +OpStore %40 %38 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %12 +%35 = OpLabel +%lod = OpVariable %_ptr_Function_float Function +%coords1D = OpVariable %_ptr_Function_float Function +OpStore %lod %float_3 +OpStore %coords1D %float_1_78900003 +%36 = OpAccessChain %_ptr_Uniform_int %__0 %int_0 +%37 = OpLoad %int %36 +%38 = OpAccessChain %_ptr_UniformConstant_25 %texSampler1D %37 +%39 = OpLoad %25 %38 +%40 = OpLoad %float %coords1D +%41 = OpLoad %float %lod +%46 = OpULessThan %bool %37 %uint_128 +OpSelectionMerge %47 None +OpBranchConditional %46 %48 %49 +%48 = OpLabel +%50 = OpLoad %25 %38 +%51 = OpImageSampleExplicitLod %v4float %50 %40 Lod %41 +OpBranch %47 +%49 = OpLabel +%52 = OpBitcast %uint %37 +%105 = OpFunctionCall %void %53 %uint_74 %uint_0 %52 %uint_128 +OpBranch %47 +%47 = OpLabel +%107 = OpPhi %v4float %51 %48 %106 %49 +%43 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +OpStore %43 %107 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%53 = OpFunction %void None %54 +%55 = OpFunctionParameter %uint +%56 = OpFunctionParameter %uint +%57 = OpFunctionParameter %uint +%58 = OpFunctionParameter %uint +%59 = OpLabel +%65 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_0 +%68 = OpAtomicIAdd %uint %65 %uint_4 %uint_0 %uint_10 +%69 = OpIAdd %uint %68 %uint_10 +%70 = OpArrayLength %uint %63 1 +%71 = OpULessThanEqual %bool %69 %70 +OpSelectionMerge %72 None +OpBranchConditional %71 %73 %72 +%73 = OpLabel +%74 = OpIAdd %uint %68 %uint_0 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %74 +OpStore %75 %uint_10 +%77 = OpIAdd %uint %68 %uint_1 +%78 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %77 +OpStore %78 %uint_23 +%80 = OpIAdd %uint %68 %uint_2 +%81 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %80 +OpStore %81 %55 +%83 = OpIAdd %uint %68 %uint_3 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %83 +OpStore %84 %uint_0 +%87 = OpLoad %uint %gl_VertexIndex +%88 = OpIAdd %uint %68 %uint_4 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %88 +OpStore %89 %87 +%91 = OpLoad %uint %gl_InstanceIndex +%93 = OpIAdd %uint %68 %uint_5 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %93 +OpStore %94 %91 +%96 = OpIAdd %uint %68 %uint_7 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %96 +OpStore %97 %56 +%99 = OpIAdd %uint %68 %uint_8 +%100 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %99 +OpStore %100 %57 +%102 = OpIAdd %uint %68 %uint_9 +%103 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %102 +OpStore %103 %58 +OpBranch %72 +%72 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, MultipleDebugFunctionsV2) { + // Same source as Simple, but compiled -g and not optimized, especially not + // inlined. The OpSource has had the source extracted for the sake of brevity. + + const std::string defs_before = + R"(OpCapability Shader +%2 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +%1 = OpString "foo5.frag" +OpSource HLSL 500 %1 +OpName %MainPs "MainPs" +OpName %PS_INPUT "PS_INPUT" +OpMemberName %PS_INPUT 0 "vTextureCoords" +OpName %PS_OUTPUT "PS_OUTPUT" +OpMemberName %PS_OUTPUT 0 "vColor" +OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;" +OpName %i "i" +OpName %ps_output "ps_output" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_0 "i" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpName %param "param" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 1 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%PS_INPUT = OpTypeStruct %v2float +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +%v4float = OpTypeVector %float 4 +%PS_OUTPUT = OpTypeStruct %v4float +%13 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%21 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_21_uint_128 = OpTypeArray %21 %uint_128 +%_ptr_UniformConstant__arr_21_uint_128 = OpTypePointer UniformConstant %_arr_21_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_21_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 +%36 = OpTypeSampler +%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 +%g_sAniso = OpVariable %_ptr_UniformConstant_36 UniformConstant +%40 = OpTypeSampledImage %21 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +%5 = OpString "foo5.frag" +OpSource HLSL 500 %5 +OpName %MainPs "MainPs" +OpName %PS_INPUT "PS_INPUT" +OpMemberName %PS_INPUT 0 "vTextureCoords" +OpName %PS_OUTPUT "PS_OUTPUT" +OpMemberName %PS_OUTPUT 0 "vColor" +OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;" +OpName %i "i" +OpName %ps_output "ps_output" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_0 "i" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpName %param "param" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 1 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_77 Block +OpMemberDecorate %_struct_77 0 Offset 0 +OpMemberDecorate %_struct_77 1 Offset 4 +OpDecorate %79 DescriptorSet 7 +OpDecorate %79 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%18 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%PS_INPUT = OpTypeStruct %v2float +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +%v4float = OpTypeVector %float 4 +%PS_OUTPUT = OpTypeStruct %v4float +%23 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%27 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_27_uint_128 = OpTypeArray %27 %uint_128 +%_ptr_UniformConstant__arr_27_uint_128 = OpTypePointer UniformConstant %_arr_27_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_27_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27 +%35 = OpTypeSampler +%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35 +%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant +%37 = OpTypeSampledImage %27 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%70 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_77 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_77 = OpTypePointer StorageBuffer %_struct_77 +%79 = OpVariable %_ptr_StorageBuffer__struct_77 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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_93 = OpConstant %uint 93 +%125 = OpConstantNull %v4float +)"; + + const std::string func1_before = + R"(%MainPs = OpFunction %void None %4 +%6 = OpLabel +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %1 21 0 +%54 = OpLoad %v2float %i_vTextureCoords +%55 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpStore %55 %54 +%59 = OpLoad %PS_INPUT %i_0 +OpStore %param %59 +%60 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +%61 = OpCompositeExtract %v4float %60 0 +OpStore %_entryPointOutput_vColor %61 +OpReturn +OpFunctionEnd +)"; + + const std::string func1_after = + R"(%MainPs = OpFunction %void None %18 +%42 = OpLabel +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %5 21 0 +%43 = OpLoad %v2float %i_vTextureCoords +%44 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpStore %44 %43 +%45 = OpLoad %PS_INPUT %i_0 +OpStore %param %45 +%46 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +%47 = OpCompositeExtract %v4float %46 0 +OpStore %_entryPointOutput_vColor %47 +OpReturn +OpFunctionEnd +)"; + + const std::string func2_before = + R"(%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %13 +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +%16 = OpLabel +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %1 24 0 +%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%32 = OpLoad %uint %31 +%34 = OpAccessChain %_ptr_UniformConstant_21 %g_tColor %32 +%35 = OpLoad %21 %34 +%39 = OpLoad %36 %g_sAniso +%41 = OpSampledImage %40 %35 %39 +%43 = OpAccessChain %_ptr_Function_v2float %i %int_0 +%44 = OpLoad %v2float %43 +%45 = OpImageSampleImplicitLod %v4float %41 %44 +%47 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpStore %47 %45 +OpLine %1 25 0 +%48 = OpLoad %PS_OUTPUT %ps_output +OpReturnValue %48 +OpFunctionEnd +)"; + + const std::string func2_after = + R"(%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %23 +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +%48 = OpLabel +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %5 24 0 +%49 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%50 = OpLoad %uint %49 +%51 = OpAccessChain %_ptr_UniformConstant_27 %g_tColor %50 +%52 = OpLoad %27 %51 +%53 = OpLoad %35 %g_sAniso +%54 = OpSampledImage %37 %52 %53 +%55 = OpAccessChain %_ptr_Function_v2float %i %int_0 +%56 = OpLoad %v2float %55 +%62 = OpULessThan %bool %50 %uint_128 +OpSelectionMerge %63 None +OpBranchConditional %62 %64 %65 +%64 = OpLabel +%66 = OpLoad %27 %51 +%67 = OpSampledImage %37 %66 %53 +%68 = OpImageSampleImplicitLod %v4float %67 %56 +OpBranch %63 +%65 = OpLabel +%124 = OpFunctionCall %void %69 %uint_93 %uint_0 %50 %uint_128 +OpBranch %63 +%63 = OpLabel +%126 = OpPhi %v4float %68 %64 %125 %65 +%58 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpStore %58 %126 +OpLine %5 25 0 +%59 = OpLoad %PS_OUTPUT %ps_output +OpReturnValue %59 +OpFunctionEnd +)"; + + const std::string output_func = + R"(%69 = OpFunction %void None %70 +%71 = OpFunctionParameter %uint +%72 = OpFunctionParameter %uint +%73 = OpFunctionParameter %uint +%74 = OpFunctionParameter %uint +%75 = OpLabel +%81 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_0 +%84 = OpAtomicIAdd %uint %81 %uint_4 %uint_0 %uint_10 +%85 = OpIAdd %uint %84 %uint_10 +%86 = OpArrayLength %uint %79 1 +%87 = OpULessThanEqual %bool %85 %86 +OpSelectionMerge %88 None +OpBranchConditional %87 %89 %88 +%89 = OpLabel +%90 = OpIAdd %uint %84 %uint_0 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %90 +OpStore %92 %uint_10 +%94 = OpIAdd %uint %84 %uint_1 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %94 +OpStore %95 %uint_23 +%97 = OpIAdd %uint %84 %uint_2 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %97 +OpStore %98 %71 +%100 = OpIAdd %uint %84 %uint_3 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %100 +OpStore %101 %uint_4 +%104 = OpLoad %v4float %gl_FragCoord +%106 = OpBitcast %v4uint %104 +%107 = OpCompositeExtract %uint %106 0 +%108 = OpIAdd %uint %84 %uint_4 +%109 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %108 +OpStore %109 %107 +%110 = OpCompositeExtract %uint %106 1 +%112 = OpIAdd %uint %84 %uint_5 +%113 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %112 +OpStore %113 %110 +%115 = OpIAdd %uint %84 %uint_7 +%116 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %115 +OpStore %116 %72 +%118 = OpIAdd %uint %84 %uint_8 +%119 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %118 +OpStore %119 %73 +%121 = OpIAdd %uint %84 %uint_9 +%122 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %121 +OpStore %122 %74 +OpBranch %88 +%88 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func1_before + func2_before, + defs_after + func1_after + func2_after + output_func, true, true, 7u, 23u, + true, true, 2u); +} + +TEST_F(InstBindlessTest, RuntimeArrayV2) { + // This test verifies that the pass will correctly instrument shader + // with runtime descriptor array. This test was created by editing the + // SPIR-V from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 1 +OpDecorate %g_tColor Binding 2 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 1 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_rarr_20 = OpTypeRuntimeArray %20 +%_ptr_UniformConstant__arr_20 = OpTypePointer UniformConstant %_rarr_20 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_20 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 +%35 = OpTypeSampler +%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35 +%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant +%39 = OpTypeSampledImage %20 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 1 +OpDecorate %g_tColor Binding 2 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 1 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_46 Block +OpMemberDecorate %_struct_46 0 Offset 0 +OpDecorate %48 DescriptorSet 7 +OpDecorate %48 Binding 1 +OpDecorate %_struct_71 Block +OpMemberDecorate %_struct_71 0 Offset 0 +OpMemberDecorate %_struct_71 1 Offset 4 +OpDecorate %73 DescriptorSet 7 +OpDecorate %73 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%16 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_runtimearr_16 = OpTypeRuntimeArray %16 +%_ptr_UniformConstant__runtimearr_16 = OpTypePointer UniformConstant %_runtimearr_16 +%g_tColor = OpVariable %_ptr_UniformConstant__runtimearr_16 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 +%24 = OpTypeSampler +%_ptr_UniformConstant_24 = OpTypePointer UniformConstant %24 +%g_sAniso = OpVariable %_ptr_UniformConstant_24 UniformConstant +%26 = OpTypeSampledImage %16 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%uint_2 = OpConstant %uint 2 +%41 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_46 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_46 = OpTypePointer StorageBuffer %_struct_46 +%48 = OpVariable %_ptr_StorageBuffer__struct_46 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%65 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_71 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_71 = OpTypePointer StorageBuffer %_struct_71 +%73 = OpVariable %_ptr_StorageBuffer__struct_71 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_59 = OpConstant %uint 59 +%116 = OpConstantNull %v4float +%119 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2float %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64 +%66 = OpLoad %20 %65 +%67 = OpLoad %35 %g_sAniso +%68 = OpSampledImage %39 %66 %67 +%71 = OpImageSampleImplicitLod %v4float %68 %53 +OpStore %_entryPointOutput_vColor %71 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %10 +%29 = OpLabel +%30 = OpLoad %v2float %i_vTextureCoords +%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%32 = OpLoad %uint %31 +%33 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %32 +%34 = OpLoad %16 %33 +%35 = OpLoad %24 %g_sAniso +%36 = OpSampledImage %26 %34 %35 +%55 = OpFunctionCall %uint %40 %uint_2 %uint_2 +%57 = OpULessThan %bool %32 %55 +OpSelectionMerge %58 None +OpBranchConditional %57 %59 %60 +%59 = OpLabel +%61 = OpLoad %16 %33 +%62 = OpSampledImage %26 %61 %35 +%136 = OpFunctionCall %uint %118 %uint_0 %uint_1 %uint_2 %32 +%137 = OpINotEqual %bool %136 %uint_0 +OpSelectionMerge %138 None +OpBranchConditional %137 %139 %140 +%139 = OpLabel +%141 = OpLoad %16 %33 +%142 = OpSampledImage %26 %141 %35 +%143 = OpImageSampleImplicitLod %v4float %142 %30 +OpBranch %138 +%140 = OpLabel +%144 = OpFunctionCall %void %64 %uint_59 %uint_1 %32 %uint_0 +OpBranch %138 +%138 = OpLabel +%145 = OpPhi %v4float %143 %139 %116 %140 +OpBranch %58 +%60 = OpLabel +%115 = OpFunctionCall %void %64 %uint_59 %uint_0 %32 %55 +OpBranch %58 +%58 = OpLabel +%117 = OpPhi %v4float %145 %138 %116 %60 +OpStore %_entryPointOutput_vColor %117 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%40 = OpFunction %uint None %41 +%42 = OpFunctionParameter %uint +%43 = OpFunctionParameter %uint +%44 = OpLabel +%50 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %42 +%51 = OpLoad %uint %50 +%52 = OpIAdd %uint %51 %43 +%53 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %52 +%54 = OpLoad %uint %53 +OpReturnValue %54 +OpFunctionEnd +%64 = OpFunction %void None %65 +%66 = OpFunctionParameter %uint +%67 = OpFunctionParameter %uint +%68 = OpFunctionParameter %uint +%69 = OpFunctionParameter %uint +%70 = OpLabel +%74 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_0 +%77 = OpAtomicIAdd %uint %74 %uint_4 %uint_0 %uint_10 +%78 = OpIAdd %uint %77 %uint_10 +%79 = OpArrayLength %uint %73 1 +%80 = OpULessThanEqual %bool %78 %79 +OpSelectionMerge %81 None +OpBranchConditional %80 %82 %81 +%82 = OpLabel +%83 = OpIAdd %uint %77 %uint_0 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %83 +OpStore %84 %uint_10 +%86 = OpIAdd %uint %77 %uint_1 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %86 +OpStore %87 %uint_23 +%88 = OpIAdd %uint %77 %uint_2 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %88 +OpStore %89 %66 +%91 = OpIAdd %uint %77 %uint_3 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %91 +OpStore %92 %uint_4 +%95 = OpLoad %v4float %gl_FragCoord +%97 = OpBitcast %v4uint %95 +%98 = OpCompositeExtract %uint %97 0 +%99 = OpIAdd %uint %77 %uint_4 +%100 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %99 +OpStore %100 %98 +%101 = OpCompositeExtract %uint %97 1 +%103 = OpIAdd %uint %77 %uint_5 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %103 +OpStore %104 %101 +%106 = OpIAdd %uint %77 %uint_7 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %106 +OpStore %107 %67 +%109 = OpIAdd %uint %77 %uint_8 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %109 +OpStore %110 %68 +%112 = OpIAdd %uint %77 %uint_9 +%113 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %112 +OpStore %113 %69 +OpBranch %81 +%81 = OpLabel +OpReturn +OpFunctionEnd +%118 = OpFunction %uint None %119 +%120 = OpFunctionParameter %uint +%121 = OpFunctionParameter %uint +%122 = OpFunctionParameter %uint +%123 = OpFunctionParameter %uint +%124 = OpLabel +%125 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %120 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %121 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %122 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %130 +%132 = OpLoad %uint %131 +%133 = OpIAdd %uint %132 %123 +%134 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %133 +%135 = OpLoad %uint %134 +OpReturnValue %135 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptorV2) { + // This test verifies that the pass will correctly instrument vanilla + // texture sample on a scalar descriptor with an initialization check if the + // SPV_EXT_descriptor_checking extension is enabled. This is the same shader + // as NoInstrumentNonBindless, but with the extension hacked on in the SPIR-V. + + const std::string defs_before = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%12 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 +%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant +%14 = OpTypeSampler +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant +%16 = OpTypeSampledImage %12 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_35 Block +OpMemberDecorate %_struct_35 0 Offset 0 +OpDecorate %37 DescriptorSet 7 +OpDecorate %37 Binding 1 +OpDecorate %_struct_67 Block +OpMemberDecorate %_struct_67 0 Offset 0 +OpMemberDecorate %_struct_67 1 Offset 4 +OpDecorate %69 DescriptorSet 7 +OpDecorate %69 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%12 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 +%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant +%14 = OpTypeSampler +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant +%16 = OpTypeSampledImage %12 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%28 = OpTypeFunction %uint %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_35 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_35 = OpTypePointer StorageBuffer %_struct_35 +%37 = OpVariable %_ptr_StorageBuffer__struct_35 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%uint_1 = OpConstant %uint 1 +%61 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_67 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_67 = OpTypePointer StorageBuffer %_struct_67 +%69 = OpVariable %_ptr_StorageBuffer__struct_67 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_40 = OpConstant %uint 40 +%113 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %8 +%19 = OpLabel +%20 = OpLoad %v2float %i_vTextureCoords +%21 = OpLoad %12 %g_tColor +%22 = OpLoad %14 %g_sAniso +%23 = OpSampledImage %16 %21 %22 +%24 = OpImageSampleImplicitLod %v4float %23 %20 +OpStore %_entryPointOutput_vColor %24 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %8 +%19 = OpLabel +%20 = OpLoad %v2float %i_vTextureCoords +%21 = OpLoad %12 %g_tColor +%22 = OpLoad %14 %g_sAniso +%23 = OpSampledImage %16 %21 %22 +%50 = OpFunctionCall %uint %27 %uint_0 %uint_0 %uint_0 %uint_0 +%52 = OpINotEqual %bool %50 %uint_0 +OpSelectionMerge %54 None +OpBranchConditional %52 %55 %56 +%55 = OpLabel +%57 = OpLoad %12 %g_tColor +%58 = OpSampledImage %16 %57 %22 +%59 = OpImageSampleImplicitLod %v4float %58 %20 +OpBranch %54 +%56 = OpLabel +%112 = OpFunctionCall %void %60 %uint_40 %uint_1 %uint_0 %uint_0 +OpBranch %54 +%54 = OpLabel +%114 = OpPhi %v4float %59 %55 %113 %56 +OpStore %_entryPointOutput_vColor %114 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%27 = OpFunction %uint None %28 +%29 = OpFunctionParameter %uint +%30 = OpFunctionParameter %uint +%31 = OpFunctionParameter %uint +%32 = OpFunctionParameter %uint +%33 = OpLabel +%39 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %29 +%40 = OpLoad %uint %39 +%41 = OpIAdd %uint %40 %30 +%42 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %41 +%43 = OpLoad %uint %42 +%44 = OpIAdd %uint %43 %31 +%45 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %44 +%46 = OpLoad %uint %45 +%47 = OpIAdd %uint %46 %32 +%48 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %47 +%49 = OpLoad %uint %48 +OpReturnValue %49 +OpFunctionEnd +%60 = OpFunction %void None %61 +%62 = OpFunctionParameter %uint +%63 = OpFunctionParameter %uint +%64 = OpFunctionParameter %uint +%65 = OpFunctionParameter %uint +%66 = OpLabel +%70 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_0 +%73 = OpAtomicIAdd %uint %70 %uint_4 %uint_0 %uint_10 +%74 = OpIAdd %uint %73 %uint_10 +%75 = OpArrayLength %uint %69 1 +%76 = OpULessThanEqual %bool %74 %75 +OpSelectionMerge %77 None +OpBranchConditional %76 %78 %77 +%78 = OpLabel +%79 = OpIAdd %uint %73 %uint_0 +%80 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %79 +OpStore %80 %uint_10 +%82 = OpIAdd %uint %73 %uint_1 +%83 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %82 +OpStore %83 %uint_23 +%85 = OpIAdd %uint %73 %uint_2 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %85 +OpStore %86 %62 +%88 = OpIAdd %uint %73 %uint_3 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %88 +OpStore %89 %uint_4 +%92 = OpLoad %v4float %gl_FragCoord +%94 = OpBitcast %v4uint %92 +%95 = OpCompositeExtract %uint %94 0 +%96 = OpIAdd %uint %73 %uint_4 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %96 +OpStore %97 %95 +%98 = OpCompositeExtract %uint %94 1 +%100 = OpIAdd %uint %73 %uint_5 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %100 +OpStore %101 %98 +%103 = OpIAdd %uint %73 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %103 +OpStore %104 %63 +%106 = OpIAdd %uint %73 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %106 +OpStore %107 %64 +%109 = OpIAdd %uint %73 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %109 +OpStore %110 %65 +OpBranch %77 +%77 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, SPV14AddToEntryPointV2) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] +; CHECK: OpDecorate [[v1]] DescriptorSet 7 +; CHECK: OpDecorate [[v2]] DescriptorSet 7 +; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer +; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var +OpExecutionMode %foo OriginUpperLeft +OpDecorate %image_var DescriptorSet 0 +OpDecorate %image_var Binding 0 +OpDecorate %sampler_var DescriptorSet 0 +OpDecorate %sampler_var Binding 1 +OpDecorate %gid DescriptorSet 0 +OpDecorate %gid Binding 2 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%v3int = OpTypeVector %int 3 +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%v4float = OpTypeVector %float 4 +%struct = OpTypeStruct %v3int +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int +%gid = OpVariable %ptr_ssbo_struct StorageBuffer +%image = OpTypeImage %float 3D 0 0 0 1 Unknown +%ptr_uc_image = OpTypePointer UniformConstant %image +%sampler = OpTypeSampler +%ptr_uc_sampler = OpTypePointer UniformConstant %sampler +%image_var = OpVariable %ptr_uc_image UniformConstant +%sampler_var = OpVariable %ptr_uc_sampler UniformConstant +%sampled = OpTypeSampledImage %image +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +%ld_image = OpLoad %image %image_var +%ld_sampler = OpLoad %sampler %sampler_var +%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0 +%ld_gid = OpLoad %v3int %gep +%convert = OpConvertUToF %v3float %ld_gid +%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler +%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); + SinglePassRunAndMatch(text, true, 7u, 23u, true, true, + 2u); +} + +TEST_F(InstBindlessTest, SPV14AddToEntryPointsV2) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] +; CHECK: OpEntryPoint Fragment {{%\w+}} "bar" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] +; CHECK: OpDecorate [[v1]] DescriptorSet 7 +; CHECK: OpDecorate [[v2]] DescriptorSet 7 +; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer +; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var +OpEntryPoint Fragment %foo "bar" %gid %image_var %sampler_var +OpExecutionMode %foo OriginUpperLeft +OpDecorate %image_var DescriptorSet 0 +OpDecorate %image_var Binding 0 +OpDecorate %sampler_var DescriptorSet 0 +OpDecorate %sampler_var Binding 1 +OpDecorate %gid DescriptorSet 0 +OpDecorate %gid Binding 2 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%v3int = OpTypeVector %int 3 +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%v4float = OpTypeVector %float 4 +%struct = OpTypeStruct %v3int +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int +%gid = OpVariable %ptr_ssbo_struct StorageBuffer +%image = OpTypeImage %float 3D 0 0 0 1 Unknown +%ptr_uc_image = OpTypePointer UniformConstant %image +%sampler = OpTypeSampler +%ptr_uc_sampler = OpTypePointer UniformConstant %sampler +%image_var = OpVariable %ptr_uc_image UniformConstant +%sampler_var = OpVariable %ptr_uc_sampler UniformConstant +%sampled = OpTypeSampledImage %image +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +%ld_image = OpLoad %image %image_var +%ld_sampler = OpLoad %sampler %sampler_var +%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0 +%ld_gid = OpLoad %v3int %gep +%convert = OpConvertUToF %v3float %ld_gid +%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler +%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); + SinglePassRunAndMatch(text, true, 7u, 23u, true, true, + 2u); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArrayV2) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) uniform uname { float a; } uniformBuffer[]; + // + // void main() + // { + // b = uniformBuffer[nu_ii].a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %16 NonUniformEXT +OpDecorate %20 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_runtimearr_uname = OpTypeRuntimeArray %uname +%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname +%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %102 NonUniformEXT +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 %_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 +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_runtimearr_uname = OpTypeRuntimeArray %uname +%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname +%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_10 +%62 = OpIAdd %uint %61 %uint_10 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_10 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_7 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_8 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_9 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecatedV2) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) buffer bname { float b; } storageBuffer[]; + // + // void main() + // { + // b = storageBuffer[nu_ii].b; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %16 NonUniformEXT +OpDecorate %20 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %102 NonUniformEXT +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 %_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 +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_10 +%62 = OpIAdd %uint %61 %uint_10 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_10 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_7 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_8 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_9 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayV2) { + // Same as Deprecated but declaring as StorageBuffer Block + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %16 NonUniformEXT +OpDecorate %20 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %102 NonUniformEXT +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 %_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 +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_10 +%62 = OpIAdd %uint %61 %uint_10 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_10 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_7 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_8 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_9 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstInitLoadUBOScalarV2) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) out float b; + // layout(binding=3) uniform uname { float a; } uniformBuffer; + // + // void main() + // { + // b = uniformBuffer.a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_ptr_Uniform_uname = OpTypePointer Uniform %uname +%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_28 Block +OpMemberDecorate %_struct_28 0 Offset 0 +OpDecorate %30 DescriptorSet 7 +OpDecorate %30 Binding 1 +OpDecorate %_struct_58 Block +OpMemberDecorate %_struct_58 0 Offset 0 +OpMemberDecorate %_struct_58 1 Offset 4 +OpDecorate %60 DescriptorSet 7 +OpDecorate %60 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%7 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_ptr_Uniform_uname = OpTypePointer Uniform %uname +%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%21 = OpTypeFunction %uint %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_28 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_28 = OpTypePointer StorageBuffer %_struct_28 +%30 = OpVariable %_ptr_StorageBuffer__struct_28 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%uint_1 = OpConstant %uint 1 +%52 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_58 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_58 = OpTypePointer StorageBuffer %_struct_58 +%60 = OpVariable %_ptr_StorageBuffer__struct_58 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_32 = OpConstant %uint 32 +%104 = OpConstantNull %float +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0 +%16 = OpLoad %float %15 +OpStore %b %16 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %7 +%14 = OpLabel +%15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0 +%43 = OpFunctionCall %uint %20 %uint_0 %uint_0 %uint_3 %uint_0 +%45 = OpINotEqual %bool %43 %uint_0 +OpSelectionMerge %47 None +OpBranchConditional %45 %48 %49 +%48 = OpLabel +%50 = OpLoad %float %15 +OpBranch %47 +%49 = OpLabel +%103 = OpFunctionCall %void %51 %uint_32 %uint_1 %uint_0 %uint_0 +OpBranch %47 +%47 = OpLabel +%105 = OpPhi %float %50 %48 %104 %49 +OpStore %b %105 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%20 = OpFunction %uint None %21 +%22 = OpFunctionParameter %uint +%23 = OpFunctionParameter %uint +%24 = OpFunctionParameter %uint +%25 = OpFunctionParameter %uint +%26 = OpLabel +%32 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %22 +%33 = OpLoad %uint %32 +%34 = OpIAdd %uint %33 %23 +%35 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %34 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %24 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %37 +%39 = OpLoad %uint %38 +%40 = OpIAdd %uint %39 %25 +%41 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %40 +%42 = OpLoad %uint %41 +OpReturnValue %42 +OpFunctionEnd +%51 = OpFunction %void None %52 +%53 = OpFunctionParameter %uint +%54 = OpFunctionParameter %uint +%55 = OpFunctionParameter %uint +%56 = OpFunctionParameter %uint +%57 = OpLabel +%61 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_0 +%64 = OpAtomicIAdd %uint %61 %uint_4 %uint_0 %uint_10 +%65 = OpIAdd %uint %64 %uint_10 +%66 = OpArrayLength %uint %60 1 +%67 = OpULessThanEqual %bool %65 %66 +OpSelectionMerge %68 None +OpBranchConditional %67 %69 %68 +%69 = OpLabel +%70 = OpIAdd %uint %64 %uint_0 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %70 +OpStore %71 %uint_10 +%73 = OpIAdd %uint %64 %uint_1 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %73 +OpStore %74 %uint_23 +%76 = OpIAdd %uint %64 %uint_2 +%77 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %76 +OpStore %77 %53 +%78 = OpIAdd %uint %64 %uint_3 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %78 +OpStore %79 %uint_4 +%83 = OpLoad %v4float %gl_FragCoord +%85 = OpBitcast %v4uint %83 +%86 = OpCompositeExtract %uint %85 0 +%87 = OpIAdd %uint %64 %uint_4 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %87 +OpStore %88 %86 +%89 = OpCompositeExtract %uint %85 1 +%91 = OpIAdd %uint %64 %uint_5 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %91 +OpStore %92 %89 +%94 = OpIAdd %uint %64 %uint_7 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %94 +OpStore %95 %54 +%97 = OpIAdd %uint %64 %uint_8 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %97 +OpStore %98 %55 +%100 = OpIAdd %uint %64 %uint_9 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %100 +OpStore %101 %56 +OpBranch %68 +%68 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArrayV2) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=1) in float b; + // + // layout(binding=4) buffer bname { float b; } storageBuffer[]; + // + // void main() + // { + // storageBuffer[nu_ii].b = b; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %nu_ii %b +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %bname "bname" +OpMemberName %bname 0 "b" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpName %b "b" +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 4 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %14 NonUniformEXT +OpDecorate %b Location 1 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Input_float = OpTypePointer Input %float +%b = OpVariable %_ptr_Input_float Input +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %bname "bname" +OpMemberName %bname 0 "b" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpName %b "b" +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 4 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %b Location 1 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %_struct_54 Block +OpMemberDecorate %_struct_54 0 Offset 0 +OpMemberDecorate %_struct_54 1 Offset 4 +OpDecorate %56 DescriptorSet 7 +OpDecorate %56 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Input_float = OpTypePointer Input %float +%b = OpVariable %_ptr_Input_float Input +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_4 = OpConstant %uint 4 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%48 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_54 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_54 = OpTypePointer StorageBuffer %_struct_54 +%56 = OpVariable %_ptr_StorageBuffer__struct_54 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%v4float = OpTypeVector %float 4 +%_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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%102 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%14 = OpLoad %int %nu_ii +%18 = OpLoad %float %b +%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0 +OpStore %20 %18 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %9 +%18 = OpLabel +%7 = OpLoad %int %nu_ii +%19 = OpLoad %float %b +%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_4 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%100 = OpBitcast %uint %7 +%119 = OpFunctionCall %uint %101 %uint_0 %uint_0 %uint_4 %100 +%120 = OpINotEqual %bool %119 %uint_0 +OpSelectionMerge %121 None +OpBranchConditional %120 %122 %123 +%122 = OpLabel +OpStore %20 %19 +OpBranch %121 +%123 = OpLabel +%124 = OpBitcast %uint %7 +%125 = OpFunctionCall %void %47 %uint_45 %uint_1 %124 %uint_0 +OpBranch %121 +%121 = OpLabel +OpBranch %43 +%45 = OpLabel +%46 = OpBitcast %uint %7 +%99 = OpFunctionCall %void %47 %uint_45 %uint_0 %46 %40 +OpBranch %43 +%43 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%47 = OpFunction %void None %48 +%49 = OpFunctionParameter %uint +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpLabel +%57 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_0 +%59 = OpAtomicIAdd %uint %57 %uint_4 %uint_0 %uint_10 +%60 = OpIAdd %uint %59 %uint_10 +%61 = OpArrayLength %uint %56 1 +%62 = OpULessThanEqual %bool %60 %61 +OpSelectionMerge %63 None +OpBranchConditional %62 %64 %63 +%64 = OpLabel +%65 = OpIAdd %uint %59 %uint_0 +%66 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %65 +OpStore %66 %uint_10 +%68 = OpIAdd %uint %59 %uint_1 +%69 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %68 +OpStore %69 %uint_23 +%71 = OpIAdd %uint %59 %uint_2 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %71 +OpStore %72 %49 +%74 = OpIAdd %uint %59 %uint_3 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %74 +OpStore %75 %uint_4 +%79 = OpLoad %v4float %gl_FragCoord +%81 = OpBitcast %v4uint %79 +%82 = OpCompositeExtract %uint %81 0 +%83 = OpIAdd %uint %59 %uint_4 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %83 +OpStore %84 %82 +%85 = OpCompositeExtract %uint %81 1 +%87 = OpIAdd %uint %59 %uint_5 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %87 +OpStore %88 %85 +%90 = OpIAdd %uint %59 %uint_7 +%91 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %90 +OpStore %91 %50 +%93 = OpIAdd %uint %59 %uint_8 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %93 +OpStore %94 %51 +%96 = OpIAdd %uint %59 %uint_9 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %96 +OpStore %97 %52 +OpBranch %63 +%63 = OpLabel +OpReturn +OpFunctionEnd +%101 = OpFunction %uint None %102 +%103 = OpFunctionParameter %uint +%104 = OpFunctionParameter %uint +%105 = OpFunctionParameter %uint +%106 = OpFunctionParameter %uint +%107 = OpLabel +%108 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %103 +%109 = OpLoad %uint %108 +%110 = OpIAdd %uint %109 %104 +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %110 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %105 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %106 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +OpReturnValue %118 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArrayV2) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) uniform uname { float a; } uniformBuffer[128]; + // + // void main() + // { + // b = uniformBuffer[nu_ii].a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %18 NonUniformEXT +OpDecorate %22 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_uname_uint_128 = OpTypeArray %uname %uint_128 +%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128 +%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +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 %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpMemberDecorate %_struct_39 1 Offset 4 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %_struct_98 Block +OpMemberDecorate %_struct_98 0 Offset 0 +OpDecorate %100 DescriptorSet 7 +OpDecorate %100 Binding 1 +OpDecorate %117 NonUniformEXT +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_uname_uint_128 = OpTypeArray %uname %uint_128 +%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128 +%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%32 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 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 +%v4float = OpTypeVector %float 4 +%_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_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_46 = OpConstant %uint 46 +%88 = OpConstantNull %float +%92 = OpTypeFunction %uint %uint %uint %uint %uint +%_struct_98 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_98 = OpTypePointer StorageBuffer %_struct_98 +%100 = OpVariable %_ptr_StorageBuffer__struct_98 StorageBuffer +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%18 = OpLoad %int %nu_ii +%21 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %18 %int_0 +%22 = OpLoad %float %21 +OpStore %b %22 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%21 = OpLabel +%7 = OpLoad %int %nu_ii +%22 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %7 %int_0 +%25 = OpULessThan %bool %7 %uint_128 +OpSelectionMerge %26 None +OpBranchConditional %25 %27 %28 +%27 = OpLabel +%90 = OpBitcast %uint %7 +%112 = OpFunctionCall %uint %91 %uint_0 %uint_0 %uint_3 %90 +%113 = OpINotEqual %bool %112 %uint_0 +OpSelectionMerge %114 None +OpBranchConditional %113 %115 %116 +%115 = OpLabel +%117 = OpLoad %float %22 +OpBranch %114 +%116 = OpLabel +%118 = OpBitcast %uint %7 +%119 = OpFunctionCall %void %31 %uint_46 %uint_1 %118 %uint_0 +OpBranch %114 +%114 = OpLabel +%120 = OpPhi %float %117 %115 %88 %116 +OpBranch %26 +%28 = OpLabel +%30 = OpBitcast %uint %7 +%87 = OpFunctionCall %void %31 %uint_46 %uint_0 %30 %uint_128 +OpBranch %26 +%26 = OpLabel +%89 = OpPhi %float %120 %114 %88 %28 +OpStore %b %89 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%31 = OpFunction %void None %32 +%33 = OpFunctionParameter %uint +%34 = OpFunctionParameter %uint +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 +%46 = OpAtomicIAdd %uint %43 %uint_4 %uint_0 %uint_10 +%47 = OpIAdd %uint %46 %uint_10 +%48 = OpArrayLength %uint %41 1 +%49 = OpULessThanEqual %bool %47 %48 +OpSelectionMerge %50 None +OpBranchConditional %49 %51 %50 +%51 = OpLabel +%52 = OpIAdd %uint %46 %uint_0 +%54 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %52 +OpStore %54 %uint_10 +%56 = OpIAdd %uint %46 %uint_1 +%57 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %56 +OpStore %57 %uint_23 +%59 = OpIAdd %uint %46 %uint_2 +%60 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %59 +OpStore %60 %33 +%62 = OpIAdd %uint %46 %uint_3 +%63 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %62 +OpStore %63 %uint_4 +%67 = OpLoad %v4float %gl_FragCoord +%69 = OpBitcast %v4uint %67 +%70 = OpCompositeExtract %uint %69 0 +%71 = OpIAdd %uint %46 %uint_4 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %71 +OpStore %72 %70 +%73 = OpCompositeExtract %uint %69 1 +%75 = OpIAdd %uint %46 %uint_5 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %75 +OpStore %76 %73 +%78 = OpIAdd %uint %46 %uint_7 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %78 +OpStore %79 %34 +%81 = OpIAdd %uint %46 %uint_8 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %81 +OpStore %82 %35 +%84 = OpIAdd %uint %46 %uint_9 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %84 +OpStore %85 %36 +OpBranch %50 +%50 = OpLabel +OpReturn +OpFunctionEnd +%91 = OpFunction %uint None %92 +%93 = OpFunctionParameter %uint +%94 = OpFunctionParameter %uint +%95 = OpFunctionParameter %uint +%96 = OpFunctionParameter %uint +%97 = OpLabel +%101 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %93 +%102 = OpLoad %uint %101 +%103 = OpIAdd %uint %102 %94 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %103 +%105 = OpLoad %uint %104 +%106 = OpIAdd %uint %105 %95 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %106 +%108 = OpLoad %uint %107 +%109 = OpIAdd %uint %108 %96 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %109 +%111 = OpLoad %uint %110 +OpReturnValue %111 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + 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/3rdparty/spirv-tools/test/opt/optimizer_test.cpp b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp index f13164b37..b4278046b 100644 --- a/3rdparty/spirv-tools/test/opt/optimizer_test.cpp +++ b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp @@ -239,7 +239,8 @@ TEST(Optimizer, VulkanToWebGPUSetsCorrectPasses) { "strip-atomic-counter-memory", "generate-webgpu-initializers", "legalize-vector-shuffle", - "split-invalid-unreachable"}; + "split-invalid-unreachable", + "compact-ids"}; std::sort(registered_passes.begin(), registered_passes.end()); std::sort(expected_passes.begin(), expected_passes.end()); @@ -317,14 +318,14 @@ INSTANTIATE_TEST_SUITE_P( "OpEntryPoint Fragment %1 \"main\" %2 %3 %4\n" "OpExecutionMode %1 OriginUpperLeft\n" "%void = OpTypeVoid\n" - "%7 = OpTypeFunction %void\n" + "%6 = OpTypeFunction %void\n" "%float = OpTypeFloat 32\n" "%_ptr_Input_float = OpTypePointer Input %float\n" "%2 = OpVariable %_ptr_Input_float Input\n" "%3 = OpVariable %_ptr_Input_float Input\n" "%4 = OpVariable %_ptr_Input_float Input\n" - "%1 = OpFunction %void None %7\n" - "%10 = OpLabel\n" + "%1 = OpFunction %void None %6\n" + "%9 = OpLabel\n" "OpReturn\n" "OpFunctionEnd\n", // pass @@ -351,9 +352,9 @@ INSTANTIATE_TEST_SUITE_P( "OpMemoryModel Logical VulkanKHR\n" "OpEntryPoint Vertex %1 \"shader\"\n" "%void = OpTypeVoid\n" - "%5 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %5\n" - "%6 = OpLabel\n" + "%3 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %3\n" + "%4 = OpLabel\n" "OpReturn\n" "OpFunctionEnd\n", // pass @@ -388,9 +389,9 @@ INSTANTIATE_TEST_SUITE_P( "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n" "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n" "%void = OpTypeVoid\n" - "%10 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %10\n" - "%11 = OpLabel\n" + "%6 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %6\n" + "%7 = OpLabel\n" "OpReturn\n" "OpFunctionEnd\n", "eliminate-dead-const"}, @@ -434,9 +435,9 @@ INSTANTIATE_TEST_SUITE_P( "%uint_1 = OpConstant %uint 1\n" "%uint_0_0 = OpConstant %uint 0\n" "%void = OpTypeVoid\n" - "%10 = OpTypeFunction %void\n" + "%9 = OpTypeFunction %void\n" "%uint_264 = OpConstant %uint 264\n" - "%1 = OpFunction %void None %10\n" + "%1 = OpFunction %void None %9\n" "%11 = OpLabel\n" "OpAtomicStore %4 %uint_0_0 %uint_264 %uint_1\n" "%12 = OpAtomicIIncrement %uint %4 %uint_0_0 %uint_264\n" @@ -472,14 +473,14 @@ INSTANTIATE_TEST_SUITE_P( "OpEntryPoint Vertex %1 \"shader\"\n" "%uint = OpTypeInt 32 0\n" "%_ptr_Private_uint = OpTypePointer Private %uint\n" - "%9 = OpConstantNull %uint\n" - "%4 = OpVariable %_ptr_Private_uint Private %9\n" + "%4 = OpConstantNull %uint\n" + "%5 = OpVariable %_ptr_Private_uint Private %4\n" "%uint_0 = OpConstant %uint 0\n" "%void = OpTypeVoid\n" - "%7 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %7\n" - "%8 = OpLabel\n" - "OpStore %4 %uint_0\n" + "%8 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %8\n" + "%9 = OpLabel\n" + "OpStore %5 %uint_0\n" "OpReturn\n" "OpFunctionEnd\n", // pass @@ -515,13 +516,13 @@ INSTANTIATE_TEST_SUITE_P( "%_ptr_Function_v3uint = OpTypePointer Function %v3uint\n" "%void = OpTypeVoid\n" "%6 = OpTypeFunction %void\n" - "%12 = OpConstantNull %v3uint\n" + "%7 = OpConstantNull %v3uint\n" "%1 = OpFunction %void None %6\n" - "%7 = OpLabel\n" - "%8 = OpVariable %_ptr_Function_v3uint Function %12\n" - "%9 = OpLoad %v3uint %8\n" - "%10 = OpLoad %v3uint %8\n" - "%11 = OpVectorShuffle %v3uint %9 %10 2 1 0\n" + "%8 = OpLabel\n" + "%9 = OpVariable %_ptr_Function_v3uint Function %7\n" + "%10 = OpLoad %v3uint %9\n" + "%11 = OpLoad %v3uint %9\n" + "%12 = OpVectorShuffle %v3uint %10 %11 2 1 0\n" "OpReturn\n" "OpFunctionEnd\n", // pass @@ -578,21 +579,48 @@ INSTANTIATE_TEST_SUITE_P( "OpBranch %12\n" "%12 = OpLabel\n" "%13 = OpSLessThan %bool %uint_1 %uint_2\n" - "OpSelectionMerge %16 None\n" - "OpBranchConditional %13 %14 %15\n" - "%14 = OpLabel\n" - "OpReturn\n" + "OpSelectionMerge %14 None\n" + "OpBranchConditional %13 %15 %16\n" "%15 = OpLabel\n" "OpReturn\n" + "%16 = OpLabel\n" + "OpReturn\n" "%10 = OpLabel\n" "OpUnreachable\n" - "%16 = OpLabel\n" + "%14 = OpLabel\n" "OpUnreachable\n" "%11 = OpLabel\n" "OpBranch %9\n" "OpFunctionEnd\n", // pass - "split-invalid-unreachable"}})); + "split-invalid-unreachable"}, + // Compact IDs + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %1000 \"shader\"\n" + "%10 = OpTypeVoid\n" + "%100 = OpTypeFunction %10\n" + "%1000 = OpFunction %10 None %100\n" + "%10000 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%void = OpTypeVoid\n" + "%3 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %3\n" + "%4 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "compact-ids"}})); TEST(Optimizer, WebGPUToVulkanSetsCorrectPasses) { Optimizer opt(SPV_ENV_VULKAN_1_1); @@ -603,8 +631,8 @@ TEST(Optimizer, WebGPUToVulkanSetsCorrectPasses) { for (auto name = pass_names.begin(); name != pass_names.end(); ++name) registered_passes.push_back(*name); - std::vector expected_passes = { - "decompose-initialized-variables"}; + std::vector expected_passes = {"decompose-initialized-variables", + "compact-ids"}; std::sort(registered_passes.begin(), registered_passes.end()); std::sort(expected_passes.begin(), expected_passes.end()); @@ -687,7 +715,34 @@ INSTANTIATE_TEST_SUITE_P( "OpReturn\n" "OpFunctionEnd\n", // pass - "decompose-initialized-variables"}})); + "decompose-initialized-variables"}, + // Compact IDs + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %1000 \"shader\"\n" + "%10 = OpTypeVoid\n" + "%100 = OpTypeFunction %10\n" + "%1000 = OpFunction %10 None %100\n" + "%10000 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%void = OpTypeVoid\n" + "%3 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %3\n" + "%4 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "compact-ids"}})); } // namespace } // namespace opt diff --git a/3rdparty/spirv-tools/test/opt/struct_cfg_analysis_test.cpp b/3rdparty/spirv-tools/test/opt/struct_cfg_analysis_test.cpp index 3a980fe8f..7fb378432 100644 --- a/3rdparty/spirv-tools/test/opt/struct_cfg_analysis_test.cpp +++ b/3rdparty/spirv-tools/test/opt/struct_cfg_analysis_test.cpp @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/struct_cfg_analysis.h" + #include #include "gmock/gmock.h" -#include "source/opt/struct_cfg_analysis.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" @@ -59,18 +60,24 @@ OpFunctionEnd 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); // BB2 is in the construct. EXPECT_EQ(analysis.ContainingConstruct(2), 1); EXPECT_EQ(analysis.ContainingLoop(2), 0); EXPECT_EQ(analysis.MergeBlock(2), 3); EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); // The merge node is not in the 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); } TEST_F(StructCFGAnalysisTest, BBInLoop) { @@ -110,24 +117,32 @@ OpFunctionEnd 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); // BB2 is in the construct. 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); // The merge node is not in the 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); // The continue block is in the construct. 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); } TEST_F(StructCFGAnalysisTest, SelectionInLoop) { @@ -172,36 +187,48 @@ OpFunctionEnd 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); // 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); // 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); // 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); // BB5 is in the selection fist 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); // The selection merge is in the loop only. 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); } TEST_F(StructCFGAnalysisTest, LoopInSelection) { @@ -246,36 +273,48 @@ OpFunctionEnd 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); // Loop header is in the selection only. EXPECT_EQ(analysis.ContainingConstruct(2), 1); EXPECT_EQ(analysis.ContainingLoop(2), 0); EXPECT_EQ(analysis.MergeBlock(2), 3); EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); // The selection 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); // The loop merge is in the selection only. EXPECT_EQ(analysis.ContainingConstruct(4), 1); EXPECT_EQ(analysis.ContainingLoop(4), 0); EXPECT_EQ(analysis.MergeBlock(4), 3); EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); // The loop continue target is in the loop. EXPECT_EQ(analysis.ContainingConstruct(5), 2); EXPECT_EQ(analysis.ContainingLoop(5), 2); EXPECT_EQ(analysis.MergeBlock(5), 4); EXPECT_EQ(analysis.LoopMergeBlock(5), 4); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); // BB6 is in the loop. EXPECT_EQ(analysis.ContainingConstruct(6), 2); EXPECT_EQ(analysis.ContainingLoop(6), 2); EXPECT_EQ(analysis.MergeBlock(6), 4); EXPECT_EQ(analysis.LoopMergeBlock(6), 4); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); } TEST_F(StructCFGAnalysisTest, SelectionInSelection) { @@ -318,30 +357,40 @@ OpFunctionEnd 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); // The inner header is in the outer selection. EXPECT_EQ(analysis.ContainingConstruct(2), 1); EXPECT_EQ(analysis.ContainingLoop(2), 0); EXPECT_EQ(analysis.MergeBlock(2), 3); EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); // 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); // The inner merge is in the outer selection. EXPECT_EQ(analysis.ContainingConstruct(4), 1); EXPECT_EQ(analysis.ContainingLoop(4), 0); EXPECT_EQ(analysis.MergeBlock(4), 3); EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); // BB5 is in the inner selection. EXPECT_EQ(analysis.ContainingConstruct(5), 2); EXPECT_EQ(analysis.ContainingLoop(5), 0); EXPECT_EQ(analysis.MergeBlock(5), 4); EXPECT_EQ(analysis.LoopMergeBlock(5), 0); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); } TEST_F(StructCFGAnalysisTest, LoopInLoop) { @@ -388,42 +437,56 @@ OpFunctionEnd 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); // The inner loop header is in the outer 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); // 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); // The inner merge is in 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); // The inner continue target is in the inner loop. EXPECT_EQ(analysis.ContainingConstruct(5), 2); EXPECT_EQ(analysis.ContainingLoop(5), 2); EXPECT_EQ(analysis.MergeBlock(5), 4); EXPECT_EQ(analysis.LoopMergeBlock(5), 4); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); // BB6 is in the loop. EXPECT_EQ(analysis.ContainingConstruct(6), 2); EXPECT_EQ(analysis.ContainingLoop(6), 2); EXPECT_EQ(analysis.MergeBlock(6), 4); EXPECT_EQ(analysis.LoopMergeBlock(6), 4); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); // 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); } TEST_F(StructCFGAnalysisTest, KernelTest) { @@ -458,6 +521,8 @@ OpFunctionEnd EXPECT_EQ(analysis.ContainingLoop(i), 0); EXPECT_EQ(analysis.MergeBlock(i), 0); EXPECT_EQ(analysis.LoopMergeBlock(i), 0); + EXPECT_EQ(analysis.ContainingSwitch(i), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(i), 0); } } @@ -481,6 +546,297 @@ OpFunctionEnd StructuredCFGAnalysis analysis(context.get()); } +TEST_F(StructCFGAnalysisTest, BBInSwitch) { + 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 +%1 = OpLabel +OpSelectionMerge %3 None +OpSwitch %uint_undef %2 0 %3 +%2 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The header is not in the 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); + + // BB2 is in the construct. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 3); + + // The merge node is not in the 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); +} + +TEST_F(StructCFGAnalysisTest, LoopInSwitch) { + 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 +OpSelectionMerge %3 None +OpSwitch %uint_undef %2 1 %3 +%2 = OpLabel +OpLoopMerge %4 %5 None +OpBranchConditional %undef_bool %4 %6 +%5 = OpLabel +OpBranch %2 +%6 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The selection 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); + + // Loop header is in the selection only. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 3); + + // The selection 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); + + // The loop merge is in the selection only. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 3); + + // The loop continue target is in the loop. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 2); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 4); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + + // BB6 is in the loop. + EXPECT_EQ(analysis.ContainingConstruct(6), 2); + EXPECT_EQ(analysis.ContainingLoop(6), 2); + EXPECT_EQ(analysis.MergeBlock(6), 4); + EXPECT_EQ(analysis.LoopMergeBlock(6), 4); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); +} + +TEST_F(StructCFGAnalysisTest, SelectionInSwitch) { + 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 +OpSelectionMerge %3 None +OpSwitch %uint_undef %2 10 %3 +%2 = OpLabel +OpSelectionMerge %4 None +OpBranchConditional %undef_bool %4 %5 +%5 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The outer selection 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); + + // The inner header is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 3); + + // 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); + + // The inner merge is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 3); + + // BB5 is in the inner selection. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 0); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 0); + EXPECT_EQ(analysis.ContainingSwitch(5), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 3); +} + +TEST_F(StructCFGAnalysisTest, SwitchInSelection) { + 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 +OpSelectionMerge %3 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpSelectionMerge %4 None +OpSwitch %uint_undef %4 7 %5 +%5 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The outer selection 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); + + // The inner header is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + + // 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); + + // The inner merge is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + + // BB5 is in the inner selection. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 0); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 0); + EXPECT_EQ(analysis.ContainingSwitch(5), 2); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 4); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/type_manager_test.cpp b/3rdparty/spirv-tools/test/opt/type_manager_test.cpp index 1072c365c..267d98c3f 100644 --- a/3rdparty/spirv-tools/test/opt/type_manager_test.cpp +++ b/3rdparty/spirv-tools/test/opt/type_manager_test.cpp @@ -117,10 +117,10 @@ std::vector> GenerateAllTypes() { types.emplace_back(new SampledImage(image2)); // Array - types.emplace_back(new Array(f32, 100)); - types.emplace_back(new Array(f32, 42)); + types.emplace_back(new Array(f32, Array::LengthInfo{100, {0, 100u}})); + types.emplace_back(new Array(f32, Array::LengthInfo{42, {0, 42u}})); auto* a42f32 = types.back().get(); - types.emplace_back(new Array(u64, 24)); + types.emplace_back(new Array(u64, Array::LengthInfo{24, {0, 24u}})); // RuntimeArray types.emplace_back(new RuntimeArray(v3f32)); @@ -171,7 +171,8 @@ std::vector> GenerateAllTypes() { TEST(TypeManager, TypeStrings) { const std::string text = R"( - OpTypeForwardPointer !20 !2 ; id for %p is 20, Uniform is 2 + OpDecorate %spec_const_with_id SpecId 99 + OpTypeForwardPointer %p Uniform %void = OpTypeVoid %bool = OpTypeBool %u32 = OpTypeInt 32 0 @@ -201,48 +202,68 @@ TEST(TypeManager, TypeStrings) { %ps = OpTypePipeStorage %nb = OpTypeNamedBarrier %rtacc = OpTypeAccelerationStructureNV + ; Set up other kinds of OpTypeArray + %s64 = OpTypeInt 64 1 + ; ID 32 + %spec_const_without_id = OpSpecConstant %s32 44 + %spec_const_with_id = OpSpecConstant %s32 42 ;; This is ID 1 + %long_constant = OpConstant %s64 5000000000 + %spec_const_op = OpSpecConstantOp %s32 IAdd %id4 %id4 + ; ID 35 + %arr_spec_const_without_id = OpTypeArray %s32 %spec_const_without_id + %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 )"; std::vector> type_id_strs = { - {1, "void"}, - {2, "bool"}, - {3, "uint32"}, - // Id 4 is used by the constant. - {5, "sint32"}, - {6, "float64"}, - {7, ""}, - {8, "<, 3>"}, - {9, "image(sint32, 3, 0, 1, 1, 0, 3, 2)"}, - {10, "image(sint32, 3, 0, 1, 1, 0, 3, 0)"}, - {11, "sampler"}, - {12, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 2))"}, - {13, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 0))"}, - {14, "[uint32, id(4)]"}, - {15, "[float64]"}, - {16, "{uint32}"}, - {17, "{float64, sint32, }"}, - {18, "opaque('')"}, - {19, "opaque('opaque')"}, - {20, "{uint32}*"}, - {21, "(uint32, uint32) -> void"}, - {22, "event"}, - {23, "device_event"}, - {24, "reserve_id"}, - {25, "queue"}, - {26, "pipe(0)"}, - {27, "pipe_storage"}, - {28, "named_barrier"}, - {29, "accelerationStructureNV"}, + {3, "void"}, + {4, "bool"}, + {5, "uint32"}, + // Id 6 is used by the constant. + {7, "sint32"}, + {8, "float64"}, + {9, ""}, + {10, "<, 3>"}, + {11, "image(sint32, 3, 0, 1, 1, 0, 3, 2)"}, + {12, "image(sint32, 3, 0, 1, 1, 0, 3, 0)"}, + {13, "sampler"}, + {14, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 2))"}, + {15, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 0))"}, + {16, "[uint32, id(6), words(0,4)]"}, + {17, "[float64]"}, + {18, "{uint32}"}, + {19, "{float64, sint32, }"}, + {20, "opaque('')"}, + {21, "opaque('opaque')"}, + {2, "{uint32} 2*"}, // Include storage class number + {22, "(uint32, uint32) -> void"}, + {23, "event"}, + {24, "device_event"}, + {25, "reserve_id"}, + {26, "queue"}, + {27, "pipe(0)"}, + {28, "pipe_storage"}, + {29, "named_barrier"}, + {30, "accelerationStructureNV"}, + {31, "sint64"}, + {35, "[sint32, id(32), words(0,44)]"}, + {36, "[sint32, id(1), words(1,99,42)]"}, + {37, "[sint32, id(33), words(0,705032704,1)]"}, + {38, "[sint32, id(34), words(2,34)]"}, }; std::unique_ptr context = BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text); + ASSERT_NE(nullptr, context.get()); // It assembled TypeManager manager(nullptr, context.get()); EXPECT_EQ(type_id_strs.size(), manager.NumTypes()); for (const auto& p : type_id_strs) { - EXPECT_EQ(p.second, manager.GetType(p.first)->str()); + ASSERT_NE(nullptr, manager.GetType(p.first)); + EXPECT_EQ(p.second, manager.GetType(p.first)->str()) + << " id is " << p.first; EXPECT_EQ(p.first, manager.GetId(manager.GetType(p.first))); } } diff --git a/3rdparty/spirv-tools/test/opt/types_test.cpp b/3rdparty/spirv-tools/test/opt/types_test.cpp index 7426ed799..fd9880680 100644 --- a/3rdparty/spirv-tools/test/opt/types_test.cpp +++ b/3rdparty/spirv-tools/test/opt/types_test.cpp @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/types.h" + #include #include #include #include "gtest/gtest.h" -#include "source/opt/types.h" #include "source/util/make_unique.h" namespace spvtools { @@ -46,8 +47,8 @@ class SameTypeTest : public ::testing::Test { std::unique_ptr image_t_; }; -#define TestMultipleInstancesOfTheSameType(ty, ...) \ - TEST_F(SameTypeTest, MultiSame##ty) { \ +#define TestMultipleInstancesOfTheSameTypeQualified(ty, name, ...) \ + TEST_F(SameTypeTest, MultiSame##ty##name) { \ std::vector> types; \ for (int i = 0; i < 10; ++i) types.emplace_back(new ty(__VA_ARGS__)); \ for (size_t i = 0; i < types.size(); ++i) { \ @@ -61,6 +62,9 @@ class SameTypeTest : public ::testing::Test { } \ } \ } +#define TestMultipleInstancesOfTheSameType(ty, ...) \ + TestMultipleInstancesOfTheSameTypeQualified(ty, Simple, __VA_ARGS__) + TestMultipleInstancesOfTheSameType(Void); TestMultipleInstancesOfTheSameType(Bool); TestMultipleInstancesOfTheSameType(Integer, 32, true); @@ -72,7 +76,23 @@ TestMultipleInstancesOfTheSameType(Image, f64_t_.get(), SpvDimCube, 0, 0, 1, 1, SpvAccessQualifierWriteOnly); TestMultipleInstancesOfTheSameType(Sampler); TestMultipleInstancesOfTheSameType(SampledImage, image_t_.get()); -TestMultipleInstancesOfTheSameType(Array, u32_t_.get(), 10); +// There are three classes of arrays, based on the kinds of length information +// they have. +// 1. Array length is a constant or spec constant without spec ID, with literals +// for the constant value. +TestMultipleInstancesOfTheSameTypeQualified(Array, LenConstant, u32_t_.get(), + Array::LengthInfo{42, + { + 0, + 9999, + }}); +// 2. Array length is a spec constant with a given spec id. +TestMultipleInstancesOfTheSameTypeQualified(Array, LenSpecId, u32_t_.get(), + Array::LengthInfo{42, {1, 99}}); +// 3. Array length is an OpSpecConstantOp expression +TestMultipleInstancesOfTheSameTypeQualified(Array, LenDefiningId, u32_t_.get(), + Array::LengthInfo{42, {2, 42}}); + TestMultipleInstancesOfTheSameType(RuntimeArray, u32_t_.get()); TestMultipleInstancesOfTheSameType(Struct, std::vector{ u32_t_.get(), f64_t_.get()}); @@ -90,6 +110,7 @@ TestMultipleInstancesOfTheSameType(PipeStorage); TestMultipleInstancesOfTheSameType(NamedBarrier); TestMultipleInstancesOfTheSameType(AccelerationStructureNV); #undef TestMultipleInstanceOfTheSameType +#undef TestMultipleInstanceOfTheSameTypeQual std::vector> GenerateAllTypes() { // Types in this test case are only equal to themselves, nothing else. @@ -151,10 +172,31 @@ std::vector> GenerateAllTypes() { types.emplace_back(new SampledImage(image2)); // Array - types.emplace_back(new Array(f32, 100)); - types.emplace_back(new Array(f32, 42)); + // Length is constant with integer bit representation of 42. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 42u}})); auto* a42f32 = types.back().get(); - types.emplace_back(new Array(u64, 24)); + // Differs from previous in length value only. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 44u}})); + // Length is 64-bit constant integer value 42. + types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 42u, 0u}})); + // Differs from previous in length value only. + types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 44u, 0u}})); + + // Length is spec constant with spec id 18 and default value 44. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, + { + 1, + 18u, + 44u, + }})); + // Differs from previous in spec id only. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 44u}})); + // Differs from previous in literal value only. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 48u}})); + // Length is spec constant op with id 42. + types.emplace_back(new Array(f32, Array::LengthInfo{42u, {2, 42}})); + // Differs from previous in result id only. + types.emplace_back(new Array(f32, Array::LengthInfo{43u, {2, 43}})); // RuntimeArray types.emplace_back(new RuntimeArray(v3f32)); @@ -215,8 +257,8 @@ TEST(Types, AllTypes) { << types[j]->str() << "'"; } else { EXPECT_FALSE(types[i]->IsSame(types[j].get())) - << "expected '" << types[i]->str() << "' is different to '" - << types[j]->str() << "'"; + << "entry (" << i << "," << j << ") expected '" << types[i]->str() + << "' is different to '" << types[j]->str() << "'"; } } } diff --git a/3rdparty/spirv-tools/test/stats/CMakeLists.txt b/3rdparty/spirv-tools/test/stats/CMakeLists.txt deleted file mode 100644 index 393cb246d..000000000 --- a/3rdparty/spirv-tools/test/stats/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2017 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(VAL_TEST_COMMON_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/../test_fixture.h - ${CMAKE_CURRENT_SOURCE_DIR}/../unit_spirv.h -) - -add_spvtools_unittest(TARGET stats - SRCS stats_aggregate_test.cpp - stats_analyzer_test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/stats/spirv_stats.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/stats/stats_analyzer.cpp - ${VAL_TEST_COMMON_SRCS} - LIBS ${SPIRV_TOOLS} -) diff --git a/3rdparty/spirv-tools/test/stats/stats_aggregate_test.cpp b/3rdparty/spirv-tools/test/stats/stats_aggregate_test.cpp deleted file mode 100644 index 074528543..000000000 --- a/3rdparty/spirv-tools/test/stats/stats_aggregate_test.cpp +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright (c) 2017 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. - -// Tests for unique type declaration rules validator. - -#include -#include - -#include "test/test_fixture.h" -#include "test/unit_spirv.h" -#include "tools/stats/spirv_stats.h" - -namespace spvtools { -namespace stats { -namespace { - -using spvtest::ScopedContext; - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cout << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cout << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -// Calls AggregateStats for binary compiled from |code|. -void CompileAndAggregateStats(const std::string& code, SpirvStats* stats, - spv_target_env env = SPV_ENV_UNIVERSAL_1_1) { - spvtools::Context ctx(env); - ctx.SetMessageConsumer(DiagnosticsMessageHandler); - spv_binary binary; - ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(ctx.CContext(), code.c_str(), - code.size(), &binary, nullptr)); - - ASSERT_EQ(SPV_SUCCESS, AggregateStats(ctx.CContext(), binary->code, - binary->wordCount, nullptr, stats)); - spvBinaryDestroy(binary); -} - -TEST(AggregateStats, CapabilityHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(4u, stats.capability_hist.size()); - EXPECT_EQ(0u, stats.capability_hist.count(SpvCapabilityShader)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityLinkage)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.capability_hist.size()); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityShader)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityLinkage)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(5u, stats.capability_hist.size()); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityShader)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(3u, stats.capability_hist.at(SpvCapabilityLinkage)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.capability_hist.size()); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityShader)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(4u, stats.capability_hist.at(SpvCapabilityLinkage)); -} - -TEST(AggregateStats, ExtensionHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpExtension "SPV_KHR_16bit_storage" -OpMemoryModel Physical32 OpenCL -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_NV_viewport_array2" -OpExtension "greatest_extension_ever" -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.extension_hist.size()); - EXPECT_EQ(0u, stats.extension_hist.count("SPV_NV_viewport_array2")); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(3u, stats.extension_hist.size()); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_NV_viewport_array2")); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - EXPECT_EQ(1u, stats.extension_hist.at("greatest_extension_ever")); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(3u, stats.extension_hist.size()); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_NV_viewport_array2")); - EXPECT_EQ(2u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - EXPECT_EQ(1u, stats.extension_hist.at("greatest_extension_ever")); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(3u, stats.extension_hist.size()); - EXPECT_EQ(2u, stats.extension_hist.at("SPV_NV_viewport_array2")); - EXPECT_EQ(2u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - EXPECT_EQ(2u, stats.extension_hist.at("greatest_extension_ever")); -} - -TEST(AggregateStats, VersionHistogram) { - const std::string code1 = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.version_hist.size()); - EXPECT_EQ(1u, stats.version_hist.at(0x00010100)); - - CompileAndAggregateStats(code1, &stats, SPV_ENV_UNIVERSAL_1_0); - EXPECT_EQ(2u, stats.version_hist.size()); - EXPECT_EQ(1u, stats.version_hist.at(0x00010100)); - EXPECT_EQ(1u, stats.version_hist.at(0x00010000)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(2u, stats.version_hist.size()); - EXPECT_EQ(2u, stats.version_hist.at(0x00010100)); - EXPECT_EQ(1u, stats.version_hist.at(0x00010000)); - - CompileAndAggregateStats(code1, &stats, SPV_ENV_UNIVERSAL_1_0); - EXPECT_EQ(2u, stats.version_hist.size()); - EXPECT_EQ(2u, stats.version_hist.at(0x00010100)); - EXPECT_EQ(2u, stats.version_hist.at(0x00010000)); -} - -TEST(AggregateStats, GeneratorHistogram) { - const std::string code1 = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -)"; - - const uint32_t kGeneratorKhronosAssembler = SPV_GENERATOR_KHRONOS_ASSEMBLER - << 16; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.generator_hist.size()); - EXPECT_EQ(1u, stats.generator_hist.at(kGeneratorKhronosAssembler)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.generator_hist.size()); - EXPECT_EQ(2u, stats.generator_hist.at(kGeneratorKhronosAssembler)); -} - -TEST(AggregateStats, OpcodeHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability Int64 -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%u64 = OpTypeInt 64 0 -%u32 = OpTypeInt 32 0 -%f32 = OpTypeFloat 32 -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_NV_viewport_array2" -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(4u, stats.opcode_hist.size()); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpTypeFloat)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.opcode_hist.size()); - EXPECT_EQ(6u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpTypeFloat)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpExtension)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(5u, stats.opcode_hist.size()); - EXPECT_EQ(10u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(3u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeFloat)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpExtension)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.opcode_hist.size()); - EXPECT_EQ(12u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeFloat)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpExtension)); -} - -TEST(AggregateStats, OpcodeMarkovHistogram) { - const std::string code1 = R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_NV_viewport_array2" -OpMemoryModel Logical GLSL450 -)"; - - const std::string code2 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability Int64 -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%u64 = OpTypeInt 64 0 -%u32 = OpTypeInt 32 0 -%f32 = OpTypeFloat 32 -)"; - - SpirvStats stats; - stats.opcode_markov_hist.resize(2); - - CompileAndAggregateStats(code1, &stats); - ASSERT_EQ(2u, stats.opcode_markov_hist.size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[0].size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[0].at(SpvOpCapability).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpExtension).size()); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpCapability)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpExtension).at(SpvOpMemoryModel)); - - EXPECT_EQ(1u, stats.opcode_markov_hist[1].size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[1].at(SpvOpCapability).size()); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpMemoryModel)); - - CompileAndAggregateStats(code2, &stats); - ASSERT_EQ(2u, stats.opcode_markov_hist.size()); - EXPECT_EQ(4u, stats.opcode_markov_hist[0].size()); - EXPECT_EQ(3u, stats.opcode_markov_hist[0].at(SpvOpCapability).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpExtension).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpMemoryModel).size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[0].at(SpvOpTypeInt).size()); - EXPECT_EQ( - 4u, stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpCapability)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpMemoryModel)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpExtension).at(SpvOpMemoryModel)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpMemoryModel).at(SpvOpTypeInt)); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpTypeInt).at(SpvOpTypeInt)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpTypeInt).at(SpvOpTypeFloat)); - - EXPECT_EQ(3u, stats.opcode_markov_hist[1].size()); - EXPECT_EQ(4u, stats.opcode_markov_hist[1].at(SpvOpCapability).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[1].at(SpvOpMemoryModel).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[1].at(SpvOpTypeInt).size()); - EXPECT_EQ( - 2u, stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpCapability)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 2u, stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpMemoryModel)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpTypeInt)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpMemoryModel).at(SpvOpTypeInt)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpTypeInt).at(SpvOpTypeFloat)); -} - -TEST(AggregateStats, ConstantLiteralsHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpCapability Float64 -OpCapability Int16 -OpCapability Int64 -OpMemoryModel Physical32 OpenCL -%u16 = OpTypeInt 16 0 -%u32 = OpTypeInt 32 0 -%u64 = OpTypeInt 64 0 -%f32 = OpTypeFloat 32 -%f64 = OpTypeFloat 64 -%1 = OpConstant %f32 0.1 -%2 = OpConstant %f32 -2 -%3 = OpConstant %f64 -2 -%4 = OpConstant %u16 16 -%5 = OpConstant %u16 2 -%6 = OpConstant %u32 32 -%7 = OpConstant %u64 64 -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int16 -OpCapability Int64 -OpMemoryModel Logical GLSL450 -%f32 = OpTypeFloat 32 -%u16 = OpTypeInt 16 0 -%s16 = OpTypeInt 16 1 -%u32 = OpTypeInt 32 0 -%s32 = OpTypeInt 32 1 -%u64 = OpTypeInt 64 0 -%s64 = OpTypeInt 64 1 -%1 = OpConstant %f32 0.1 -%2 = OpConstant %f32 -2 -%3 = OpConstant %u16 1 -%4 = OpConstant %u16 16 -%5 = OpConstant %u16 2 -%6 = OpConstant %s16 -16 -%7 = OpConstant %u32 32 -%8 = OpConstant %s32 2 -%9 = OpConstant %s32 -32 -%10 = OpConstant %u64 64 -%11 = OpConstant %s64 -64 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(2u, stats.f32_constant_hist.size()); - EXPECT_EQ(1u, stats.f64_constant_hist.size()); - EXPECT_EQ(1u, stats.f32_constant_hist.at(0.1f)); - EXPECT_EQ(1u, stats.f32_constant_hist.at(-2.f)); - EXPECT_EQ(1u, stats.f64_constant_hist.at(-2)); - - EXPECT_EQ(2u, stats.u16_constant_hist.size()); - EXPECT_EQ(0u, stats.s16_constant_hist.size()); - EXPECT_EQ(1u, stats.u32_constant_hist.size()); - EXPECT_EQ(0u, stats.s32_constant_hist.size()); - EXPECT_EQ(1u, stats.u64_constant_hist.size()); - EXPECT_EQ(0u, stats.s64_constant_hist.size()); - EXPECT_EQ(1u, stats.u16_constant_hist.at(16)); - EXPECT_EQ(1u, stats.u16_constant_hist.at(2)); - EXPECT_EQ(1u, stats.u32_constant_hist.at(32)); - EXPECT_EQ(1u, stats.u64_constant_hist.at(64)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(2u, stats.f32_constant_hist.size()); - EXPECT_EQ(1u, stats.f64_constant_hist.size()); - EXPECT_EQ(2u, stats.f32_constant_hist.at(0.1f)); - EXPECT_EQ(2u, stats.f32_constant_hist.at(-2.f)); - EXPECT_EQ(1u, stats.f64_constant_hist.at(-2)); - - EXPECT_EQ(3u, stats.u16_constant_hist.size()); - EXPECT_EQ(1u, stats.s16_constant_hist.size()); - EXPECT_EQ(1u, stats.u32_constant_hist.size()); - EXPECT_EQ(2u, stats.s32_constant_hist.size()); - EXPECT_EQ(1u, stats.u64_constant_hist.size()); - EXPECT_EQ(1u, stats.s64_constant_hist.size()); - EXPECT_EQ(2u, stats.u16_constant_hist.at(16)); - EXPECT_EQ(2u, stats.u16_constant_hist.at(2)); - EXPECT_EQ(1u, stats.u16_constant_hist.at(1)); - EXPECT_EQ(1u, stats.s16_constant_hist.at(-16)); - EXPECT_EQ(2u, stats.u32_constant_hist.at(32)); - EXPECT_EQ(1u, stats.s32_constant_hist.at(2)); - EXPECT_EQ(1u, stats.s32_constant_hist.at(-32)); - EXPECT_EQ(2u, stats.u64_constant_hist.at(64)); - EXPECT_EQ(1u, stats.s64_constant_hist.at(-64)); -} - -} // namespace -} // namespace stats -} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/stats/stats_analyzer_test.cpp b/3rdparty/spirv-tools/test/stats/stats_analyzer_test.cpp deleted file mode 100644 index 3764c5bdd..000000000 --- a/3rdparty/spirv-tools/test/stats/stats_analyzer_test.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2017 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. - -// Tests for unique type declaration rules validator. - -#include -#include - -#include "source/latest_version_spirv_header.h" -#include "test/test_fixture.h" -#include "tools/stats/stats_analyzer.h" - -namespace spvtools { -namespace stats { -namespace { - -// Fills |stats| with some synthetic header stats, as if aggregated from 100 -// modules (100 used for simpler percentage evaluation). -void FillDefaultStats(SpirvStats* stats) { - *stats = SpirvStats(); - stats->version_hist[0x00010000] = 40; - stats->version_hist[0x00010100] = 60; - stats->generator_hist[0x00000000] = 64; - stats->generator_hist[0x00010000] = 1; - stats->generator_hist[0x00020000] = 2; - stats->generator_hist[0x00030000] = 3; - stats->generator_hist[0x00040000] = 4; - stats->generator_hist[0x00050000] = 5; - stats->generator_hist[0x00060000] = 6; - stats->generator_hist[0x00070000] = 7; - stats->generator_hist[0x00080000] = 8; - - int num_version_entries = 0; - for (const auto& pair : stats->version_hist) { - num_version_entries += pair.second; - } - - int num_generator_entries = 0; - for (const auto& pair : stats->generator_hist) { - num_generator_entries += pair.second; - } - - EXPECT_EQ(num_version_entries, num_generator_entries); -} - -TEST(StatsAnalyzer, Version) { - SpirvStats stats; - FillDefaultStats(&stats); - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteVersion(ss); - const std::string output = ss.str(); - const std::string expected_output = "Version 1.1 60%\nVersion 1.0 40%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Generator) { - SpirvStats stats; - FillDefaultStats(&stats); - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteGenerator(ss); - const std::string output = ss.str(); - const std::string expected_output = - "Khronos 64%\nKhronos Glslang Reference Front End 8%\n" - "Khronos SPIR-V Tools Assembler 7%\nKhronos LLVM/SPIR-V Translator 6%" - "\nARM 5%\nNVIDIA 4%\nCodeplay 3%\nValve 2%\nLunarG 1%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Capability) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.capability_hist[SpvCapabilityShader] = 25; - stats.capability_hist[SpvCapabilityKernel] = 75; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteCapability(ss); - const std::string output = ss.str(); - const std::string expected_output = "Kernel 75%\nShader 25%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Extension) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.extension_hist["greatest_extension_ever"] = 1; - stats.extension_hist["worst_extension_ever"] = 10; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteExtension(ss); - const std::string output = ss.str(); - const std::string expected_output = - "worst_extension_ever 10%\ngreatest_extension_ever 1%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Opcode) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.opcode_hist[SpvOpCapability] = 20; - stats.opcode_hist[SpvOpConstant] = 80; - stats.opcode_hist[SpvOpDecorate] = 100; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteOpcode(ss); - const std::string output = ss.str(); - const std::string expected_output = - "Total unique opcodes used: 3\nDecorate 50%\n" - "Constant 40%\nCapability 10%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, OpcodeMarkov) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.opcode_hist[SpvOpFMul] = 400; - stats.opcode_hist[SpvOpFAdd] = 200; - stats.opcode_hist[SpvOpFSub] = 400; - - stats.opcode_markov_hist.resize(1); - auto& hist = stats.opcode_markov_hist[0]; - hist[SpvOpFMul][SpvOpFAdd] = 100; - hist[SpvOpFMul][SpvOpFSub] = 300; - hist[SpvOpFAdd][SpvOpFMul] = 100; - hist[SpvOpFAdd][SpvOpFAdd] = 100; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteOpcodeMarkov(ss); - const std::string output = ss.str(); - const std::string expected_output = - "FMul -> FSub 75% (base rate 40%, pair occurrences 300)\n" - "FMul -> FAdd 25% (base rate 20%, pair occurrences 100)\n" - "FAdd -> FAdd 50% (base rate 20%, pair occurrences 100)\n" - "FAdd -> FMul 50% (base rate 40%, pair occurrences 100)\n"; - - EXPECT_EQ(expected_output, output); -} - -} // namespace -} // namespace stats -} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_builtins_test.cpp b/3rdparty/spirv-tools/test/val/val_builtins_test.cpp index 797194f58..df048adc2 100644 --- a/3rdparty/spirv-tools/test/val/val_builtins_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_builtins_test.cpp @@ -62,7 +62,10 @@ using ValidateVulkanCombineBuiltInArrayedVariable = spvtest::ValidateBase< std::tuple>; using ValidateWebGPUCombineBuiltInArrayedVariable = spvtest::ValidateBase< std::tuple>; - +using ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult = + spvtest::ValidateBase< + std::tuple>; bool InitializerRequired(spv_target_env env, const char* const storage_class) { return spvIsWebGPUEnv(env) && (strncmp(storage_class, "Output", 6) == 0 || @@ -74,11 +77,20 @@ CodeGenerator GetInMainCodeGenerator(spv_target_env env, const char* const built_in, const char* const execution_model, const char* const storage_class, + const char* const capabilities, + const char* const extensions, const char* const data_type) { CodeGenerator generator = spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() : CodeGenerator::GetDefaultShaderCodeGenerator(); + if (capabilities) { + generator.capabilities_ += capabilities; + } + if (extensions) { + generator.extensions_ += extensions; + } + generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; @@ -144,8 +156,9 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetInMainCodeGenerator( - SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CodeGenerator generator = + GetInMainCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -165,8 +178,9 @@ TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InMain) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetInMainCodeGenerator( - SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + CodeGenerator generator = + GetInMainCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); ASSERT_EQ(test_result.validation_result, @@ -179,15 +193,50 @@ TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InMain) { } } +TEST_P( + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + InMain) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const char* const capabilities = std::get<4>(GetParam()); + const char* const extensions = std::get<5>(GetParam()); + const TestResult& test_result = std::get<6>(GetParam()); + + CodeGenerator generator = GetInMainCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, + capabilities, extensions, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + CodeGenerator GetInFunctionCodeGenerator(spv_target_env env, const char* const built_in, const char* const execution_model, const char* const storage_class, + const char* const capabilities, + const char* const extensions, const char* const data_type) { CodeGenerator generator = spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() : CodeGenerator::GetDefaultShaderCodeGenerator(); + if (capabilities) { + generator.capabilities_ += capabilities; + } + if (extensions) { + generator.extensions_ += extensions; + } + generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; @@ -267,8 +316,9 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetInFunctionCodeGenerator( - SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CodeGenerator generator = + GetInFunctionCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -288,8 +338,9 @@ TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InFunction) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetInFunctionCodeGenerator( - SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + CodeGenerator generator = + GetInFunctionCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); ASSERT_EQ(test_result.validation_result, @@ -302,15 +353,50 @@ TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InFunction) { } } +TEST_P( + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + InFunction) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const char* const capabilities = std::get<4>(GetParam()); + const char* const extensions = std::get<5>(GetParam()); + const TestResult& test_result = std::get<6>(GetParam()); + + CodeGenerator generator = GetInFunctionCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, + capabilities, extensions, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + CodeGenerator GetVariableCodeGenerator(spv_target_env env, const char* const built_in, const char* const execution_model, const char* const storage_class, + const char* const capabilities, + const char* const extensions, const char* const data_type) { CodeGenerator generator = spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() : CodeGenerator::GetDefaultShaderCodeGenerator(); + if (capabilities) { + generator.capabilities_ += capabilities; + } + if (extensions) { + generator.extensions_ += extensions; + } + generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; @@ -373,8 +459,9 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetVariableCodeGenerator( - SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CodeGenerator generator = + GetVariableCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -394,8 +481,9 @@ TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, Variable) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetVariableCodeGenerator( - SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + CodeGenerator generator = + GetVariableCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); ASSERT_EQ(test_result.validation_result, @@ -408,6 +496,32 @@ TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, Variable) { } } +TEST_P( + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const char* const capabilities = std::get<4>(GetParam()); + const char* const extensions = std::get<5>(GetParam()); + const TestResult& test_result = std::get<6>(GetParam()); + + CodeGenerator generator = GetVariableCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, + capabilities, extensions, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -2028,6 +2142,81 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 32-bit float array", "components are not float scalar")))); +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Input"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsInputMeshSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("MeshNV", "TaskNV"), Values("Input"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\nOpCapability MeshShadingNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\nOpExtension " + "\"SPV_NV_mesh_shader\"\n"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsInputRaySuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("RayGenerationNV", "IntersectionNV", "AnyHitNV", "ClosestHitNV", + "MissNV", "CallableNV"), + Values("Input"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\nOpCapability RayTracingNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\nOpExtension " + "\"SPV_NV_ray_tracing\"\n"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsNotInput, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Output"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class", + "uses storage class Output")))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsNotIntScalar, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Input"), Values("%f32", "%u32vec3"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int scalar", + "is not an int scalar")))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsNotInt32, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Input"), Values("%u64"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int scalar", + "has bit width 64")))); + CodeGenerator GetWorkgroupSizeSuccessGenerator(spv_target_env env) { CodeGenerator generator = env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() @@ -2785,6 +2974,112 @@ OpMemberDecorate %input_type 0 BuiltIn InstanceId "AnyHitNV execution models")); } +TEST_F(ValidateBuiltIns, ValidBuiltinsForMeshShader) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability MeshShadingNV +)"; + + generator.extensions_ = R"( +OpExtension "SPV_NV_mesh_shader" +)"; + + generator.before_types_ = R"( +OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId +OpDecorate %gl_PrimitiveID PerPrimitiveNV +OpDecorate %gl_Layer BuiltIn Layer +OpDecorate %gl_Layer PerPrimitiveNV +OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex +OpDecorate %gl_ViewportIndex PerPrimitiveNV +)"; + + generator.after_types_ = R"( +%u32_81 = OpConstant %u32 81 +%_arr_int_uint_81 = OpTypeArray %i32 %u32_81 +%_ptr_Output__arr_int_uint_81 = OpTypePointer Output %_arr_int_uint_81 +%gl_PrimitiveID = OpVariable %_ptr_Output__arr_int_uint_81 Output +%gl_Layer = OpVariable %_ptr_Output__arr_int_uint_81 Output +%gl_ViewportIndex = OpVariable %_ptr_Output__arr_int_uint_81 Output +)"; + + EntryPoint entry_point; + entry_point.name = "main_d_r"; + entry_point.execution_model = "MeshNV"; + entry_point.interfaces = "%gl_PrimitiveID %gl_Layer %gl_ViewportIndex"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateBuiltIns, InvalidBuiltinsForMeshShader) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability MeshShadingNV +)"; + + generator.extensions_ = R"( +OpExtension "SPV_NV_mesh_shader" +)"; + + generator.before_types_ = R"( +OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId +OpDecorate %gl_PrimitiveID PerPrimitiveNV +OpDecorate %gl_Layer BuiltIn Layer +OpDecorate %gl_Layer PerPrimitiveNV +OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex +OpDecorate %gl_ViewportIndex PerPrimitiveNV +)"; + + generator.after_types_ = R"( +%u32_81 = OpConstant %u32 81 +%_arr_float_uint_81 = OpTypeArray %f32 %u32_81 +%_ptr_Output__arr_float_uint_81 = OpTypePointer Output %_arr_float_uint_81 +%gl_PrimitiveID = OpVariable %_ptr_Output__arr_float_uint_81 Output +%gl_Layer = OpVariable %_ptr_Output__arr_float_uint_81 Output +%gl_ViewportIndex = OpVariable %_ptr_Output__arr_float_uint_81 Output +)"; + + EntryPoint entry_point; + entry_point.name = "main_d_r"; + entry_point.execution_model = "MeshNV"; + entry_point.interfaces = "%gl_PrimitiveID %gl_Layer %gl_ViewportIndex"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("needs to be a 32-bit int scalar")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("is not an int scalar")); +} + +TEST_F(ValidateBuiltIns, GetUnderlyingTypeNoAssert) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "PSMa" %12 %17 + OpExecutionMode %4 OriginUpperLeft + OpDecorate %gl_PointCoord BuiltIn PointCoord + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %gl_PointCoord = OpTypeStruct %v4float + %_ptr_Input_v4float = OpTypePointer Input %v4float + %_ptr_Output_v4float = OpTypePointer Output %v4float + %12 = OpVariable %_ptr_Input_v4float Input + %17 = OpVariable %_ptr_Output_v4float Output + %4 = OpFunction %void None %3 + %15 = OpLabel + OpReturn + OpFunctionEnd)"; + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("did not find an member index to get underlying data " + "type")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_cfg_test.cpp b/3rdparty/spirv-tools/test/val/val_cfg_test.cpp index 0bb8fece1..0a9357bc7 100644 --- a/3rdparty/spirv-tools/test/val/val_cfg_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_cfg_test.cpp @@ -3262,6 +3262,35 @@ OpFunctionEnd "IterationMultiple loop control operand must be greater than zero")); } +TEST_F(ValidateCFG, LoopMergeTargetsHeader) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%fn = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %loop %continue None +OpBranch %body +%continue = OpLabel +OpBranch %loop +%body = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Merge Block may not be the block containing the OpLoopMerge")); +} + TEST_F(ValidateCFG, InvalidSelectionExit) { const std::string text = R"( OpCapability Shader @@ -3403,6 +3432,149 @@ OpFunctionEnd "9[%9], but not via a structured exit")); } +TEST_F(ValidateCFG, BreakFromSwitch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpTypeInt 32 0 +%4 = OpUndef %2 +%5 = OpUndef %3 +%6 = OpTypeFunction %1 +%7 = OpFunction %1 None %6 +%8 = OpLabel +OpSelectionMerge %9 None +OpSwitch %5 %9 0 %10 +%10 = OpLabel +OpSelectionMerge %11 None +OpBranchConditional %4 %11 %12 +%12 = OpLabel +OpBranch %9 +%11 = OpLabel +OpBranch %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, InvalidBreakFromSwitch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpTypeInt 32 0 +%4 = OpUndef %2 +%5 = OpUndef %3 +%6 = OpTypeFunction %1 +%7 = OpFunction %1 None %6 +%8 = OpLabel +OpSelectionMerge %9 None +OpSwitch %5 %9 0 %10 +%10 = OpLabel +OpSelectionMerge %11 None +OpSwitch %5 %11 0 %12 +%12 = OpLabel +OpBranch %9 +%11 = OpLabel +OpBranch %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 12[%12] exits the selection headed by " + "10[%10], but not via a structured exit")); +} + +TEST_F(ValidateCFG, BreakToOuterSwitch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpTypeInt 32 0 +%4 = OpUndef %2 +%5 = OpUndef %3 +%6 = OpTypeFunction %1 +%7 = OpFunction %1 None %6 +%8 = OpLabel +OpSelectionMerge %9 None +OpSwitch %5 %9 0 %10 +%10 = OpLabel +OpSelectionMerge %11 None +OpSwitch %5 %11 0 %12 +%12 = OpLabel +OpSelectionMerge %13 None +OpBranchConditional %4 %13 %14 +%14 = OpLabel +OpBranch %9 +%13 = OpLabel +OpBranch %11 +%11 = OpLabel +OpBranch %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 14[%14] exits the selection headed by " + "10[%10], but not via a structured exit")); +} + +TEST_F(ValidateCFG, BreakToOuterLoop) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpUndef %2 +%4 = OpTypeFunction %1 +%5 = OpFunction %1 None %4 +%6 = OpLabel +OpBranch %7 +%7 = OpLabel +OpLoopMerge %8 %9 None +OpBranch %10 +%10 = OpLabel +OpLoopMerge %9 %11 None +OpBranch %12 +%12 = OpLabel +OpSelectionMerge %11 None +OpBranchConditional %3 %11 %13 +%13 = OpLabel +OpBranch %8 +%11 = OpLabel +OpBranchConditional %3 %9 %10 +%9 = OpLabel +OpBranchConditional %3 %8 %7 +%8 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 13[%13] exits the loop headed by " + "10[%10], but not via a structured exit")); +} + /// TODO(umar): Nested CFG constructs } // namespace diff --git a/3rdparty/spirv-tools/test/val/val_code_generator.cpp b/3rdparty/spirv-tools/test/val/val_code_generator.cpp index 1c83517d9..62aae9c41 100644 --- a/3rdparty/spirv-tools/test/val/val_code_generator.cpp +++ b/3rdparty/spirv-tools/test/val/val_code_generator.cpp @@ -46,6 +46,8 @@ std::string GetDefaultShaderTypes() { %bool = OpTypeBool %f32 = OpTypeFloat 32 %f64 = OpTypeFloat 64 +%i32 = OpTypeInt 32 1 +%i64 = OpTypeInt 64 1 %u32 = OpTypeInt 32 0 %u64 = OpTypeInt 64 0 %f32vec2 = OpTypeVector %f32 2 diff --git a/3rdparty/spirv-tools/test/val/val_ext_inst_test.cpp b/3rdparty/spirv-tools/test/val/val_ext_inst_test.cpp index e5ff3926e..73cb48f74 100644 --- a/3rdparty/spirv-tools/test/val/val_ext_inst_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_ext_inst_test.cpp @@ -428,6 +428,10 @@ OpCapability Matrix %f16vec8_input = OpVariable %f16vec8_ptr_input Input %f16_ptr_input = OpTypePointer Input %f16 +%u32vec8_ptr_input = OpTypePointer Input %u32vec8 +%u32vec8_input = OpVariable %u32vec8_ptr_input Input +%u32_ptr_input = OpTypePointer Input %u32 + %f32_ptr_generic = OpTypePointer Generic %f32 %u32_ptr_generic = OpTypePointer Generic %u32 @@ -4485,14 +4489,15 @@ TEST_F(ValidateExtInst, VLoadNPNotPointer) { TEST_F(ValidateExtInst, VLoadNWrongStorageClass) { std::ostringstream ss; - ss << "%ptr = OpAccessChain %u32_ptr_workgroup %u32vec8_workgroup %u32_1\n"; + ss << "%ptr = OpAccessChain %u32_ptr_input %u32vec8_input %u32_1\n"; ss << "%val1 = OpExtInst %u32vec2 %extinst vloadn %u32_1 %ptr 2\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("OpenCL.std vloadn: expected operand P storage class " - "to be UniformConstant or Generic")); + "to be UniformConstant, Generic, CrossWorkgroup, " + "Workgroup or Function")); } TEST_F(ValidateExtInst, VLoadNWrongComponentType) { @@ -4746,19 +4751,21 @@ TEST_F(ValidateExtInst, VStoreNPNotPointer) { CompileSuccessfully(GenerateKernelCode(ss.str())); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Operand 124[%_ptr_Generic_float] cannot be a type")); + HasSubstr("Operand 127[%_ptr_Generic_float] cannot be a type")); } -TEST_F(ValidateExtInst, VStoreNPNotGeneric) { +TEST_F(ValidateExtInst, VStoreNWrongStorageClass) { std::ostringstream ss; - ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n"; + ss << "%ptr_w = OpAccessChain %f32_ptr_uniform_constant " + "%f32vec8_uniform_constant %u32_1\n"; ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u32_1 %ptr_w\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpenCL.std vstoren: expected operand P storage class " - "to be Generic")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpenCL.std vstoren: expected operand P storage class " + "to be Generic, CrossWorkgroup, Workgroup or Function")); } TEST_F(ValidateExtInst, VStorePWrongDataType) { @@ -5060,7 +5067,7 @@ TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotPointer) { CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Operand 134[%_ptr_UniformConstant_uchar] cannot be a " + HasSubstr("Operand 137[%_ptr_UniformConstant_uchar] cannot be a " "type")); } diff --git a/3rdparty/spirv-tools/test/val/val_modes_test.cpp b/3rdparty/spirv-tools/test/val/val_modes_test.cpp index bc157a4f1..c5b1a378b 100644 --- a/3rdparty/spirv-tools/test/val/val_modes_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_modes_test.cpp @@ -1002,6 +1002,105 @@ OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 "constant instructions.")); } +TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpExecutionMode %main PixelInterlockOrderedEXT +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Execution mode can only be used with the Fragment execution model")); +} + +TEST_F(ValidateMode, FragmentShaderInterlockTooManyModesBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpCapability FragmentShaderSampleInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main PixelInterlockOrderedEXT +OpExecutionMode %main SampleInterlockOrderedEXT +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Fragment execution model entry points can specify at most " + "one fragment shader interlock execution mode")); +} + +TEST_F(ValidateMode, FragmentShaderInterlockNoModeBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entryf = OpLabel +OpBeginInvocationInterlockEXT +OpEndInvocationInterlockEXT +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%1 = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT require a " + "fragment shader interlock execution mode")); +} + +TEST_F(ValidateMode, FragmentShaderInterlockGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main PixelInterlockOrderedEXT +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entryf = OpLabel +OpBeginInvocationInterlockEXT +OpEndInvocationInterlockEXT +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%1 = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_opencl_test.cpp b/3rdparty/spirv-tools/test/val/val_opencl_test.cpp index 52e4db6f2..18b2f715e 100644 --- a/3rdparty/spirv-tools/test/val/val_opencl_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_opencl_test.cpp @@ -56,6 +56,217 @@ TEST_F(ValidateOpenCL, NonOpenCLMemoryModelBad) { "\n OpMemoryModel Physical32 GLSL450\n")); } +TEST_F(ValidateOpenCL, NonVoidSampledTypeImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeInt 32 0 + %2 = OpTypeImage %1 2D 0 0 0 0 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Sampled Type must be OpTypeVoid in the OpenCL environment." + "\n %2 = OpTypeImage %uint 2D 0 0 0 0 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, NonZeroMSImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 2D 0 0 1 0 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("MS must be 0 in the OpenCL environement." + "\n %2 = OpTypeImage %void 2D 0 0 1 0 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, Non1D2DArrayedImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 3D 0 1 0 0 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the OpenCL environment, Arrayed may only be set to 1 " + "when Dim is either 1D or 2D." + "\n %2 = OpTypeImage %void 3D 0 1 0 0 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, NonZeroSampledImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 3D 0 0 0 1 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Sampled must be 0 in the OpenCL environment." + "\n %2 = OpTypeImage %void 3D 0 0 0 1 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, NoAccessQualifierImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 3D 0 0 0 0 Unknown +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In the OpenCL environment, the optional " + "Access Qualifier must be present." + "\n %2 = OpTypeImage %void 3D 0 0 0 0 Unknown\n")); +} + +TEST_F(ValidateOpenCL, ImageWriteWithOptionalImageOperandsBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "test" + %uint = OpTypeInt 32 0 + %uint_7 = OpConstant %uint 7 + %uint_3 = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_4 = OpConstant %uint 4 + %void = OpTypeVoid + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown WriteOnly + %4 = OpTypeFunction %void %3 + %v2uint = OpTypeVector %uint 2 + %v4uint = OpTypeVector %uint 4 + %12 = OpConstantComposite %v2uint %uint_7 %uint_3 + %17 = OpConstantComposite %v4uint %uint_1 %uint_2 %uint_3 %uint_4 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + OpImageWrite %img %12 %17 ConstOffset %12 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Optional Image Operands are not allowed in the " + "OpenCL environment." + "\n OpImageWrite %15 %13 %14 ConstOffset %13\n")); +} + +TEST_F(ValidateOpenCL, ImageReadWithConstOffsetBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %uint_7 = OpConstant %uint 7 + %uint_3 = OpConstant %uint 3 + %void = OpTypeVoid + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %v4uint = OpTypeVector %uint 4 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantComposite %v2uint %uint_7 %uint_3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %v4uint %img %coord ConstOffset %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "ConstOffset image operand not allowed in the OpenCL environment." + "\n %call = OpImageRead %v4uint %img %coord ConstOffset %coord\n")); +} + +TEST_F(ValidateOpenCL, ImageSampleExplicitLodWithConstOffsetBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpCapability LiteralSampler + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %uint_7 = OpConstant %uint 7 + %uint_3 = OpConstant %uint 3 + %void = OpTypeVoid + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %8 = OpTypeSampler + %10 = OpTypeSampledImage %3 + %v4uint = OpTypeVector %uint 4 + %v2uint = OpTypeVector %uint 2 + %float = OpTypeFloat 32 + %9 = OpConstantSampler %8 None 0 Nearest + %coord = OpConstantComposite %v2uint %uint_7 %uint_3 + %float_0 = OpConstant %float 0 + %5 = OpFunction %void None %4 + %6 = OpFunctionParameter %3 + %entry = OpLabel + %img = OpSampledImage %10 %6 %9 + %call = OpImageSampleExplicitLod %v4uint %img %coord + Lod|ConstOffset %float_0 %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "ConstOffset image operand not allowed in the OpenCL environment." + "\n %call = OpImageSampleExplicitLod %v4uint %img " + "%coord Lod|ConstOffset %float_0 %coord\n")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/tools/CMakeLists.txt b/3rdparty/spirv-tools/tools/CMakeLists.txt index bce6f1bbf..b3a4cc1a0 100644 --- a/3rdparty/spirv-tools/tools/CMakeLists.txt +++ b/3rdparty/spirv-tools/tools/CMakeLists.txt @@ -48,13 +48,6 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS}) endif() add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS}) - add_spvtools_tool(TARGET spirv-stats - SRCS stats/stats.cpp - stats/stats_analyzer.cpp - stats/stats_analyzer.h - stats/spirv_stats.cpp - stats/spirv_stats.h - LIBS ${SPIRV_TOOLS}) add_spvtools_tool(TARGET spirv-cfg SRCS cfg/cfg.cpp cfg/bin_to_dot.h @@ -62,25 +55,16 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) LIBS ${SPIRV_TOOLS}) target_include_directories(spirv-cfg PRIVATE ${spirv-tools_SOURCE_DIR} ${SPIRV_HEADER_INCLUDE_DIR}) - target_include_directories(spirv-stats PRIVATE ${spirv-tools_SOURCE_DIR} - ${SPIRV_HEADER_INCLUDE_DIR}) - - set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt spirv-stats + set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt spirv-cfg spirv-link) if(NOT DEFINED IOS_PLATFORM) set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-reduce) endif() - if(SPIRV_BUILD_COMPRESSION) - add_spvtools_tool(TARGET spirv-markv - SRCS comp/markv.cpp - comp/markv_model_factory.cpp - comp/markv_model_shader.cpp - LIBS SPIRV-Tools-comp SPIRV-Tools-opt ${SPIRV_TOOLS}) - target_include_directories(spirv-markv PRIVATE ${spirv-tools_SOURCE_DIR} - ${SPIRV_HEADER_INCLUDE_DIR}) - set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-markv) - endif(SPIRV_BUILD_COMPRESSION) + if(SPIRV_BUILD_FUZZER) + add_spvtools_tool(TARGET spirv-fuzz SRCS fuzz/fuzz.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-fuzz ${SPIRV_TOOLS}) + set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-fuzz) + endif(SPIRV_BUILD_FUZZER) if(ENABLE_SPIRV_TOOLS_INSTALL) install(TARGETS ${SPIRV_INSTALL_TARGETS} diff --git a/3rdparty/spirv-tools/tools/comp/markv.cpp b/3rdparty/spirv-tools/tools/comp/markv.cpp deleted file mode 100644 index 9a0a51808..000000000 --- a/3rdparty/spirv-tools/tools/comp/markv.cpp +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) 2017 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "source/comp/markv.h" -#include "source/spirv_target_env.h" -#include "source/table.h" -#include "spirv-tools/optimizer.hpp" -#include "tools/comp/markv_model_factory.h" -#include "tools/io.h" - -namespace { - -const auto kSpvEnv = SPV_ENV_UNIVERSAL_1_2; - -enum Task { - kNoTask = 0, - kEncode, - kDecode, - kTest, -}; - -struct ScopedContext { - ScopedContext(spv_target_env env) : context(spvContextCreate(env)) {} - ~ScopedContext() { spvContextDestroy(context); } - spv_context context; -}; - -void print_usage(char* argv0) { - printf( - R"(%s - Encodes or decodes a SPIR-V binary to or from a MARK-V binary. - -USAGE: %s [e|d|t] [options] [] - -The input binary is read from . If no file is specified, -or if the filename is "-", then the binary is read from standard input. - -If no output is specified then the output is printed to stdout in a human -readable format. - -WIP: MARK-V codec is in early stages of development. At the moment it only -can encode and decode some SPIR-V files and only if exacly the same build of -software is used (is doesn't write or handle version numbers yet). - -Tasks: - e Encode SPIR-V to MARK-V. - d Decode MARK-V to SPIR-V. - t Test the codec by first encoding the given SPIR-V file to - MARK-V, then decoding it back to SPIR-V and comparing results. - -Options: - -h, --help Print this help. - --comments Write codec comments to stderr. - --version Display MARK-V codec version. - --validate Validate SPIR-V while encoding or decoding. - --model= - Compression model, possible values: - shader_lite - fast, poor compression ratio - shader_mid - balanced - shader_max - best compression ratio - Default: shader_lite - - -o Set the output filename. - Output goes to standard output if this option is - not specified, or if the filename is "-". - Not needed for 't' task (testing). -)", - argv0, argv0); -} - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cerr << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cerr << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -} // namespace - -int main(int argc, char** argv) { - const char* input_filename = nullptr; - const char* output_filename = nullptr; - - Task task = kNoTask; - - if (argc < 3) { - print_usage(argv[0]); - return 0; - } - - const char* task_char = argv[1]; - if (0 == strcmp("e", task_char)) { - task = kEncode; - } else if (0 == strcmp("d", task_char)) { - task = kDecode; - } else if (0 == strcmp("t", task_char)) { - task = kTest; - } - - if (task == kNoTask) { - print_usage(argv[0]); - return 1; - } - - bool want_comments = false; - bool validate_spirv_binary = false; - - spvtools::comp::MarkvModelType model_type = - spvtools::comp::kMarkvModelUnknown; - - for (int argi = 2; argi < argc; ++argi) { - if ('-' == argv[argi][0]) { - switch (argv[argi][1]) { - case 'h': - print_usage(argv[0]); - return 0; - case 'o': { - if (!output_filename && argi + 1 < argc && - (task == kEncode || task == kDecode)) { - output_filename = argv[++argi]; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case '-': { - if (0 == strcmp(argv[argi], "--help")) { - print_usage(argv[0]); - return 0; - } else if (0 == strcmp(argv[argi], "--comments")) { - want_comments = true; - } else if (0 == strcmp(argv[argi], "--version")) { - fprintf(stderr, "error: Not implemented\n"); - return 1; - } else if (0 == strcmp(argv[argi], "--validate")) { - validate_spirv_binary = true; - } else if (0 == strcmp(argv[argi], "--model=shader_lite")) { - if (model_type != spvtools::comp::kMarkvModelUnknown) - fprintf(stderr, "error: More than one model specified\n"); - model_type = spvtools::comp::kMarkvModelShaderLite; - } else if (0 == strcmp(argv[argi], "--model=shader_mid")) { - if (model_type != spvtools::comp::kMarkvModelUnknown) - fprintf(stderr, "error: More than one model specified\n"); - model_type = spvtools::comp::kMarkvModelShaderMid; - } else if (0 == strcmp(argv[argi], "--model=shader_max")) { - if (model_type != spvtools::comp::kMarkvModelUnknown) - fprintf(stderr, "error: More than one model specified\n"); - model_type = spvtools::comp::kMarkvModelShaderMax; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case '\0': { - // Setting a filename of "-" to indicate stdin. - if (!input_filename) { - input_filename = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } break; - default: - print_usage(argv[0]); - return 1; - } - } else { - if (!input_filename) { - input_filename = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } - } - - if (model_type == spvtools::comp::kMarkvModelUnknown) - model_type = spvtools::comp::kMarkvModelShaderLite; - - const auto no_comments = spvtools::comp::MarkvLogConsumer(); - const auto output_to_stderr = [](const std::string& str) { - std::cerr << str; - }; - - ScopedContext ctx(kSpvEnv); - - std::unique_ptr model = - spvtools::comp::CreateMarkvModel(model_type); - - std::vector spirv; - std::vector markv; - - spvtools::comp::MarkvCodecOptions options; - options.validate_spirv_binary = validate_spirv_binary; - - if (task == kEncode) { - if (!ReadFile(input_filename, "rb", &spirv)) return 1; - assert(!spirv.empty()); - - if (SPV_SUCCESS != spvtools::comp::SpirvToMarkv( - ctx.context, spirv, options, *model, - DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, - spvtools::comp::MarkvDebugConsumer(), &markv)) { - std::cerr << "error: Failed to encode " << input_filename << " to MARK-V " - << std::endl; - return 1; - } - - if (!WriteFile(output_filename, "wb", markv.data(), markv.size())) - return 1; - } else if (task == kDecode) { - if (!ReadFile(input_filename, "rb", &markv)) return 1; - assert(!markv.empty()); - - if (SPV_SUCCESS != spvtools::comp::MarkvToSpirv( - ctx.context, markv, options, *model, - DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, - spvtools::comp::MarkvDebugConsumer(), &spirv)) { - std::cerr << "error: Failed to decode " << input_filename << " to SPIR-V " - << std::endl; - return 1; - } - - if (!WriteFile(output_filename, "wb", spirv.data(), spirv.size())) - return 1; - } else if (task == kTest) { - if (!ReadFile(input_filename, "rb", &spirv)) return 1; - assert(!spirv.empty()); - - std::vector spirv_before; - spvtools::Optimizer optimizer(kSpvEnv); - optimizer.RegisterPass(spvtools::CreateCompactIdsPass()); - if (!optimizer.Run(spirv.data(), spirv.size(), &spirv_before)) { - std::cerr << "error: Optimizer failure on: " << input_filename - << std::endl; - } - - std::vector encoder_instruction_bits; - std::vector encoder_instruction_comments; - std::vector> encoder_instruction_words; - std::vector decoder_instruction_bits; - std::vector decoder_instruction_comments; - std::vector> decoder_instruction_words; - - const auto encoder_debug_consumer = [&](const std::vector& words, - const std::string& bits, - const std::string& comment) { - encoder_instruction_words.push_back(words); - encoder_instruction_bits.push_back(bits); - encoder_instruction_comments.push_back(comment); - return true; - }; - - if (SPV_SUCCESS != spvtools::comp::SpirvToMarkv( - ctx.context, spirv_before, options, *model, - DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, - encoder_debug_consumer, &markv)) { - std::cerr << "error: Failed to encode " << input_filename << " to MARK-V " - << std::endl; - return 1; - } - - const auto write_bug_report = [&]() { - for (size_t inst_index = 0; inst_index < decoder_instruction_words.size(); - ++inst_index) { - std::cerr << "\nInstruction #" << inst_index << std::endl; - std::cerr << "\nEncoder words: "; - for (uint32_t word : encoder_instruction_words[inst_index]) - std::cerr << word << " "; - std::cerr << "\nDecoder words: "; - for (uint32_t word : decoder_instruction_words[inst_index]) - std::cerr << word << " "; - std::cerr << std::endl; - - std::cerr << "\nEncoder bits: " << encoder_instruction_bits[inst_index]; - std::cerr << "\nDecoder bits: " << decoder_instruction_bits[inst_index]; - std::cerr << std::endl; - - std::cerr << "\nEncoder comments:\n" - << encoder_instruction_comments[inst_index]; - std::cerr << "Decoder comments:\n" - << decoder_instruction_comments[inst_index]; - std::cerr << std::endl; - } - }; - - const auto decoder_debug_consumer = [&](const std::vector& words, - const std::string& bits, - const std::string& comment) { - const size_t inst_index = decoder_instruction_words.size(); - if (inst_index >= encoder_instruction_words.size()) { - write_bug_report(); - std::cerr << "error: Decoder has more instructions than encoder: " - << input_filename << std::endl; - return false; - } - - decoder_instruction_words.push_back(words); - decoder_instruction_bits.push_back(bits); - decoder_instruction_comments.push_back(comment); - - if (encoder_instruction_words[inst_index] != - decoder_instruction_words[inst_index]) { - write_bug_report(); - std::cerr << "error: Words of the last decoded instruction differ from " - "reference: " - << input_filename << std::endl; - return false; - } - - if (encoder_instruction_bits[inst_index] != - decoder_instruction_bits[inst_index]) { - write_bug_report(); - std::cerr << "error: Bits of the last decoded instruction differ from " - "reference: " - << input_filename << std::endl; - return false; - } - return true; - }; - - std::vector spirv_after; - const spv_result_t decoding_result = spvtools::comp::MarkvToSpirv( - ctx.context, markv, options, *model, DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, decoder_debug_consumer, - &spirv_after); - - if (decoding_result == SPV_REQUESTED_TERMINATION) { - std::cerr << "error: Decoding interrupted by the debugger: " - << input_filename << std::endl; - return 1; - } - - if (decoding_result != SPV_SUCCESS) { - std::cerr << "error: Failed to decode encoded " << input_filename - << " back to SPIR-V " << std::endl; - return 1; - } - - assert(spirv_before.size() == spirv_after.size()); - assert(std::mismatch(std::next(spirv_before.begin(), 5), spirv_before.end(), - std::next(spirv_after.begin(), 5)) == - std::make_pair(spirv_before.end(), spirv_after.end())); - } - - return 0; -} diff --git a/3rdparty/spirv-tools/tools/comp/markv_model_factory.cpp b/3rdparty/spirv-tools/tools/comp/markv_model_factory.cpp deleted file mode 100644 index 863fcf558..000000000 --- a/3rdparty/spirv-tools/tools/comp/markv_model_factory.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2017 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 "tools/comp/markv_model_factory.h" - -#include "source/util/make_unique.h" -#include "tools/comp/markv_model_shader.h" - -namespace spvtools { -namespace comp { - -std::unique_ptr CreateMarkvModel(MarkvModelType type) { - std::unique_ptr model; - switch (type) { - case kMarkvModelShaderLite: { - model = MakeUnique(); - break; - } - case kMarkvModelShaderMid: { - model = MakeUnique(); - break; - } - case kMarkvModelShaderMax: { - model = MakeUnique(); - break; - } - case kMarkvModelUnknown: { - assert(0 && "kMarkvModelUnknown supplied to CreateMarkvModel"); - return model; - } - } - - model->SetModelType(static_cast(type)); - - return model; -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/tools/comp/markv_model_shader.cpp b/3rdparty/spirv-tools/tools/comp/markv_model_shader.cpp deleted file mode 100644 index 8e296cd8c..000000000 --- a/3rdparty/spirv-tools/tools/comp/markv_model_shader.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2017 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 "tools/comp/markv_model_shader.h" - -#include -#include -#include -#include -#include -#include - -#include "source/util/make_unique.h" - -namespace spvtools { -namespace comp { -namespace { - -// Signals that the value is not in the coding scheme and a fallback method -// needs to be used. -const uint64_t kMarkvNoneOfTheAbove = MarkvModel::GetMarkvNoneOfTheAbove(); - -inline uint32_t CombineOpcodeAndNumOperands(uint32_t opcode, - uint32_t num_operands) { - return opcode | (num_operands << 16); -} - -#include "tools/comp/markv_model_shader_default_autogen.inc" - -} // namespace - -MarkvModelShaderLite::MarkvModelShaderLite() { - const uint16_t kVersionNumber = 1; - SetModelVersion(kVersionNumber); - - opcode_and_num_operands_huffman_codec_ = - MakeUnique>(GetOpcodeAndNumOperandsHist()); - - id_fallback_strategy_ = IdFallbackStrategy::kShortDescriptor; -} - -MarkvModelShaderMid::MarkvModelShaderMid() { - const uint16_t kVersionNumber = 1; - SetModelVersion(kVersionNumber); - - opcode_and_num_operands_huffman_codec_ = - MakeUnique>(GetOpcodeAndNumOperandsHist()); - non_id_word_huffman_codecs_ = GetNonIdWordHuffmanCodecs(); - id_descriptor_huffman_codecs_ = GetIdDescriptorHuffmanCodecs(); - descriptors_with_coding_scheme_ = GetDescriptorsWithCodingScheme(); - literal_string_huffman_codecs_ = GetLiteralStringHuffmanCodecs(); - - id_fallback_strategy_ = IdFallbackStrategy::kShortDescriptor; -} - -MarkvModelShaderMax::MarkvModelShaderMax() { - const uint16_t kVersionNumber = 1; - SetModelVersion(kVersionNumber); - - opcode_and_num_operands_huffman_codec_ = - MakeUnique>(GetOpcodeAndNumOperandsHist()); - opcode_and_num_operands_markov_huffman_codecs_ = - GetOpcodeAndNumOperandsMarkovHuffmanCodecs(); - non_id_word_huffman_codecs_ = GetNonIdWordHuffmanCodecs(); - id_descriptor_huffman_codecs_ = GetIdDescriptorHuffmanCodecs(); - descriptors_with_coding_scheme_ = GetDescriptorsWithCodingScheme(); - literal_string_huffman_codecs_ = GetLiteralStringHuffmanCodecs(); - - id_fallback_strategy_ = IdFallbackStrategy::kRuleBased; -} - -} // namespace comp -} // namespace spvtools diff --git a/3rdparty/spirv-tools/tools/comp/markv_model_shader.h b/3rdparty/spirv-tools/tools/comp/markv_model_shader.h deleted file mode 100644 index 3a704571f..000000000 --- a/3rdparty/spirv-tools/tools/comp/markv_model_shader.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TOOLS_COMP_MARKV_MODEL_SHADER_H_ -#define TOOLS_COMP_MARKV_MODEL_SHADER_H_ - -#include "source/comp/markv_model.h" - -namespace spvtools { -namespace comp { - -// MARK-V shader compression model, which only uses fast and lightweight -// algorithms, which do not require training and are not heavily dependent on -// SPIR-V grammar. Compression ratio is worse than by other models. -class MarkvModelShaderLite : public MarkvModel { - public: - MarkvModelShaderLite(); -}; - -// MARK-V shader compression model with balanced compression ratio and runtime -// performance. -class MarkvModelShaderMid : public MarkvModel { - public: - MarkvModelShaderMid(); -}; - -// MARK-V shader compression model designed for maximum compression. -class MarkvModelShaderMax : public MarkvModel { - public: - MarkvModelShaderMax(); -}; - -} // namespace comp -} // namespace spvtools - -#endif // TOOLS_COMP_MARKV_MODEL_SHADER_H_ diff --git a/3rdparty/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc b/3rdparty/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc deleted file mode 100644 index 0093cf1c0..000000000 --- a/3rdparty/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc +++ /dev/null @@ -1,14519 +0,0 @@ - -std::map GetOpcodeAndNumOperandsHist() { - return std::map({ - { CombineOpcodeAndNumOperands(SpvOpExtInst, 7), 158282 }, - { CombineOpcodeAndNumOperands(SpvOpDot, 4), 151035 }, - { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 6), 183292 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleImplicitLod, 4), 126492 }, - { CombineOpcodeAndNumOperands(SpvOpExecutionMode, 2), 13311 }, - { CombineOpcodeAndNumOperands(SpvOpFNegate, 3), 29952 }, - { CombineOpcodeAndNumOperands(SpvOpExtInst, 5), 106847 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleExplicitLod, 7), 26350 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleExplicitLod, 6), 28186 }, - { CombineOpcodeAndNumOperands(SpvOpFDiv, 4), 41635 }, - { CombineOpcodeAndNumOperands(SpvOpFMul, 4), 412786 }, - { CombineOpcodeAndNumOperands(SpvOpFunction, 4), 62905 }, - { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 8), 118614 }, - { CombineOpcodeAndNumOperands(SpvOpDecorate, 2), 100735 }, - { CombineOpcodeAndNumOperands(SpvOpReturnValue, 1), 40852 }, - { CombineOpcodeAndNumOperands(SpvOpVectorTimesScalar, 4), 157091 }, - { CombineOpcodeAndNumOperands(SpvOpExtInst, 6), 122100 }, - { CombineOpcodeAndNumOperands(SpvOpAccessChain, 5), 82930 }, - { CombineOpcodeAndNumOperands(SpvOpFSub, 4), 161019 }, - { CombineOpcodeAndNumOperands(SpvOpConstant, 3), 466014 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 5), 107126 }, - { CombineOpcodeAndNumOperands(SpvOpTypeImage, 8), 34775 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleDrefExplicitLod, 7), 26146 }, - { CombineOpcodeAndNumOperands(SpvOpMemoryModel, 2), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpDecorate, 3), 485251 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 4), 78011 }, - { CombineOpcodeAndNumOperands(SpvOpTypeFloat, 2), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpVectorTimesMatrix, 4), 15848 }, - { CombineOpcodeAndNumOperands(SpvOpTypeVector, 3), 69404 }, - { CombineOpcodeAndNumOperands(SpvOpTypeFunction, 3), 19998 }, - { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 6), 40228 }, - { CombineOpcodeAndNumOperands(SpvOpCapability, 1), 22510 }, - { CombineOpcodeAndNumOperands(SpvOpTypeArray, 3), 37585 }, - { CombineOpcodeAndNumOperands(SpvOpTypeInt, 3), 30454 }, - { CombineOpcodeAndNumOperands(SpvOpFunctionCall, 4), 29021 }, - { CombineOpcodeAndNumOperands(SpvOpFAdd, 4), 342237 }, - { CombineOpcodeAndNumOperands(SpvOpTypeMatrix, 3), 24449 }, - { CombineOpcodeAndNumOperands(SpvOpLabel, 1), 129408 }, - { CombineOpcodeAndNumOperands(SpvOpTypePointer, 3), 246535 }, - { CombineOpcodeAndNumOperands(SpvOpAccessChain, 4), 503456 }, - { CombineOpcodeAndNumOperands(SpvOpTypeFunction, 2), 19779 }, - { CombineOpcodeAndNumOperands(SpvOpBranchConditional, 3), 24139 }, - { CombineOpcodeAndNumOperands(SpvOpVariable, 3), 697946 }, - { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 5), 55769 }, - { CombineOpcodeAndNumOperands(SpvOpTypeVoid, 1), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 6), 145508 }, - { CombineOpcodeAndNumOperands(SpvOpFunctionParameter, 2), 85583 }, - { CombineOpcodeAndNumOperands(SpvOpTypeSampledImage, 2), 34775 }, - { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 4), 66362 }, - { CombineOpcodeAndNumOperands(SpvOpLoad, 3), 1272902 }, - { CombineOpcodeAndNumOperands(SpvOpReturn, 0), 22122 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 4), 861008 }, - { CombineOpcodeAndNumOperands(SpvOpFunctionEnd, 0), 62905 }, - { CombineOpcodeAndNumOperands(SpvOpExtInstImport, 2), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpSelectionMerge, 2), 22009 }, - { CombineOpcodeAndNumOperands(SpvOpBranch, 1), 38275 }, - { CombineOpcodeAndNumOperands(SpvOpTypeBool, 1), 12208 }, - { CombineOpcodeAndNumOperands(SpvOpSampledImage, 4), 95518 }, - { CombineOpcodeAndNumOperands(SpvOpMemberDecorate, 3), 94887 }, - { CombineOpcodeAndNumOperands(SpvOpMemberDecorate, 4), 1942215 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 5), 205266 }, - { CombineOpcodeAndNumOperands(SpvOpUndef, 2), 22157 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeInsert, 5), 142749 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeInsert, 6), 24420 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 6), 16896 }, - { CombineOpcodeAndNumOperands(SpvOpStore, 2), 604982 }, - { CombineOpcodeAndNumOperands(SpvOpIAdd, 4), 14471 }, - { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 7), 269658 }, - { kMarkvNoneOfTheAbove, 399895 }, - }); -} - -std::map>> -GetOpcodeAndNumOperandsMarkovHuffmanCodecs() { - std::map>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262273, 0, 0}, - {262277, 0, 0}, - {262286, 0, 0}, - {327745, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393295, 0, 0}, - {393304, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 8}, - {0, 12, 19}, - {0, 18, 20}, - {0, 5, 21}, - {0, 15, 7}, - {0, 10, 1}, - {0, 23, 22}, - {0, 14, 24}, - {0, 6, 4}, - {0, 2, 17}, - {0, 13, 25}, - {0, 9, 26}, - {0, 28, 27}, - {0, 3, 29}, - {0, 30, 16}, - {0, 32, 31}, - {0, 34, 33}, - })); - - codecs.emplace(SpvOpImageSampleExplicitLod, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(55, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393303, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 5}, - {0, 29, 17}, - {0, 1, 30}, - {0, 10, 20}, - {0, 32, 31}, - {0, 33, 2}, - {0, 34, 23}, - {0, 8, 35}, - {0, 6, 36}, - {0, 19, 22}, - {0, 28, 25}, - {0, 38, 37}, - {0, 13, 39}, - {0, 40, 24}, - {0, 27, 21}, - {0, 26, 41}, - {0, 42, 12}, - {0, 15, 43}, - {0, 44, 18}, - {0, 45, 3}, - {0, 11, 7}, - {0, 16, 46}, - {0, 47, 9}, - {0, 4, 48}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - })); - - codecs.emplace(SpvOpFDiv, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(19, { - {0, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262286, 0, 0}, - {393295, 0, 0}, - {393304, 0, 0}, - {458840, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 10}, - {0, 11, 3}, - {0, 2, 9}, - {0, 4, 1}, - {0, 5, 6}, - {0, 13, 12}, - {0, 15, 14}, - {0, 16, 7}, - {0, 18, 17}, - })); - - codecs.emplace(SpvOpSampledImage, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262285, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393298, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 10}, - {0, 30, 35}, - {0, 1, 36}, - {0, 11, 37}, - {0, 38, 6}, - {0, 16, 39}, - {0, 15, 40}, - {0, 25, 2}, - {0, 41, 20}, - {0, 26, 19}, - {0, 42, 29}, - {0, 28, 22}, - {0, 23, 34}, - {0, 44, 43}, - {0, 17, 45}, - {0, 24, 27}, - {0, 18, 33}, - {0, 47, 46}, - {0, 8, 48}, - {0, 50, 49}, - {0, 32, 51}, - {0, 31, 52}, - {0, 53, 21}, - {0, 54, 13}, - {0, 3, 55}, - {0, 7, 14}, - {0, 57, 56}, - {0, 58, 5}, - {0, 59, 9}, - {0, 61, 60}, - {0, 63, 62}, - {0, 64, 12}, - {0, 66, 65}, - })); - - codecs.emplace(SpvOpFMul, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(79, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262328, 0, 0}, - {262334, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393303, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 38, 33}, - {0, 18, 41}, - {0, 42, 23}, - {0, 43, 6}, - {0, 34, 44}, - {0, 1, 45}, - {0, 31, 14}, - {0, 47, 46}, - {0, 48, 2}, - {0, 12, 21}, - {0, 49, 30}, - {0, 37, 50}, - {0, 51, 20}, - {0, 5, 24}, - {0, 40, 16}, - {0, 29, 13}, - {0, 26, 52}, - {0, 53, 17}, - {0, 36, 54}, - {0, 55, 28}, - {0, 57, 56}, - {0, 19, 25}, - {0, 39, 8}, - {0, 32, 58}, - {0, 59, 27}, - {0, 22, 10}, - {0, 35, 60}, - {0, 62, 61}, - {0, 63, 7}, - {0, 65, 64}, - {0, 4, 66}, - {0, 68, 67}, - {0, 11, 3}, - {0, 15, 69}, - {0, 9, 70}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - })); - - codecs.emplace(SpvOpFAdd, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(55, { - {0, 0, 0}, - {65556, 0, 0}, - {65562, 0, 0}, - {131073, 0, 0}, - {131094, 0, 0}, - {131105, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262177, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {327724, 0, 0}, - {393249, 0, 0}, - {393260, 0, 0}, - {458785, 0, 0}, - {524313, 0, 0}, - {524321, 0, 0}, - {589857, 0, 0}, - {655393, 0, 0}, - {720929, 0, 0}, - {852001, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 26, 24}, - {0, 29, 27}, - {0, 4, 30}, - {0, 21, 9}, - {0, 31, 20}, - {0, 33, 32}, - {0, 34, 3}, - {0, 8, 35}, - {0, 36, 5}, - {0, 23, 16}, - {0, 38, 37}, - {0, 25, 2}, - {0, 39, 1}, - {0, 17, 40}, - {0, 41, 15}, - {0, 18, 42}, - {0, 43, 6}, - {0, 44, 14}, - {0, 28, 19}, - {0, 7, 45}, - {0, 46, 22}, - {0, 48, 47}, - {0, 49, 11}, - {0, 51, 50}, - {0, 12, 10}, - {0, 53, 52}, - {0, 13, 54}, - })); - - codecs.emplace(SpvOpTypePointer, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {262328, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 9, 23}, - {0, 1, 30}, - {0, 5, 31}, - {0, 32, 28}, - {0, 33, 25}, - {0, 34, 29}, - {0, 18, 24}, - {0, 27, 16}, - {0, 7, 13}, - {0, 14, 35}, - {0, 20, 10}, - {0, 36, 21}, - {0, 2, 37}, - {0, 38, 3}, - {0, 39, 22}, - {0, 40, 19}, - {0, 41, 11}, - {0, 6, 4}, - {0, 12, 42}, - {0, 43, 8}, - {0, 15, 26}, - {0, 45, 44}, - {0, 47, 46}, - {0, 48, 17}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(SpvOpFSub, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {65785, 0, 0}, - {131134, 0, 0}, - {196719, 0, 0}, - {262209, 0, 0}, - {262276, 0, 0}, - {327745, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 4}, - {0, 2, 8}, - {0, 1, 9}, - {0, 5, 10}, - {0, 3, 6}, - {0, 12, 11}, - })); - - codecs.emplace(SpvOpIAdd, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196732, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262328, 0, 0}, - {262334, 0, 0}, - {262340, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393298, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {458842, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 2}, - {0, 31, 43}, - {0, 4, 44}, - {0, 26, 45}, - {0, 39, 46}, - {0, 34, 36}, - {0, 19, 47}, - {0, 6, 48}, - {0, 35, 9}, - {0, 12, 29}, - {0, 21, 49}, - {0, 22, 13}, - {0, 17, 50}, - {0, 23, 51}, - {0, 52, 7}, - {0, 37, 1}, - {0, 53, 3}, - {0, 54, 24}, - {0, 56, 55}, - {0, 32, 57}, - {0, 59, 58}, - {0, 42, 10}, - {0, 60, 8}, - {0, 5, 41}, - {0, 61, 20}, - {0, 62, 38}, - {0, 64, 63}, - {0, 40, 65}, - {0, 66, 18}, - {0, 15, 28}, - {0, 14, 67}, - {0, 68, 30}, - {0, 70, 69}, - {0, 72, 71}, - {0, 73, 27}, - {0, 16, 74}, - {0, 75, 33}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 11}, - })); - - codecs.emplace(SpvOpCompositeExtract, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(29, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262225, 0, 0}, - {262273, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393295, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 10, 6}, - {0, 16, 13}, - {0, 7, 17}, - {0, 15, 18}, - {0, 19, 12}, - {0, 20, 14}, - {0, 1, 4}, - {0, 22, 21}, - {0, 11, 8}, - {0, 2, 5}, - {0, 9, 23}, - {0, 3, 24}, - {0, 26, 25}, - {0, 28, 27}, - })); - - codecs.emplace(SpvOpVectorTimesMatrix, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpBranch, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {262198, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpFunctionEnd, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpBranchConditional, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(53, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 16}, - {0, 21, 28}, - {0, 18, 23}, - {0, 4, 29}, - {0, 10, 5}, - {0, 1, 30}, - {0, 32, 31}, - {0, 22, 33}, - {0, 34, 8}, - {0, 35, 15}, - {0, 13, 36}, - {0, 26, 17}, - {0, 38, 37}, - {0, 39, 11}, - {0, 40, 14}, - {0, 12, 27}, - {0, 19, 41}, - {0, 24, 42}, - {0, 44, 43}, - {0, 45, 7}, - {0, 20, 46}, - {0, 9, 47}, - {0, 48, 2}, - {0, 50, 49}, - {0, 6, 3}, - {0, 52, 51}, - })); - - codecs.emplace(SpvOpFunctionCall, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(71, { - {0, 0, 0}, - {65556, 0, 0}, - {65562, 0, 0}, - {131073, 0, 0}, - {131094, 0, 0}, - {131099, 0, 0}, - {131134, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196665, 0, 0}, - {196667, 0, 0}, - {196669, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262225, 0, 0}, - {262275, 0, 0}, - {262280, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327724, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {393228, 0, 0}, - {393260, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458831, 0, 0}, - {524313, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 22, 4}, - {0, 32, 23}, - {0, 37, 30}, - {0, 21, 38}, - {0, 39, 31}, - {0, 41, 40}, - {0, 13, 42}, - {0, 43, 26}, - {0, 10, 44}, - {0, 28, 45}, - {0, 35, 18}, - {0, 20, 46}, - {0, 33, 47}, - {0, 24, 48}, - {0, 6, 49}, - {0, 3, 50}, - {0, 16, 51}, - {0, 27, 52}, - {0, 53, 1}, - {0, 9, 17}, - {0, 29, 54}, - {0, 19, 2}, - {0, 8, 36}, - {0, 55, 34}, - {0, 25, 56}, - {0, 7, 57}, - {0, 5, 58}, - {0, 60, 59}, - {0, 61, 15}, - {0, 63, 62}, - {0, 65, 64}, - {0, 66, 11}, - {0, 12, 67}, - {0, 69, 68}, - {0, 14, 70}, - })); - - codecs.emplace(SpvOpVariable, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(SpvOpAccessChain, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(73, { - {0, 0, 0}, - {252, 0, 0}, - {253, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131073, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196667, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {196854, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262276, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {262321, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393298, 0, 0}, - {393461, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 28, 5}, - {0, 30, 8}, - {0, 13, 38}, - {0, 40, 39}, - {0, 41, 26}, - {0, 42, 19}, - {0, 43, 29}, - {0, 23, 44}, - {0, 36, 32}, - {0, 45, 22}, - {0, 2, 46}, - {0, 21, 20}, - {0, 48, 47}, - {0, 33, 49}, - {0, 4, 50}, - {0, 51, 24}, - {0, 18, 11}, - {0, 52, 12}, - {0, 25, 15}, - {0, 53, 17}, - {0, 37, 54}, - {0, 55, 35}, - {0, 7, 27}, - {0, 57, 56}, - {0, 58, 31}, - {0, 6, 59}, - {0, 1, 60}, - {0, 62, 61}, - {0, 63, 14}, - {0, 3, 16}, - {0, 34, 64}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 10, 9}, - {0, 72, 71}, - })); - - codecs.emplace(SpvOpLabel, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {56, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(SpvOpReturn, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {65784, 0, 0}, - {131127, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(SpvOpFunction, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(31, { - {0, 0, 0}, - {65556, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262177, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 1}, - {0, 13, 5}, - {0, 18, 17}, - {0, 7, 19}, - {0, 9, 20}, - {0, 16, 21}, - {0, 15, 10}, - {0, 22, 4}, - {0, 24, 23}, - {0, 25, 14}, - {0, 8, 11}, - {0, 2, 26}, - {0, 28, 27}, - {0, 3, 6}, - {0, 30, 29}, - })); - - codecs.emplace(SpvOpTypeVector, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {65784, 0, 0}, - {131127, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 4, 1}, - })); - - codecs.emplace(SpvOpFunctionParameter, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {56, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(SpvOpReturnValue, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {131105, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpTypeVoid, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(89, { - {0, 0, 0}, - {253, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458809, 0, 0}, - {458831, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {589881, 0, 0}, - {655417, 0, 0}, - {720953, 0, 0}, - {786489, 0, 0}, - {852025, 0, 0}, - {917561, 0, 0}, - {983097, 0, 0}, - {1114169, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 40, 32}, - {0, 46, 29}, - {0, 38, 27}, - {0, 20, 47}, - {0, 49, 48}, - {0, 50, 44}, - {0, 51, 43}, - {0, 14, 5}, - {0, 42, 52}, - {0, 13, 19}, - {0, 3, 26}, - {0, 54, 53}, - {0, 56, 55}, - {0, 57, 6}, - {0, 39, 37}, - {0, 15, 58}, - {0, 18, 31}, - {0, 59, 21}, - {0, 60, 17}, - {0, 61, 41}, - {0, 62, 24}, - {0, 34, 63}, - {0, 35, 64}, - {0, 65, 8}, - {0, 66, 36}, - {0, 67, 30}, - {0, 16, 11}, - {0, 69, 68}, - {0, 70, 28}, - {0, 22, 71}, - {0, 33, 72}, - {0, 45, 73}, - {0, 75, 74}, - {0, 77, 76}, - {0, 78, 12}, - {0, 1, 2}, - {0, 9, 79}, - {0, 25, 80}, - {0, 23, 81}, - {0, 4, 82}, - {0, 84, 83}, - {0, 86, 85}, - {0, 7, 10}, - {0, 88, 87}, - })); - - codecs.emplace(SpvOpStore, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {131075, 0, 0}, - {131088, 0, 0}, - {131143, 0, 0}, - {196624, 0, 0}, - {196679, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 8}, - {0, 7, 9}, - {0, 6, 10}, - {0, 5, 11}, - {0, 2, 12}, - })); - - codecs.emplace(SpvOpEntryPoint, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(97, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196732, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262276, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262326, 0, 0}, - {262328, 0, 0}, - {262330, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458809, 0, 0}, - {458817, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {589881, 0, 0}, - {720953, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 42, 47}, - {0, 48, 50}, - {0, 45, 51}, - {0, 34, 52}, - {0, 53, 41}, - {0, 1, 54}, - {0, 55, 5}, - {0, 15, 4}, - {0, 56, 35}, - {0, 26, 24}, - {0, 18, 28}, - {0, 57, 38}, - {0, 59, 58}, - {0, 60, 25}, - {0, 20, 9}, - {0, 7, 61}, - {0, 62, 22}, - {0, 11, 31}, - {0, 63, 8}, - {0, 64, 40}, - {0, 66, 65}, - {0, 27, 44}, - {0, 29, 67}, - {0, 68, 39}, - {0, 69, 2}, - {0, 37, 49}, - {0, 71, 70}, - {0, 30, 72}, - {0, 73, 17}, - {0, 33, 74}, - {0, 23, 14}, - {0, 32, 75}, - {0, 21, 76}, - {0, 77, 16}, - {0, 46, 78}, - {0, 13, 79}, - {0, 80, 12}, - {0, 19, 81}, - {0, 43, 36}, - {0, 83, 82}, - {0, 10, 84}, - {0, 85, 3}, - {0, 6, 86}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - })); - - codecs.emplace(SpvOpLoad, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(47, { - {0, 0, 0}, - {262159, 0, 0}, - {327695, 0, 0}, - {393231, 0, 0}, - {458767, 0, 0}, - {524303, 0, 0}, - {589839, 0, 0}, - {655375, 0, 0}, - {720911, 0, 0}, - {786447, 0, 0}, - {851983, 0, 0}, - {917519, 0, 0}, - {983055, 0, 0}, - {1048591, 0, 0}, - {1114127, 0, 0}, - {1179663, 0, 0}, - {1245199, 0, 0}, - {1310735, 0, 0}, - {1376271, 0, 0}, - {1441807, 0, 0}, - {1507343, 0, 0}, - {1572879, 0, 0}, - {1638415, 0, 0}, - {1703951, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 23}, - {0, 22, 25}, - {0, 21, 26}, - {0, 6, 20}, - {0, 19, 27}, - {0, 29, 28}, - {0, 24, 18}, - {0, 30, 13}, - {0, 31, 14}, - {0, 32, 7}, - {0, 17, 15}, - {0, 33, 2}, - {0, 34, 8}, - {0, 16, 12}, - {0, 35, 3}, - {0, 36, 5}, - {0, 9, 37}, - {0, 39, 38}, - {0, 11, 40}, - {0, 4, 10}, - {0, 42, 41}, - {0, 44, 43}, - {0, 46, 45}, - })); - - codecs.emplace(SpvOpMemoryModel, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {196631, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 4, 5}, - {0, 1, 6}, - })); - - codecs.emplace(SpvOpTypeFloat, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(69, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262289, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {327849, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458809, 0, 0}, - {458831, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 33, 10}, - {0, 31, 36}, - {0, 26, 37}, - {0, 5, 38}, - {0, 20, 39}, - {0, 22, 40}, - {0, 24, 25}, - {0, 15, 41}, - {0, 9, 17}, - {0, 1, 42}, - {0, 4, 43}, - {0, 35, 44}, - {0, 34, 45}, - {0, 19, 46}, - {0, 7, 29}, - {0, 16, 47}, - {0, 48, 32}, - {0, 49, 27}, - {0, 11, 14}, - {0, 18, 28}, - {0, 23, 50}, - {0, 51, 12}, - {0, 52, 21}, - {0, 6, 53}, - {0, 55, 54}, - {0, 57, 56}, - {0, 3, 58}, - {0, 13, 59}, - {0, 60, 8}, - {0, 30, 61}, - {0, 62, 2}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - })); - - codecs.emplace(SpvOpCompositeConstruct, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(39, { - {0, 0, 0}, - {65556, 0, 0}, - {131094, 0, 0}, - {131105, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {262177, 0, 0}, - {327713, 0, 0}, - {393249, 0, 0}, - {458785, 0, 0}, - {524313, 0, 0}, - {524321, 0, 0}, - {589857, 0, 0}, - {655393, 0, 0}, - {786465, 0, 0}, - {917537, 0, 0}, - {1048609, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 19, 18}, - {0, 21, 15}, - {0, 1, 22}, - {0, 16, 23}, - {0, 14, 24}, - {0, 20, 25}, - {0, 13, 17}, - {0, 3, 26}, - {0, 6, 11}, - {0, 27, 12}, - {0, 4, 28}, - {0, 29, 10}, - {0, 9, 30}, - {0, 7, 31}, - {0, 33, 32}, - {0, 34, 5}, - {0, 8, 35}, - {0, 2, 36}, - {0, 38, 37}, - })); - - codecs.emplace(SpvOpTypeFunction, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {131086, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpExtInstImport, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {131099, 0, 0}, - {196640, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(SpvOpTypeImage, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {131143, 0, 0}, - {196679, 0, 0}, - {196680, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 2}, - {0, 3, 6}, - {0, 7, 1}, - {0, 4, 8}, - })); - - codecs.emplace(SpvOpMemberDecorate, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {65553, 0, 0}, - {131083, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(SpvOpCapability, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(17, { - {0, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {327713, 0, 0}, - {458785, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 8}, - {0, 1, 10}, - {0, 6, 11}, - {0, 9, 12}, - {0, 4, 13}, - {0, 3, 14}, - {0, 15, 2}, - {0, 5, 16}, - })); - - codecs.emplace(SpvOpTypeInt, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(29, { - {0, 0, 0}, - {65556, 0, 0}, - {131073, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327724, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 16, 3}, - {0, 11, 17}, - {0, 5, 18}, - {0, 15, 19}, - {0, 13, 20}, - {0, 1, 4}, - {0, 12, 21}, - {0, 7, 22}, - {0, 14, 23}, - {0, 24, 10}, - {0, 25, 9}, - {0, 27, 26}, - {0, 8, 28}, - })); - - codecs.emplace(SpvOpConstantComposite, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {65556, 0, 0}, - {196631, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {327724, 0, 0}, - {393260, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 7}, - {0, 1, 9}, - {0, 10, 8}, - {0, 2, 11}, - {0, 5, 12}, - {0, 13, 4}, - {0, 3, 14}, - })); - - codecs.emplace(SpvOpTypeSampledImage, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(21, { - {0, 0, 0}, - {131073, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262198, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 11, 12}, - {0, 8, 13}, - {0, 7, 14}, - {0, 4, 10}, - {0, 9, 2}, - {0, 16, 15}, - {0, 1, 17}, - {0, 19, 18}, - {0, 6, 20}, - })); - - codecs.emplace(SpvOpTypeStruct, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(49, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 20, 12}, - {0, 26, 24}, - {0, 21, 27}, - {0, 28, 16}, - {0, 10, 8}, - {0, 30, 29}, - {0, 31, 17}, - {0, 32, 13}, - {0, 25, 6}, - {0, 1, 33}, - {0, 14, 11}, - {0, 3, 34}, - {0, 18, 35}, - {0, 37, 36}, - {0, 23, 5}, - {0, 38, 2}, - {0, 39, 7}, - {0, 4, 9}, - {0, 40, 19}, - {0, 42, 41}, - {0, 43, 22}, - {0, 45, 44}, - {0, 46, 15}, - {0, 48, 47}, - })); - - codecs.emplace(SpvOpFNegate, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {65555, 0, 0}, - {131143, 0, 0}, - {196679, 0, 0}, - {196680, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 6}, - {0, 1, 2}, - {0, 8, 7}, - {0, 5, 9}, - {0, 3, 10}, - })); - - codecs.emplace(SpvOpDecorate, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(25, { - {0, 0, 0}, - {65562, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262177, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 11}, - {0, 9, 14}, - {0, 10, 15}, - {0, 13, 16}, - {0, 4, 17}, - {0, 2, 1}, - {0, 18, 7}, - {0, 20, 19}, - {0, 21, 3}, - {0, 22, 6}, - {0, 5, 8}, - {0, 24, 23}, - })); - - codecs.emplace(SpvOpTypeMatrix, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(31, { - {0, 0, 0}, - {65556, 0, 0}, - {131073, 0, 0}, - {131094, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327724, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 2}, - {0, 17, 3}, - {0, 5, 18}, - {0, 1, 19}, - {0, 16, 4}, - {0, 21, 20}, - {0, 6, 15}, - {0, 7, 22}, - {0, 24, 23}, - {0, 13, 14}, - {0, 25, 8}, - {0, 26, 11}, - {0, 27, 10}, - {0, 29, 28}, - {0, 30, 9}, - })); - - codecs.emplace(SpvOpConstant, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(33, { - {0, 0, 0}, - {131113, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {327724, 0, 0}, - {393249, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {524321, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 4}, - {0, 13, 11}, - {0, 16, 15}, - {0, 18, 10}, - {0, 20, 19}, - {0, 21, 2}, - {0, 23, 22}, - {0, 8, 24}, - {0, 9, 25}, - {0, 17, 26}, - {0, 14, 27}, - {0, 12, 28}, - {0, 1, 3}, - {0, 5, 29}, - {0, 30, 7}, - {0, 32, 31}, - })); - - codecs.emplace(SpvOpTypeBool, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 7}, - {0, 2, 8}, - {0, 6, 9}, - {0, 1, 10}, - })); - - codecs.emplace(SpvOpTypeArray, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {262334, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 27}, - {0, 11, 28}, - {0, 35, 21}, - {0, 36, 1}, - {0, 4, 37}, - {0, 39, 38}, - {0, 40, 30}, - {0, 41, 12}, - {0, 19, 42}, - {0, 13, 43}, - {0, 16, 44}, - {0, 45, 22}, - {0, 34, 18}, - {0, 29, 24}, - {0, 46, 25}, - {0, 6, 2}, - {0, 9, 31}, - {0, 17, 47}, - {0, 49, 48}, - {0, 50, 33}, - {0, 51, 26}, - {0, 20, 52}, - {0, 32, 53}, - {0, 3, 54}, - {0, 15, 14}, - {0, 23, 55}, - {0, 8, 56}, - {0, 58, 57}, - {0, 10, 59}, - {0, 5, 60}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - })); - - codecs.emplace(SpvOpExtInst, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196718, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393303, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 18, 6}, - {0, 30, 22}, - {0, 31, 25}, - {0, 10, 32}, - {0, 21, 33}, - {0, 3, 34}, - {0, 35, 5}, - {0, 23, 36}, - {0, 14, 17}, - {0, 37, 26}, - {0, 1, 38}, - {0, 29, 39}, - {0, 13, 40}, - {0, 41, 19}, - {0, 28, 20}, - {0, 16, 42}, - {0, 27, 43}, - {0, 8, 24}, - {0, 7, 44}, - {0, 9, 45}, - {0, 15, 46}, - {0, 12, 47}, - {0, 48, 2}, - {0, 4, 49}, - {0, 51, 50}, - {0, 11, 52}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(SpvOpVectorTimesScalar, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393303, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 26, 29}, - {0, 20, 35}, - {0, 12, 36}, - {0, 6, 37}, - {0, 38, 28}, - {0, 30, 5}, - {0, 8, 39}, - {0, 2, 40}, - {0, 41, 21}, - {0, 1, 10}, - {0, 43, 42}, - {0, 23, 16}, - {0, 44, 33}, - {0, 34, 31}, - {0, 14, 45}, - {0, 19, 46}, - {0, 25, 47}, - {0, 49, 48}, - {0, 27, 22}, - {0, 7, 50}, - {0, 17, 32}, - {0, 18, 51}, - {0, 24, 52}, - {0, 54, 53}, - {0, 55, 9}, - {0, 56, 11}, - {0, 57, 4}, - {0, 15, 58}, - {0, 59, 13}, - {0, 60, 3}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - })); - - codecs.emplace(SpvOpVectorShuffle, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(33, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262277, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327745, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 13, 12}, - {0, 1, 18}, - {0, 19, 11}, - {0, 9, 20}, - {0, 10, 21}, - {0, 22, 15}, - {0, 23, 8}, - {0, 4, 24}, - {0, 25, 7}, - {0, 17, 26}, - {0, 5, 27}, - {0, 14, 3}, - {0, 29, 28}, - {0, 30, 2}, - {0, 6, 31}, - {0, 32, 16}, - })); - - codecs.emplace(SpvOpImageSampleImplicitLod, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(55, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {196817, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393298, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 2}, - {0, 22, 29}, - {0, 30, 1}, - {0, 6, 31}, - {0, 9, 32}, - {0, 28, 3}, - {0, 27, 33}, - {0, 20, 16}, - {0, 34, 8}, - {0, 10, 35}, - {0, 4, 36}, - {0, 24, 23}, - {0, 21, 13}, - {0, 7, 37}, - {0, 38, 14}, - {0, 25, 39}, - {0, 17, 11}, - {0, 12, 19}, - {0, 41, 40}, - {0, 42, 18}, - {0, 15, 43}, - {0, 45, 44}, - {0, 47, 46}, - {0, 26, 48}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - })); - - codecs.emplace(SpvOpDot, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {131075, 0, 0}, - {131088, 0, 0}, - {196624, 0, 0}, - {196679, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 2, 7}, - {0, 1, 8}, - {0, 6, 9}, - {0, 4, 10}, - })); - - codecs.emplace(SpvOpExecutionMode, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {196858, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpSelectionMerge, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262277, 0, 0}, - {327745, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 12}, - {0, 7, 13}, - {0, 5, 1}, - {0, 4, 10}, - {0, 14, 6}, - {0, 16, 15}, - {0, 17, 11}, - {0, 3, 8}, - {0, 19, 18}, - {0, 9, 20}, - {0, 22, 21}, - })); - - codecs.emplace(SpvOpImageSampleDrefExplicitLod, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {65790, 0, 0}, - {131073, 0, 0}, - {262198, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 1}, - {0, 3, 5}, - {0, 2, 6}, - })); - - codecs.emplace(SpvOpUndef, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {65785, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262334, 0, 0}, - {327692, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393298, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 3}, - {0, 5, 31}, - {0, 11, 32}, - {0, 33, 12}, - {0, 34, 20}, - {0, 16, 27}, - {0, 35, 23}, - {0, 37, 36}, - {0, 14, 18}, - {0, 39, 38}, - {0, 7, 30}, - {0, 8, 25}, - {0, 40, 15}, - {0, 13, 2}, - {0, 1, 29}, - {0, 19, 41}, - {0, 43, 42}, - {0, 28, 44}, - {0, 46, 45}, - {0, 22, 21}, - {0, 47, 24}, - {0, 48, 26}, - {0, 10, 6}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 4, 9}, - {0, 56, 55}, - {0, 58, 57}, - })); - - codecs.emplace(SpvOpCompositeInsert, std::move(codec)); - } - - return codecs; -} - -std::map>> -GetLiteralStringHuffmanCodecs() { - std::map>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {"", 0, 0}, - {"MainPs", 0, 0}, - {"MainVs", 0, 0}, - {"kMarkvNoneOfTheAbove", 0, 0}, - {"main", 0, 0}, - {"", 2, 3}, - {"", 1, 5}, - {"", 4, 6}, - })); - - codecs.emplace(SpvOpEntryPoint, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {"", 0, 0}, - {"GLSL.std.450", 0, 0}, - {"kMarkvNoneOfTheAbove", 0, 0}, - {"", 1, 2}, - })); - - codecs.emplace(SpvOpExtInstImport, std::move(codec)); - } - - return codecs; -} - -std::map, std::unique_ptr>> -GetNonIdWordHuffmanCodecs() { - std::map, std::unique_ptr>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(33, { - {0, 0, 0}, - {4, 0, 0}, - {8, 0, 0}, - {10, 0, 0}, - {26, 0, 0}, - {29, 0, 0}, - {31, 0, 0}, - {37, 0, 0}, - {40, 0, 0}, - {43, 0, 0}, - {46, 0, 0}, - {49, 0, 0}, - {66, 0, 0}, - {67, 0, 0}, - {68, 0, 0}, - {69, 0, 0}, - {71, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 5}, - {0, 18, 13}, - {0, 3, 7}, - {0, 19, 11}, - {0, 20, 16}, - {0, 14, 17}, - {0, 21, 1}, - {0, 2, 6}, - {0, 23, 22}, - {0, 4, 24}, - {0, 26, 25}, - {0, 28, 27}, - {0, 10, 15}, - {0, 8, 9}, - {0, 30, 29}, - {0, 32, 31}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpMemoryModel, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpMemoryModel, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {0, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpEntryPoint, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpExecutionMode, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {18, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 2}, - {0, 6, 5}, - {0, 7, 1}, - {0, 3, 8}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpExecutionMode, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1, 0, 0}, - {32, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpCapability, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {32, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeInt, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeInt, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {32, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeFloat, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 4}, - {0, 1, 5}, - {0, 6, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeVector, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeMatrix, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 7}, - {0, 6, 8}, - {0, 1, 4}, - {0, 2, 9}, - {0, 10, 3}, - {0, 12, 11}, - })); - - codecs.emplace(std::pair(SpvOpTypePointer, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(173, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {17, 0, 0}, - {18, 0, 0}, - {19, 0, 0}, - {20, 0, 0}, - {21, 0, 0}, - {22, 0, 0}, - {23, 0, 0}, - {24, 0, 0}, - {26, 0, 0}, - {27, 0, 0}, - {28, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {32, 0, 0}, - {256, 0, 0}, - {507307272, 0, 0}, - {864026611, 0, 0}, - {981668463, 0, 0}, - {997553156, 0, 0}, - {1014330372, 0, 0}, - {1020708227, 0, 0}, - {1028443341, 0, 0}, - {1032953056, 0, 0}, - {1033463938, 0, 0}, - {1033463943, 0, 0}, - {1039998884, 0, 0}, - {1039998950, 0, 0}, - {1040187392, 0, 0}, - {1042401985, 0, 0}, - {1044220635, 0, 0}, - {1045622707, 0, 0}, - {1045622740, 0, 0}, - {1048576000, 0, 0}, - {1053609165, 0, 0}, - {1053790359, 0, 0}, - {1054448026, 0, 0}, - {1055437881, 0, 0}, - {1056300230, 0, 0}, - {1056964608, 0, 0}, - {1058056805, 0, 0}, - {1059286575, 0, 0}, - {1061158912, 0, 0}, - {1061997773, 0, 0}, - {1064514355, 0, 0}, - {1064854933, 0, 0}, - {1065353216, 0, 0}, - {1069547520, 0, 0}, - {1073741824, 0, 0}, - {1077936128, 0, 0}, - {1082130432, 0, 0}, - {1091567616, 0, 0}, - {1115422720, 0, 0}, - {1124073472, 0, 0}, - {1132396544, 0, 0}, - {1140850688, 0, 0}, - {1199562752, 0, 0}, - {3179067684, 0, 0}, - {3180973575, 0, 0}, - {3182651297, 0, 0}, - {3196448879, 0, 0}, - {3204448256, 0, 0}, - {3204993516, 0, 0}, - {3205248529, 0, 0}, - {3207137644, 0, 0}, - {3208642560, 0, 0}, - {3211081967, 0, 0}, - {3212836864, 0, 0}, - {3332128768, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 38, 37}, - {0, 42, 39}, - {0, 49, 44}, - {0, 45, 43}, - {0, 26, 50}, - {0, 46, 73}, - {0, 35, 28}, - {0, 32, 65}, - {0, 83, 40}, - {0, 60, 62}, - {0, 27, 54}, - {0, 79, 67}, - {0, 31, 74}, - {0, 51, 12}, - {0, 70, 30}, - {0, 15, 16}, - {0, 88, 25}, - {0, 90, 89}, - {0, 34, 71}, - {0, 72, 29}, - {0, 92, 91}, - {0, 14, 33}, - {0, 94, 93}, - {0, 22, 23}, - {0, 21, 95}, - {0, 19, 24}, - {0, 96, 13}, - {0, 47, 41}, - {0, 53, 48}, - {0, 58, 56}, - {0, 63, 59}, - {0, 76, 75}, - {0, 78, 77}, - {0, 81, 80}, - {0, 84, 82}, - {0, 52, 20}, - {0, 97, 69}, - {0, 99, 98}, - {0, 18, 10}, - {0, 68, 61}, - {0, 17, 100}, - {0, 102, 101}, - {0, 11, 36}, - {0, 104, 103}, - {0, 86, 105}, - {0, 107, 106}, - {0, 109, 108}, - {0, 110, 9}, - {0, 8, 111}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 126, 7}, - {0, 127, 85}, - {0, 6, 128}, - {0, 129, 55}, - {0, 130, 5}, - {0, 132, 131}, - {0, 134, 133}, - {0, 136, 135}, - {0, 137, 66}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 146, 57}, - {0, 147, 64}, - {0, 148, 4}, - {0, 149, 2}, - {0, 151, 150}, - {0, 152, 3}, - {0, 154, 153}, - {0, 156, 155}, - {0, 158, 157}, - {0, 159, 1}, - {0, 160, 87}, - {0, 162, 161}, - {0, 164, 163}, - {0, 166, 165}, - {0, 168, 167}, - {0, 170, 169}, - {0, 172, 171}, - })); - - codecs.emplace(std::pair(SpvOpConstant, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 7}, - {0, 4, 8}, - {0, 9, 2}, - {0, 1, 5}, - {0, 10, 6}, - {0, 12, 11}, - })); - - codecs.emplace(std::pair(SpvOpVariable, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {0, 0, 0}, - {2, 0, 0}, - {6, 0, 0}, - {11, 0, 0}, - {30, 0, 0}, - {33, 0, 0}, - {34, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 8}, - {0, 9, 1}, - {0, 3, 10}, - {0, 6, 11}, - {0, 12, 2}, - {0, 7, 5}, - {0, 14, 13}, - })); - - codecs.emplace(std::pair(SpvOpDecorate, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(37, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {18, 0, 0}, - {64, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 11}, - {0, 10, 13}, - {0, 12, 14}, - {0, 21, 20}, - {0, 9, 22}, - {0, 19, 15}, - {0, 8, 23}, - {0, 18, 24}, - {0, 25, 7}, - {0, 5, 6}, - {0, 26, 16}, - {0, 27, 4}, - {0, 28, 3}, - {0, 30, 29}, - {0, 31, 2}, - {0, 33, 32}, - {0, 35, 34}, - {0, 1, 36}, - })); - - codecs.emplace(std::pair(SpvOpDecorate, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(79, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {17, 0, 0}, - {18, 0, 0}, - {19, 0, 0}, - {20, 0, 0}, - {21, 0, 0}, - {22, 0, 0}, - {23, 0, 0}, - {24, 0, 0}, - {25, 0, 0}, - {26, 0, 0}, - {27, 0, 0}, - {28, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {32, 0, 0}, - {33, 0, 0}, - {34, 0, 0}, - {35, 0, 0}, - {36, 0, 0}, - {37, 0, 0}, - {38, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 39, 37}, - {0, 40, 36}, - {0, 34, 35}, - {0, 32, 33}, - {0, 30, 31}, - {0, 27, 29}, - {0, 26, 28}, - {0, 42, 41}, - {0, 23, 25}, - {0, 38, 22}, - {0, 44, 43}, - {0, 46, 45}, - {0, 21, 47}, - {0, 19, 20}, - {0, 17, 18}, - {0, 14, 15}, - {0, 12, 10}, - {0, 16, 13}, - {0, 9, 11}, - {0, 7, 8}, - {0, 6, 5}, - {0, 24, 48}, - {0, 50, 49}, - {0, 3, 4}, - {0, 51, 2}, - {0, 1, 52}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - })); - - codecs.emplace(std::pair(SpvOpMemberDecorate, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {4, 0, 0}, - {7, 0, 0}, - {35, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 5, 2}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpMemberDecorate, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(149, { - {0, 0, 0}, - {0, 0, 0}, - {16, 0, 0}, - {28, 0, 0}, - {32, 0, 0}, - {36, 0, 0}, - {40, 0, 0}, - {44, 0, 0}, - {48, 0, 0}, - {60, 0, 0}, - {64, 0, 0}, - {76, 0, 0}, - {80, 0, 0}, - {84, 0, 0}, - {88, 0, 0}, - {92, 0, 0}, - {96, 0, 0}, - {100, 0, 0}, - {108, 0, 0}, - {112, 0, 0}, - {120, 0, 0}, - {124, 0, 0}, - {128, 0, 0}, - {132, 0, 0}, - {136, 0, 0}, - {140, 0, 0}, - {144, 0, 0}, - {148, 0, 0}, - {152, 0, 0}, - {156, 0, 0}, - {160, 0, 0}, - {172, 0, 0}, - {176, 0, 0}, - {192, 0, 0}, - {204, 0, 0}, - {208, 0, 0}, - {224, 0, 0}, - {236, 0, 0}, - {240, 0, 0}, - {248, 0, 0}, - {256, 0, 0}, - {272, 0, 0}, - {288, 0, 0}, - {292, 0, 0}, - {296, 0, 0}, - {300, 0, 0}, - {304, 0, 0}, - {316, 0, 0}, - {320, 0, 0}, - {332, 0, 0}, - {336, 0, 0}, - {348, 0, 0}, - {352, 0, 0}, - {364, 0, 0}, - {368, 0, 0}, - {372, 0, 0}, - {376, 0, 0}, - {384, 0, 0}, - {392, 0, 0}, - {400, 0, 0}, - {416, 0, 0}, - {424, 0, 0}, - {432, 0, 0}, - {448, 0, 0}, - {460, 0, 0}, - {464, 0, 0}, - {468, 0, 0}, - {472, 0, 0}, - {476, 0, 0}, - {480, 0, 0}, - {488, 0, 0}, - {492, 0, 0}, - {496, 0, 0}, - {512, 0, 0}, - {640, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 17}, - {0, 37, 31}, - {0, 21, 39}, - {0, 24, 23}, - {0, 5, 13}, - {0, 38, 76}, - {0, 51, 77}, - {0, 55, 53}, - {0, 58, 56}, - {0, 64, 61}, - {0, 67, 66}, - {0, 70, 68}, - {0, 54, 71}, - {0, 62, 60}, - {0, 65, 63}, - {0, 73, 72}, - {0, 59, 57}, - {0, 52, 74}, - {0, 50, 69}, - {0, 49, 47}, - {0, 48, 46}, - {0, 45, 43}, - {0, 42, 44}, - {0, 78, 41}, - {0, 20, 18}, - {0, 80, 79}, - {0, 15, 27}, - {0, 7, 34}, - {0, 81, 6}, - {0, 28, 3}, - {0, 35, 82}, - {0, 9, 36}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 11, 29}, - {0, 99, 25}, - {0, 100, 40}, - {0, 102, 101}, - {0, 26, 32}, - {0, 19, 30}, - {0, 16, 12}, - {0, 4, 8}, - {0, 104, 103}, - {0, 106, 105}, - {0, 33, 107}, - {0, 109, 108}, - {0, 111, 110}, - {0, 22, 112}, - {0, 113, 10}, - {0, 115, 114}, - {0, 75, 116}, - {0, 118, 117}, - {0, 119, 1}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 131, 130}, - {0, 132, 2}, - {0, 134, 133}, - {0, 136, 135}, - {0, 138, 137}, - {0, 140, 139}, - {0, 142, 141}, - {0, 144, 143}, - {0, 146, 145}, - {0, 148, 147}, - })); - - codecs.emplace(std::pair(SpvOpMemberDecorate, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 3}, - {0, 9, 5}, - {0, 1, 10}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 7}, - {0, 8, 5}, - {0, 9, 1}, - {0, 4, 10}, - {0, 11, 6}, - {0, 2, 12}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 8}, - {0, 5, 2}, - {0, 10, 9}, - {0, 1, 4}, - {0, 12, 11}, - {0, 7, 13}, - {0, 3, 14}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 5}, - {0, 9, 7}, - {0, 10, 3}, - {0, 11, 2}, - {0, 6, 1}, - {0, 13, 12}, - {0, 4, 14}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(61, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {17, 0, 0}, - {18, 0, 0}, - {19, 0, 0}, - {20, 0, 0}, - {21, 0, 0}, - {22, 0, 0}, - {23, 0, 0}, - {24, 0, 0}, - {27, 0, 0}, - {28, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 30, 16}, - {0, 26, 27}, - {0, 29, 28}, - {0, 18, 22}, - {0, 12, 19}, - {0, 15, 20}, - {0, 14, 23}, - {0, 32, 7}, - {0, 8, 21}, - {0, 11, 33}, - {0, 17, 34}, - {0, 25, 13}, - {0, 36, 35}, - {0, 9, 10}, - {0, 38, 37}, - {0, 39, 31}, - {0, 5, 40}, - {0, 42, 41}, - {0, 44, 43}, - {0, 6, 45}, - {0, 46, 24}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 55, 4}, - {0, 56, 3}, - {0, 57, 2}, - {0, 58, 1}, - {0, 60, 59}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(63, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {32, 0, 0}, - {33, 0, 0}, - {34, 0, 0}, - {35, 0, 0}, - {36, 0, 0}, - {37, 0, 0}, - {38, 0, 0}, - {39, 0, 0}, - {40, 0, 0}, - {41, 0, 0}, - {42, 0, 0}, - {43, 0, 0}, - {44, 0, 0}, - {45, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 13, 14}, - {0, 12, 9}, - {0, 11, 25}, - {0, 27, 26}, - {0, 29, 28}, - {0, 31, 30}, - {0, 23, 22}, - {0, 10, 24}, - {0, 8, 21}, - {0, 17, 7}, - {0, 19, 18}, - {0, 15, 20}, - {0, 6, 16}, - {0, 5, 33}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 45, 44}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 32, 52}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 3, 2}, - {0, 59, 4}, - {0, 60, 1}, - {0, 62, 61}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 3, 2}, - {0, 6, 4}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 11}, - {0, 10, 13}, - {0, 9, 14}, - {0, 7, 5}, - {0, 8, 6}, - {0, 4, 15}, - {0, 17, 16}, - {0, 18, 3}, - {0, 19, 2}, - {0, 20, 1}, - {0, 22, 21}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 2, 6}, - {0, 7, 1}, - {0, 4, 8}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {2, 0, 0}, - {10, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleDrefExplicitLod, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpSelectionMerge, 1), std::move(codec)); - } - - return codecs; -} - -std::map, std::unique_ptr>> -GetIdDescriptorHuffmanCodecs() { - std::map, std::unique_ptr>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 1, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(63, { - {0, 0, 0}, - {34183582, 0, 0}, - {223800276, 0, 0}, - {295018543, 0, 0}, - {439764402, 0, 0}, - {443558693, 0, 0}, - {583624926, 0, 0}, - {599185303, 0, 0}, - {779021139, 0, 0}, - {1015552308, 0, 0}, - {1027242654, 0, 0}, - {1077859090, 0, 0}, - {1104362365, 0, 0}, - {1132589448, 0, 0}, - {1236389532, 0, 0}, - {1739837626, 0, 0}, - {1955104493, 0, 0}, - {2161102232, 0, 0}, - {2197874825, 0, 0}, - {2217833278, 0, 0}, - {2244470522, 0, 0}, - {2532518896, 0, 0}, - {2789375411, 0, 0}, - {3061690214, 0, 0}, - {3287039847, 0, 0}, - {3357301402, 0, 0}, - {3365041621, 0, 0}, - {3510257966, 0, 0}, - {3534235309, 0, 0}, - {4018237905, 0, 0}, - {4145966869, 0, 0}, - {4272200782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 10, 19}, - {0, 6, 1}, - {0, 26, 13}, - {0, 2, 11}, - {0, 15, 22}, - {0, 23, 18}, - {0, 4, 27}, - {0, 28, 12}, - {0, 3, 30}, - {0, 9, 7}, - {0, 20, 14}, - {0, 29, 16}, - {0, 21, 8}, - {0, 34, 33}, - {0, 36, 35}, - {0, 31, 25}, - {0, 37, 24}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 45, 44}, - {0, 17, 5}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 32, 62}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {4228502127, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(113, { - {0, 0, 0}, - {50998433, 0, 0}, - {139011596, 0, 0}, - {181902171, 0, 0}, - {296981500, 0, 0}, - {321630747, 0, 0}, - {416853049, 0, 0}, - {464259778, 0, 0}, - {615982737, 0, 0}, - {669982125, 0, 0}, - {759277550, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {922996215, 0, 0}, - {969500141, 0, 0}, - {1015552308, 0, 0}, - {1139547465, 0, 0}, - {1203545131, 0, 0}, - {1220643281, 0, 0}, - {1220749418, 0, 0}, - {1367301635, 0, 0}, - {1395923345, 0, 0}, - {1554194368, 0, 0}, - {1742737136, 0, 0}, - {1755648697, 0, 0}, - {1962162282, 0, 0}, - {1964254745, 0, 0}, - {2055836767, 0, 0}, - {2096388952, 0, 0}, - {2124837447, 0, 0}, - {2161102232, 0, 0}, - {2321729979, 0, 0}, - {2346547796, 0, 0}, - {2399809085, 0, 0}, - {2432827426, 0, 0}, - {2455417440, 0, 0}, - {2572638469, 0, 0}, - {2614879967, 0, 0}, - {2855506940, 0, 0}, - {2919796598, 0, 0}, - {2970183398, 0, 0}, - {2976066508, 0, 0}, - {3044188332, 0, 0}, - {3061690214, 0, 0}, - {3091876332, 0, 0}, - {3104643263, 0, 0}, - {3107165180, 0, 0}, - {3187066832, 0, 0}, - {3413713311, 0, 0}, - {3487022798, 0, 0}, - {3602693817, 0, 0}, - {3678875745, 0, 0}, - {3701632935, 0, 0}, - {3829325073, 0, 0}, - {4040340620, 0, 0}, - {4174489262, 0, 0}, - {4272200782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 33, 7}, - {0, 13, 34}, - {0, 21, 18}, - {0, 53, 22}, - {0, 39, 1}, - {0, 14, 9}, - {0, 43, 26}, - {0, 51, 35}, - {0, 19, 6}, - {0, 15, 25}, - {0, 55, 29}, - {0, 32, 3}, - {0, 27, 44}, - {0, 10, 46}, - {0, 45, 24}, - {0, 36, 40}, - {0, 47, 8}, - {0, 48, 54}, - {0, 58, 5}, - {0, 60, 59}, - {0, 30, 61}, - {0, 62, 56}, - {0, 64, 63}, - {0, 41, 50}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 37, 31}, - {0, 4, 17}, - {0, 16, 20}, - {0, 72, 71}, - {0, 73, 52}, - {0, 49, 12}, - {0, 75, 74}, - {0, 76, 11}, - {0, 23, 42}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 85, 28}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 94, 2}, - {0, 96, 95}, - {0, 98, 97}, - {0, 100, 99}, - {0, 102, 101}, - {0, 38, 103}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 57, 112}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(127, { - {0, 0, 0}, - {72782198, 0, 0}, - {139011596, 0, 0}, - {296981500, 0, 0}, - {300939750, 0, 0}, - {401211099, 0, 0}, - {429277936, 0, 0}, - {505940164, 0, 0}, - {538168945, 0, 0}, - {603915804, 0, 0}, - {688216667, 0, 0}, - {706016261, 0, 0}, - {790502615, 0, 0}, - {810488476, 0, 0}, - {993150979, 0, 0}, - {1203545131, 0, 0}, - {1206726575, 0, 0}, - {1265796414, 0, 0}, - {1314843976, 0, 0}, - {1367301635, 0, 0}, - {1378082995, 0, 0}, - {1410311776, 0, 0}, - {1443829854, 0, 0}, - {1448448666, 0, 0}, - {1468919488, 0, 0}, - {1496351055, 0, 0}, - {1619778288, 0, 0}, - {1684282922, 0, 0}, - {1848784182, 0, 0}, - {1901166356, 0, 0}, - {2095546797, 0, 0}, - {2096388952, 0, 0}, - {2162986400, 0, 0}, - {2197874825, 0, 0}, - {2246405597, 0, 0}, - {2250225826, 0, 0}, - {2282454607, 0, 0}, - {2328748202, 0, 0}, - {2348201466, 0, 0}, - {2597020383, 0, 0}, - {2633682514, 0, 0}, - {2817335337, 0, 0}, - {2855506940, 0, 0}, - {2936040203, 0, 0}, - {2955375511, 0, 0}, - {3122368657, 0, 0}, - {3154597438, 0, 0}, - {3184381405, 0, 0}, - {3187066832, 0, 0}, - {3233393284, 0, 0}, - {3251128023, 0, 0}, - {3260309823, 0, 0}, - {3441531391, 0, 0}, - {3496407048, 0, 0}, - {3582002820, 0, 0}, - {3647586740, 0, 0}, - {3653838348, 0, 0}, - {3730093054, 0, 0}, - {3759072440, 0, 0}, - {3928764629, 0, 0}, - {3969279737, 0, 0}, - {3994511488, 0, 0}, - {4026740269, 0, 0}, - {4274214049, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 43, 23}, - {0, 5, 24}, - {0, 9, 8}, - {0, 36, 21}, - {0, 13, 46}, - {0, 7, 12}, - {0, 35, 20}, - {0, 61, 59}, - {0, 22, 29}, - {0, 38, 62}, - {0, 56, 45}, - {0, 6, 48}, - {0, 33, 30}, - {0, 14, 58}, - {0, 34, 28}, - {0, 51, 40}, - {0, 63, 55}, - {0, 25, 16}, - {0, 17, 11}, - {0, 53, 52}, - {0, 65, 27}, - {0, 39, 41}, - {0, 67, 66}, - {0, 69, 68}, - {0, 10, 4}, - {0, 37, 18}, - {0, 60, 47}, - {0, 1, 32}, - {0, 71, 70}, - {0, 73, 72}, - {0, 57, 26}, - {0, 74, 31}, - {0, 76, 75}, - {0, 77, 44}, - {0, 78, 15}, - {0, 79, 54}, - {0, 81, 80}, - {0, 82, 49}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 89, 19}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 2, 96}, - {0, 98, 97}, - {0, 100, 99}, - {0, 102, 101}, - {0, 104, 103}, - {0, 106, 105}, - {0, 3, 107}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 114, 50}, - {0, 116, 115}, - {0, 118, 117}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 64, 42}, - {0, 126, 125}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(93, { - {0, 0, 0}, - {99347751, 0, 0}, - {102542696, 0, 0}, - {107497541, 0, 0}, - {112452386, 0, 0}, - {139011596, 0, 0}, - {296981500, 0, 0}, - {429277936, 0, 0}, - {451957774, 0, 0}, - {508217552, 0, 0}, - {573901046, 0, 0}, - {774727851, 0, 0}, - {801484894, 0, 0}, - {920604853, 0, 0}, - {925559698, 0, 0}, - {1022915255, 0, 0}, - {1209418480, 0, 0}, - {1287937401, 0, 0}, - {1319785741, 0, 0}, - {1392080469, 0, 0}, - {1538342947, 0, 0}, - {1541020250, 0, 0}, - {1587209598, 0, 0}, - {1594733696, 0, 0}, - {1631434666, 0, 0}, - {1636389511, 0, 0}, - {1684282922, 0, 0}, - {1859128680, 0, 0}, - {1901166356, 0, 0}, - {2004567202, 0, 0}, - {2119793999, 0, 0}, - {2280400314, 0, 0}, - {2538917932, 0, 0}, - {2677264274, 0, 0}, - {2683080096, 0, 0}, - {2854085372, 0, 0}, - {2879917501, 0, 0}, - {3059119137, 0, 0}, - {3174324790, 0, 0}, - {3194725903, 0, 0}, - {3358097187, 0, 0}, - {3547456240, 0, 0}, - {3614752756, 0, 0}, - {3753486980, 0, 0}, - {3811268385, 0, 0}, - {3953733490, 0, 0}, - {3990925720, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 23, 22}, - {0, 36, 31}, - {0, 17, 40}, - {0, 27, 19}, - {0, 35, 33}, - {0, 30, 38}, - {0, 42, 39}, - {0, 46, 32}, - {0, 13, 12}, - {0, 44, 14}, - {0, 29, 11}, - {0, 10, 18}, - {0, 15, 37}, - {0, 1, 4}, - {0, 45, 2}, - {0, 21, 28}, - {0, 8, 5}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 54, 16}, - {0, 55, 25}, - {0, 56, 3}, - {0, 58, 57}, - {0, 59, 26}, - {0, 20, 7}, - {0, 61, 60}, - {0, 62, 24}, - {0, 41, 63}, - {0, 65, 64}, - {0, 9, 34}, - {0, 67, 66}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 76, 43}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 47, 91}, - {0, 92, 6}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {166253838, 0, 0}, - {679771963, 0, 0}, - {1247793383, 0, 0}, - {2261697609, 0, 0}, - {2263349224, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 8}, - {0, 9, 1}, - {0, 3, 5}, - {0, 11, 10}, - {0, 2, 12}, - {0, 7, 6}, - {0, 14, 13}, - })); - - codecs.emplace(std::pair(SpvOpTypeVector, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {789872778, 0, 0}, - {1415510495, 0, 0}, - {1951208733, 0, 0}, - {2430404313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 5}, - {0, 4, 6}, - {0, 7, 1}, - {0, 3, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeVector, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {1389644742, 0, 0}, - {3232633974, 0, 0}, - {3278176820, 0, 0}, - {3648138580, 0, 0}, - {3687777340, 0, 0}, - {3694383800, 0, 0}, - {3697687030, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 4}, - {0, 9, 6}, - {0, 10, 8}, - {0, 2, 11}, - {0, 12, 3}, - {0, 1, 13}, - {0, 14, 7}, - })); - - codecs.emplace(std::pair(SpvOpTypeArray, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeArray, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {144116905, 0, 0}, - {827246872, 0, 0}, - {1545298048, 0, 0}, - {2715370488, 0, 0}, - {2798552666, 0, 0}, - {3812456892, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 8, 6}, - {0, 9, 7}, - {0, 1, 10}, - {0, 11, 4}, - {0, 5, 12}, - })); - - codecs.emplace(std::pair(SpvOpTypeArray, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {40653745, 0, 0}, - {119981689, 0, 0}, - {153085016, 0, 0}, - {451382997, 0, 0}, - {545678922, 0, 0}, - {899570100, 0, 0}, - {929101967, 0, 0}, - {1070791291, 0, 0}, - {1100599986, 0, 0}, - {1103903216, 0, 0}, - {1154919607, 0, 0}, - {1199157863, 0, 0}, - {1258105452, 0, 0}, - {1369578001, 0, 0}, - {1372881231, 0, 0}, - {1674803691, 0, 0}, - {1677700667, 0, 0}, - {1989520052, 0, 0}, - {2593884753, 0, 0}, - {2664825925, 0, 0}, - {2924146124, 0, 0}, - {2926633629, 0, 0}, - {3249265647, 0, 0}, - {3345288309, 0, 0}, - {3410158390, 0, 0}, - {3489360962, 0, 0}, - {3495967422, 0, 0}, - {3504981554, 0, 0}, - {3705139860, 0, 0}, - {3822983876, 0, 0}, - {4141567741, 0, 0}, - {4234287173, 0, 0}, - {4240893633, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 15, 23}, - {0, 20, 17}, - {0, 32, 22}, - {0, 19, 12}, - {0, 13, 3}, - {0, 30, 27}, - {0, 4, 35}, - {0, 24, 36}, - {0, 31, 37}, - {0, 33, 38}, - {0, 39, 7}, - {0, 6, 40}, - {0, 41, 29}, - {0, 14, 42}, - {0, 43, 28}, - {0, 10, 44}, - {0, 45, 18}, - {0, 26, 46}, - {0, 5, 47}, - {0, 48, 2}, - {0, 49, 9}, - {0, 50, 16}, - {0, 34, 25}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 8, 21}, - {0, 1, 11}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {3278176820, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 6}, - {0, 2, 7}, - {0, 3, 8}, - {0, 9, 1}, - {0, 5, 10}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3232633974, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 7}, - {0, 2, 8}, - {0, 4, 9}, - {0, 10, 3}, - {0, 1, 6}, - {0, 12, 11}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 6}, - {0, 1, 7}, - {0, 3, 4}, - {0, 8, 2}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 3, 7}, - {0, 5, 4}, - {0, 8, 1}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2263349224, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 2, 7}, - {0, 8, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 2, 7}, - {0, 8, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 7, 1}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 7, 4}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 8), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 4}, - {0, 3, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 9), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 1, 6}, - {0, 4, 7}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 10), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 7, 4}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 11), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 4, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 12), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 13), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 7, 1}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 14), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 5, 3}, - {0, 6, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 15), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 16), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 7, 1}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 17), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 18), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 3, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 19), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 20), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 21), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 1}, - {0, 2, 6}, - {0, 3, 7}, - {0, 8, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 22), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 23), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 4}, - {0, 1, 7}, - {0, 2, 8}, - {0, 3, 9}, - {0, 10, 5}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 24), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 25), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 26), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 27), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 28), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 29), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 30), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 3}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 31), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 32), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 33), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 34), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 35), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 36), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 37), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1389644742, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 38), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {3697687030, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 39), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 40), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 41), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 42), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 43), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 44), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 45), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 46), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 47), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 48), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 49), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 50), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 51), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(101, { - {0, 0, 0}, - {85880059, 0, 0}, - {135486769, 0, 0}, - {304448521, 0, 0}, - {436416061, 0, 0}, - {440421571, 0, 0}, - {450406196, 0, 0}, - {503094540, 0, 0}, - {543621065, 0, 0}, - {626892406, 0, 0}, - {628544021, 0, 0}, - {827698488, 0, 0}, - {869050696, 0, 0}, - {907126242, 0, 0}, - {908777857, 0, 0}, - {910429472, 0, 0}, - {1113409935, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1322549027, 0, 0}, - {1784441183, 0, 0}, - {2080953106, 0, 0}, - {2194691858, 0, 0}, - {2448331885, 0, 0}, - {2466255445, 0, 0}, - {2468230023, 0, 0}, - {2547657777, 0, 0}, - {2549309392, 0, 0}, - {2550961007, 0, 0}, - {2894051250, 0, 0}, - {2929019254, 0, 0}, - {2934934694, 0, 0}, - {2936586309, 0, 0}, - {2938237924, 0, 0}, - {3077271274, 0, 0}, - {3092528578, 0, 0}, - {3094180193, 0, 0}, - {3094857332, 0, 0}, - {3095831808, 0, 0}, - {3183924418, 0, 0}, - {3207966516, 0, 0}, - {3282979782, 0, 0}, - {3433956341, 0, 0}, - {3561562003, 0, 0}, - {3563213618, 0, 0}, - {3564865233, 0, 0}, - {3585511591, 0, 0}, - {4028622909, 0, 0}, - {4039938779, 0, 0}, - {4050155669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 16, 25}, - {0, 50, 1}, - {0, 42, 35}, - {0, 31, 41}, - {0, 4, 43}, - {0, 9, 10}, - {0, 3, 30}, - {0, 52, 47}, - {0, 12, 53}, - {0, 55, 54}, - {0, 36, 56}, - {0, 49, 57}, - {0, 6, 58}, - {0, 34, 33}, - {0, 59, 26}, - {0, 21, 32}, - {0, 60, 15}, - {0, 24, 61}, - {0, 62, 38}, - {0, 22, 2}, - {0, 37, 7}, - {0, 63, 46}, - {0, 14, 13}, - {0, 64, 5}, - {0, 65, 45}, - {0, 66, 19}, - {0, 18, 67}, - {0, 17, 20}, - {0, 68, 11}, - {0, 8, 69}, - {0, 70, 39}, - {0, 72, 71}, - {0, 74, 73}, - {0, 40, 75}, - {0, 76, 23}, - {0, 78, 77}, - {0, 29, 79}, - {0, 28, 80}, - {0, 27, 48}, - {0, 82, 81}, - {0, 51, 83}, - {0, 84, 44}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 100, 99}, - })); - - codecs.emplace(std::pair(SpvOpTypePointer, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(65, { - {0, 0, 0}, - {119981689, 0, 0}, - {162255877, 0, 0}, - {451382997, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {1100599986, 0, 0}, - {1103903216, 0, 0}, - {1154919607, 0, 0}, - {1343794461, 0, 0}, - {1415510495, 0, 0}, - {1674803691, 0, 0}, - {1951208733, 0, 0}, - {1989520052, 0, 0}, - {2160380860, 0, 0}, - {2263349224, 0, 0}, - {2320303498, 0, 0}, - {2924146124, 0, 0}, - {2984325996, 0, 0}, - {3334207724, 0, 0}, - {3345288309, 0, 0}, - {3410158390, 0, 0}, - {3489360962, 0, 0}, - {3495967422, 0, 0}, - {3504981554, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {3866587616, 0, 0}, - {3868239231, 0, 0}, - {3869890846, 0, 0}, - {3998230222, 0, 0}, - {4240893633, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 3}, - {0, 6, 24}, - {0, 11, 7}, - {0, 32, 21}, - {0, 27, 34}, - {0, 35, 25}, - {0, 36, 8}, - {0, 26, 31}, - {0, 14, 15}, - {0, 28, 37}, - {0, 1, 23}, - {0, 39, 38}, - {0, 12, 40}, - {0, 22, 41}, - {0, 10, 16}, - {0, 43, 42}, - {0, 29, 44}, - {0, 2, 45}, - {0, 46, 19}, - {0, 48, 47}, - {0, 18, 49}, - {0, 50, 30}, - {0, 9, 33}, - {0, 52, 51}, - {0, 54, 53}, - {0, 13, 55}, - {0, 17, 56}, - {0, 5, 57}, - {0, 59, 58}, - {0, 60, 20}, - {0, 62, 61}, - {0, 64, 63}, - })); - - codecs.emplace(std::pair(SpvOpTypePointer, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(99, { - {0, 0, 0}, - {75986790, 0, 0}, - {95470391, 0, 0}, - {170378107, 0, 0}, - {172029722, 0, 0}, - {204234270, 0, 0}, - {205885885, 0, 0}, - {244668133, 0, 0}, - {265778447, 0, 0}, - {616435646, 0, 0}, - {618087261, 0, 0}, - {753954113, 0, 0}, - {1000070091, 0, 0}, - {1308462133, 0, 0}, - {1671139745, 0, 0}, - {1774874546, 0, 0}, - {1776526161, 0, 0}, - {1887808856, 0, 0}, - {1889460471, 0, 0}, - {1917966999, 0, 0}, - {2044728014, 0, 0}, - {2192810893, 0, 0}, - {2293247016, 0, 0}, - {2503194620, 0, 0}, - {2605012269, 0, 0}, - {2608484640, 0, 0}, - {2615111110, 0, 0}, - {2668769415, 0, 0}, - {2759951687, 0, 0}, - {2761603302, 0, 0}, - {2856623532, 0, 0}, - {2945369269, 0, 0}, - {2956189845, 0, 0}, - {3085119011, 0, 0}, - {3367313400, 0, 0}, - {3447882276, 0, 0}, - {3633746133, 0, 0}, - {3635397748, 0, 0}, - {3710645347, 0, 0}, - {3712296962, 0, 0}, - {3715846592, 0, 0}, - {3727494858, 0, 0}, - {3747079365, 0, 0}, - {3748965853, 0, 0}, - {3750617468, 0, 0}, - {4018820793, 0, 0}, - {4022124023, 0, 0}, - {4024173916, 0, 0}, - {4215670524, 0, 0}, - {4217322139, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 10, 9}, - {0, 31, 24}, - {0, 40, 13}, - {0, 45, 33}, - {0, 34, 46}, - {0, 43, 38}, - {0, 44, 15}, - {0, 11, 30}, - {0, 21, 6}, - {0, 47, 3}, - {0, 51, 16}, - {0, 14, 52}, - {0, 8, 53}, - {0, 35, 5}, - {0, 55, 54}, - {0, 56, 26}, - {0, 20, 57}, - {0, 39, 19}, - {0, 59, 58}, - {0, 61, 60}, - {0, 4, 62}, - {0, 2, 63}, - {0, 25, 7}, - {0, 64, 27}, - {0, 12, 22}, - {0, 65, 48}, - {0, 41, 42}, - {0, 17, 23}, - {0, 49, 66}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 18, 75}, - {0, 37, 32}, - {0, 76, 36}, - {0, 78, 77}, - {0, 79, 28}, - {0, 81, 80}, - {0, 82, 29}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 91, 50}, - {0, 93, 92}, - {0, 95, 94}, - {0, 1, 96}, - {0, 98, 97}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {899570100, 0, 0}, - {929101967, 0, 0}, - {1100599986, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3056042030, 0, 0}, - {3334207724, 0, 0}, - {3357250579, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 10, 13}, - {0, 4, 15}, - {0, 16, 11}, - {0, 17, 1}, - {0, 14, 12}, - {0, 19, 18}, - {0, 21, 20}, - {0, 7, 6}, - {0, 9, 22}, - {0, 24, 23}, - {0, 25, 2}, - {0, 26, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {283209196, 0, 0}, - {436416061, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {815757910, 0, 0}, - {827698488, 0, 0}, - {1164221089, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1525861001, 0, 0}, - {1579585816, 0, 0}, - {1675764636, 0, 0}, - {1824016656, 0, 0}, - {1951208733, 0, 0}, - {1991787192, 0, 0}, - {2180701723, 0, 0}, - {2194691858, 0, 0}, - {2320303498, 0, 0}, - {2881886868, 0, 0}, - {2926633629, 0, 0}, - {3249265647, 0, 0}, - {3334207724, 0, 0}, - {3472123498, 0, 0}, - {3674863070, 0, 0}, - {4050155669, 0, 0}, - {4141567741, 0, 0}, - {4155122613, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 24, 7}, - {0, 17, 1}, - {0, 4, 15}, - {0, 11, 16}, - {0, 28, 30}, - {0, 25, 20}, - {0, 14, 31}, - {0, 32, 26}, - {0, 12, 5}, - {0, 2, 22}, - {0, 33, 13}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 21}, - {0, 29, 18}, - {0, 27, 41}, - {0, 43, 42}, - {0, 19, 44}, - {0, 45, 23}, - {0, 6, 3}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 10, 8}, - {0, 53, 52}, - {0, 9, 54}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(17, { - {0, 0, 0}, - {679771963, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 9}, - {0, 10, 6}, - {0, 1, 5}, - {0, 11, 3}, - {0, 12, 7}, - {0, 13, 2}, - {0, 15, 14}, - {0, 16, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(17, { - {0, 0, 0}, - {679771963, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1951208733, 0, 0}, - {2194691858, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 5}, - {0, 10, 9}, - {0, 11, 6}, - {0, 7, 12}, - {0, 1, 3}, - {0, 2, 13}, - {0, 15, 14}, - {0, 4, 16}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 6}, - {0, 5, 7}, - {0, 2, 8}, - {0, 1, 9}, - {0, 10, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1951208733, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 5}, - {0, 3, 9}, - {0, 1, 10}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {789872778, 0, 0}, - {827698488, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 1}, - {0, 4, 6}, - {0, 3, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {543621065, 0, 0}, - {827698488, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 8), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {827698488, 0, 0}, - {1951208733, 0, 0}, - {3095831808, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 4}, - {0, 3, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 9), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1296054774, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 10), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1296054774, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 11), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 4, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 12), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - {0, 4, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 13), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 14), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 15), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {2430404313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpConstant, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(183, { - {0, 0, 0}, - {51041423, 0, 0}, - {52882140, 0, 0}, - {72782198, 0, 0}, - {142465290, 0, 0}, - {144116905, 0, 0}, - {158160339, 0, 0}, - {169135842, 0, 0}, - {210116709, 0, 0}, - {290391815, 0, 0}, - {296981500, 0, 0}, - {385229009, 0, 0}, - {438318340, 0, 0}, - {529742207, 0, 0}, - {628331516, 0, 0}, - {677668732, 0, 0}, - {778500192, 0, 0}, - {825595257, 0, 0}, - {910398460, 0, 0}, - {917019124, 0, 0}, - {959681532, 0, 0}, - {1031290113, 0, 0}, - {1039111164, 0, 0}, - {1064945649, 0, 0}, - {1087394637, 0, 0}, - {1092948665, 0, 0}, - {1156369516, 0, 0}, - {1158021131, 0, 0}, - {1172110445, 0, 0}, - {1304296041, 0, 0}, - {1400019344, 0, 0}, - {1450415100, 0, 0}, - {1452222566, 0, 0}, - {1543646433, 0, 0}, - {1543672828, 0, 0}, - {1612361408, 0, 0}, - {1622381564, 0, 0}, - {1691572958, 0, 0}, - {1755648697, 0, 0}, - {1782996825, 0, 0}, - {1784648440, 0, 0}, - {1930923350, 0, 0}, - {1939359710, 0, 0}, - {1971252067, 0, 0}, - {1979847999, 0, 0}, - {2078849875, 0, 0}, - {2113115132, 0, 0}, - {2135340676, 0, 0}, - {2170273742, 0, 0}, - {2268204687, 0, 0}, - {2285081596, 0, 0}, - {2318200267, 0, 0}, - {2321729979, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2466126792, 0, 0}, - {2490492987, 0, 0}, - {2524697596, 0, 0}, - {2557550659, 0, 0}, - {2678954464, 0, 0}, - {2705477184, 0, 0}, - {2715370488, 0, 0}, - {2732195517, 0, 0}, - {2775815164, 0, 0}, - {2796901051, 0, 0}, - {2798552666, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {2922615804, 0, 0}, - {2937761472, 0, 0}, - {2944827576, 0, 0}, - {3092754101, 0, 0}, - {3107165180, 0, 0}, - {3168953855, 0, 0}, - {3184177968, 0, 0}, - {3202349435, 0, 0}, - {3266548732, 0, 0}, - {3332104493, 0, 0}, - {3362723943, 0, 0}, - {3571454885, 0, 0}, - {3712763835, 0, 0}, - {3743748793, 0, 0}, - {3810805277, 0, 0}, - {3912967080, 0, 0}, - {3929248764, 0, 0}, - {3958731802, 0, 0}, - {3997952447, 0, 0}, - {4016096296, 0, 0}, - {4106658327, 0, 0}, - {4172568578, 0, 0}, - {4198082194, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 35, 16}, - {0, 49, 42}, - {0, 86, 69}, - {0, 53, 30}, - {0, 45, 89}, - {0, 50, 68}, - {0, 73, 71}, - {0, 17, 46}, - {0, 14, 81}, - {0, 63, 44}, - {0, 12, 3}, - {0, 72, 31}, - {0, 55, 67}, - {0, 36, 19}, - {0, 22, 88}, - {0, 9, 70}, - {0, 93, 23}, - {0, 95, 94}, - {0, 47, 91}, - {0, 34, 32}, - {0, 97, 96}, - {0, 41, 61}, - {0, 99, 98}, - {0, 37, 1}, - {0, 77, 100}, - {0, 51, 60}, - {0, 101, 79}, - {0, 6, 2}, - {0, 11, 7}, - {0, 24, 21}, - {0, 43, 28}, - {0, 59, 56}, - {0, 75, 62}, - {0, 80, 78}, - {0, 87, 83}, - {0, 18, 15}, - {0, 102, 38}, - {0, 104, 103}, - {0, 85, 90}, - {0, 76, 25}, - {0, 29, 105}, - {0, 107, 106}, - {0, 58, 52}, - {0, 109, 108}, - {0, 57, 110}, - {0, 112, 111}, - {0, 114, 113}, - {0, 115, 33}, - {0, 74, 116}, - {0, 118, 117}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 126, 125}, - {0, 128, 127}, - {0, 130, 129}, - {0, 131, 13}, - {0, 54, 27}, - {0, 133, 132}, - {0, 48, 40}, - {0, 5, 8}, - {0, 82, 134}, - {0, 26, 135}, - {0, 39, 4}, - {0, 136, 64}, - {0, 138, 137}, - {0, 140, 139}, - {0, 84, 141}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 20, 150}, - {0, 65, 151}, - {0, 66, 152}, - {0, 153, 10}, - {0, 155, 154}, - {0, 157, 156}, - {0, 159, 158}, - {0, 161, 160}, - {0, 163, 162}, - {0, 165, 164}, - {0, 167, 166}, - {0, 169, 168}, - {0, 170, 92}, - {0, 172, 171}, - {0, 174, 173}, - {0, 176, 175}, - {0, 178, 177}, - {0, 180, 179}, - {0, 182, 181}, - })); - - codecs.emplace(std::pair(SpvOpConstant, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1247793383, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 5}, - {0, 4, 6}, - {0, 1, 3}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {15502752, 0, 0}, - {46736908, 0, 0}, - {139011596, 0, 0}, - {149720480, 0, 0}, - {249378857, 0, 0}, - {251209228, 0, 0}, - {503145996, 0, 0}, - {836581417, 0, 0}, - {882718761, 0, 0}, - {1289566249, 0, 0}, - {1325348861, 0, 0}, - {1558001705, 0, 0}, - {1646147798, 0, 0}, - {1679946323, 0, 0}, - {1766401548, 0, 0}, - {1992893964, 0, 0}, - {2123388694, 0, 0}, - {2162986400, 0, 0}, - {2580096524, 0, 0}, - {2598189097, 0, 0}, - {2683080096, 0, 0}, - {2698156268, 0, 0}, - {2763960513, 0, 0}, - {3015046341, 0, 0}, - {3133016299, 0, 0}, - {3251128023, 0, 0}, - {3504158761, 0, 0}, - {3535289452, 0, 0}, - {3536941067, 0, 0}, - {3538592682, 0, 0}, - {3540244297, 0, 0}, - {3541895912, 0, 0}, - {3570219049, 0, 0}, - {3653838348, 0, 0}, - {3764205609, 0, 0}, - {3882634684, 0, 0}, - {3913885196, 0, 0}, - {3982047273, 0, 0}, - {4024252457, 0, 0}, - {4243119782, 0, 0}, - {4255182614, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 4}, - {0, 39, 2}, - {0, 38, 10}, - {0, 29, 41}, - {0, 23, 28}, - {0, 9, 24}, - {0, 44, 43}, - {0, 45, 6}, - {0, 20, 12}, - {0, 18, 33}, - {0, 19, 16}, - {0, 7, 46}, - {0, 48, 47}, - {0, 5, 49}, - {0, 13, 11}, - {0, 17, 14}, - {0, 25, 22}, - {0, 40, 36}, - {0, 1, 50}, - {0, 31, 30}, - {0, 51, 32}, - {0, 42, 52}, - {0, 54, 53}, - {0, 55, 15}, - {0, 37, 56}, - {0, 57, 34}, - {0, 59, 58}, - {0, 61, 60}, - {0, 35, 21}, - {0, 62, 26}, - {0, 64, 63}, - {0, 65, 27}, - {0, 3, 66}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(65, { - {0, 0, 0}, - {142465290, 0, 0}, - {158160339, 0, 0}, - {169135842, 0, 0}, - {210116709, 0, 0}, - {296981500, 0, 0}, - {615748604, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1039111164, 0, 0}, - {1087394637, 0, 0}, - {1156369516, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {2100532220, 0, 0}, - {2170273742, 0, 0}, - {2285081596, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2732195517, 0, 0}, - {2763232252, 0, 0}, - {2796901051, 0, 0}, - {2855506940, 0, 0}, - {2922615804, 0, 0}, - {2937761472, 0, 0}, - {3202349435, 0, 0}, - {3362723943, 0, 0}, - {3712763835, 0, 0}, - {3810805277, 0, 0}, - {3929248764, 0, 0}, - {4016096296, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 23}, - {0, 13, 6}, - {0, 20, 14}, - {0, 15, 24}, - {0, 17, 28}, - {0, 16, 31}, - {0, 7, 34}, - {0, 9, 32}, - {0, 36, 35}, - {0, 38, 37}, - {0, 40, 39}, - {0, 2, 8}, - {0, 10, 3}, - {0, 25, 19}, - {0, 27, 26}, - {0, 33, 30}, - {0, 11, 41}, - {0, 1, 21}, - {0, 18, 42}, - {0, 44, 43}, - {0, 46, 45}, - {0, 48, 47}, - {0, 29, 49}, - {0, 4, 50}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 59, 5}, - {0, 61, 60}, - {0, 62, 22}, - {0, 64, 63}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {52882140, 0, 0}, - {210116709, 0, 0}, - {296981500, 0, 0}, - {385229009, 0, 0}, - {615748604, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1031290113, 0, 0}, - {1039111164, 0, 0}, - {1172110445, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {1622381564, 0, 0}, - {1782996825, 0, 0}, - {1971252067, 0, 0}, - {2100532220, 0, 0}, - {2268204687, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2490492987, 0, 0}, - {2678954464, 0, 0}, - {2763232252, 0, 0}, - {2855506940, 0, 0}, - {2922615804, 0, 0}, - {3912967080, 0, 0}, - {3929248764, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 24}, - {0, 12, 5}, - {0, 22, 16}, - {0, 18, 17}, - {0, 30, 27}, - {0, 6, 13}, - {0, 9, 28}, - {0, 32, 31}, - {0, 34, 33}, - {0, 7, 35}, - {0, 4, 1}, - {0, 10, 8}, - {0, 20, 15}, - {0, 25, 21}, - {0, 36, 29}, - {0, 19, 37}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 26, 44}, - {0, 45, 2}, - {0, 47, 46}, - {0, 49, 48}, - {0, 50, 14}, - {0, 51, 3}, - {0, 53, 52}, - {0, 54, 23}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(39, { - {0, 0, 0}, - {210116709, 0, 0}, - {296981500, 0, 0}, - {615748604, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1039111164, 0, 0}, - {1092948665, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {1612361408, 0, 0}, - {2100532220, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2524697596, 0, 0}, - {2763232252, 0, 0}, - {2855506940, 0, 0}, - {3929248764, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 7}, - {0, 9, 3}, - {0, 15, 11}, - {0, 10, 21}, - {0, 18, 12}, - {0, 4, 20}, - {0, 22, 19}, - {0, 23, 6}, - {0, 14, 24}, - {0, 5, 25}, - {0, 27, 26}, - {0, 28, 17}, - {0, 30, 29}, - {0, 31, 13}, - {0, 1, 32}, - {0, 34, 33}, - {0, 16, 35}, - {0, 2, 36}, - {0, 38, 37}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {296981500, 0, 0}, - {615748604, 0, 0}, - {673708384, 0, 0}, - {959681532, 0, 0}, - {1039111164, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {1939359710, 0, 0}, - {2100532220, 0, 0}, - {2113115132, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2763232252, 0, 0}, - {2855506940, 0, 0}, - {3929248764, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 18, 3}, - {0, 6, 19}, - {0, 12, 4}, - {0, 17, 2}, - {0, 9, 7}, - {0, 20, 13}, - {0, 11, 8}, - {0, 10, 16}, - {0, 21, 15}, - {0, 5, 22}, - {0, 24, 23}, - {0, 26, 25}, - {0, 28, 27}, - {0, 29, 1}, - {0, 31, 30}, - {0, 33, 32}, - {0, 34, 14}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {929101967, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3056042030, 0, 0}, - {3334207724, 0, 0}, - {3357250579, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 11}, - {0, 9, 3}, - {0, 1, 13}, - {0, 14, 10}, - {0, 12, 15}, - {0, 17, 16}, - {0, 18, 4}, - {0, 7, 5}, - {0, 20, 19}, - {0, 2, 21}, - {0, 22, 6}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(89, { - {0, 0, 0}, - {35240468, 0, 0}, - {123060826, 0, 0}, - {184634770, 0, 0}, - {359054425, 0, 0}, - {459968607, 0, 0}, - {619875033, 0, 0}, - {904486530, 0, 0}, - {945128292, 0, 0}, - {950731750, 0, 0}, - {1058429216, 0, 0}, - {1182296898, 0, 0}, - {1238120570, 0, 0}, - {1429389803, 0, 0}, - {1652168174, 0, 0}, - {1717510093, 0, 0}, - {1766422419, 0, 0}, - {1775308984, 0, 0}, - {1776629361, 0, 0}, - {1824526196, 0, 0}, - {1957265068, 0, 0}, - {1998433745, 0, 0}, - {2055664760, 0, 0}, - {2303184249, 0, 0}, - {2451531615, 0, 0}, - {2507457870, 0, 0}, - {2550501832, 0, 0}, - {2590402790, 0, 0}, - {2649103430, 0, 0}, - {2780190687, 0, 0}, - {2831059514, 0, 0}, - {3167253437, 0, 0}, - {3269075805, 0, 0}, - {3323202731, 0, 0}, - {3361419439, 0, 0}, - {3464197236, 0, 0}, - {3472029049, 0, 0}, - {3518630848, 0, 0}, - {3604842236, 0, 0}, - {3653985133, 0, 0}, - {4091916710, 0, 0}, - {4121643374, 0, 0}, - {4185590212, 0, 0}, - {4233562270, 0, 0}, - {4235213885, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 40}, - {0, 14, 31}, - {0, 7, 9}, - {0, 29, 27}, - {0, 18, 44}, - {0, 8, 5}, - {0, 10, 3}, - {0, 41, 37}, - {0, 42, 35}, - {0, 2, 1}, - {0, 47, 46}, - {0, 48, 4}, - {0, 11, 49}, - {0, 50, 36}, - {0, 19, 51}, - {0, 53, 52}, - {0, 55, 54}, - {0, 15, 12}, - {0, 26, 16}, - {0, 56, 21}, - {0, 25, 33}, - {0, 43, 24}, - {0, 57, 39}, - {0, 59, 58}, - {0, 61, 60}, - {0, 62, 34}, - {0, 64, 63}, - {0, 17, 30}, - {0, 66, 65}, - {0, 20, 67}, - {0, 13, 68}, - {0, 28, 69}, - {0, 70, 32}, - {0, 72, 71}, - {0, 73, 22}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 80, 23}, - {0, 45, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 38, 86}, - {0, 88, 87}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {75986790, 0, 0}, - {95470391, 0, 0}, - {170378107, 0, 0}, - {172029722, 0, 0}, - {204234270, 0, 0}, - {205885885, 0, 0}, - {244668133, 0, 0}, - {265778447, 0, 0}, - {753954113, 0, 0}, - {1000070091, 0, 0}, - {1671139745, 0, 0}, - {1774874546, 0, 0}, - {1776526161, 0, 0}, - {1887808856, 0, 0}, - {1889460471, 0, 0}, - {1917966999, 0, 0}, - {2044728014, 0, 0}, - {2192810893, 0, 0}, - {2293247016, 0, 0}, - {2503194620, 0, 0}, - {2608484640, 0, 0}, - {2615111110, 0, 0}, - {2668769415, 0, 0}, - {2759951687, 0, 0}, - {2761603302, 0, 0}, - {2856623532, 0, 0}, - {2956189845, 0, 0}, - {3085119011, 0, 0}, - {3367313400, 0, 0}, - {3447882276, 0, 0}, - {3633746133, 0, 0}, - {3635397748, 0, 0}, - {3710645347, 0, 0}, - {3712296962, 0, 0}, - {3727494858, 0, 0}, - {3747079365, 0, 0}, - {3748965853, 0, 0}, - {3750617468, 0, 0}, - {4018820793, 0, 0}, - {4022124023, 0, 0}, - {4024173916, 0, 0}, - {4215670524, 0, 0}, - {4217322139, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 39, 28}, - {0, 29, 40}, - {0, 37, 33}, - {0, 38, 12}, - {0, 9, 26}, - {0, 18, 6}, - {0, 41, 3}, - {0, 11, 13}, - {0, 5, 8}, - {0, 45, 30}, - {0, 22, 46}, - {0, 48, 47}, - {0, 16, 17}, - {0, 34, 49}, - {0, 51, 50}, - {0, 53, 52}, - {0, 7, 2}, - {0, 23, 21}, - {0, 54, 10}, - {0, 20, 36}, - {0, 55, 35}, - {0, 56, 4}, - {0, 43, 57}, - {0, 59, 58}, - {0, 60, 42}, - {0, 62, 61}, - {0, 63, 15}, - {0, 64, 31}, - {0, 14, 65}, - {0, 66, 24}, - {0, 67, 32}, - {0, 68, 19}, - {0, 70, 69}, - {0, 71, 27}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 78, 25}, - {0, 44, 79}, - {0, 81, 80}, - {0, 83, 82}, - {0, 1, 84}, - {0, 86, 85}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(41, { - {0, 0, 0}, - {436416061, 0, 0}, - {543621065, 0, 0}, - {679771963, 0, 0}, - {815757910, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1579585816, 0, 0}, - {1675764636, 0, 0}, - {1824016656, 0, 0}, - {1951208733, 0, 0}, - {2194691858, 0, 0}, - {2320303498, 0, 0}, - {2926633629, 0, 0}, - {3095831808, 0, 0}, - {3249265647, 0, 0}, - {3334207724, 0, 0}, - {4050155669, 0, 0}, - {4141567741, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 11}, - {0, 19, 16}, - {0, 9, 4}, - {0, 1, 17}, - {0, 22, 10}, - {0, 24, 23}, - {0, 15, 25}, - {0, 13, 26}, - {0, 27, 20}, - {0, 12, 28}, - {0, 30, 29}, - {0, 31, 18}, - {0, 3, 21}, - {0, 32, 14}, - {0, 34, 33}, - {0, 35, 8}, - {0, 5, 6}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 7}, - })); - - codecs.emplace(std::pair(SpvOpFunctionParameter, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(41, { - {0, 0, 0}, - {522971108, 0, 0}, - {615341051, 0, 0}, - {718301639, 0, 0}, - {985750227, 0, 0}, - {1395113939, 0, 0}, - {1510333659, 0, 0}, - {1642805350, 0, 0}, - {1846856260, 0, 0}, - {1957218950, 0, 0}, - {1977038330, 0, 0}, - {1978689945, 0, 0}, - {1980341560, 0, 0}, - {2262220987, 0, 0}, - {2674422363, 0, 0}, - {3197739982, 0, 0}, - {3465954368, 0, 0}, - {3941049054, 0, 0}, - {3945795573, 0, 0}, - {4080527786, 0, 0}, - {4154758669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 17}, - {0, 4, 15}, - {0, 8, 7}, - {0, 2, 20}, - {0, 22, 19}, - {0, 24, 23}, - {0, 14, 25}, - {0, 16, 26}, - {0, 27, 13}, - {0, 6, 28}, - {0, 30, 29}, - {0, 31, 10}, - {0, 11, 21}, - {0, 32, 12}, - {0, 34, 33}, - {0, 35, 5}, - {0, 9, 18}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 1}, - })); - - codecs.emplace(std::pair(SpvOpFunctionParameter, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {899570100, 0, 0}, - {929101967, 0, 0}, - {1100599986, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3056042030, 0, 0}, - {3334207724, 0, 0}, - {3357250579, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 10, 13}, - {0, 4, 15}, - {0, 16, 11}, - {0, 17, 1}, - {0, 14, 12}, - {0, 19, 18}, - {0, 21, 20}, - {0, 22, 8}, - {0, 7, 6}, - {0, 23, 9}, - {0, 25, 24}, - {0, 26, 2}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(115, { - {0, 0, 0}, - {57149555, 0, 0}, - {86116519, 0, 0}, - {168339452, 0, 0}, - {181902171, 0, 0}, - {284226441, 0, 0}, - {314809953, 0, 0}, - {330249537, 0, 0}, - {527665290, 0, 0}, - {545363837, 0, 0}, - {707478563, 0, 0}, - {740921498, 0, 0}, - {807276090, 0, 0}, - {824323032, 0, 0}, - {835458563, 0, 0}, - {1162127370, 0, 0}, - {1245448751, 0, 0}, - {1277245109, 0, 0}, - {1375043498, 0, 0}, - {1380991098, 0, 0}, - {1603937321, 0, 0}, - {1708264968, 0, 0}, - {1717555224, 0, 0}, - {1765126703, 0, 0}, - {1838993983, 0, 0}, - {1949856502, 0, 0}, - {2108571893, 0, 0}, - {2110223508, 0, 0}, - {2293637521, 0, 0}, - {2377112119, 0, 0}, - {2378763734, 0, 0}, - {2512398201, 0, 0}, - {2516325050, 0, 0}, - {2645135839, 0, 0}, - {2708915136, 0, 0}, - {2894979602, 0, 0}, - {2903897222, 0, 0}, - {2976581453, 0, 0}, - {3054834317, 0, 0}, - {3075866530, 0, 0}, - {3085157904, 0, 0}, - {3242843022, 0, 0}, - {3266028549, 0, 0}, - {3296691317, 0, 0}, - {3299488628, 0, 0}, - {3322500634, 0, 0}, - {3345707173, 0, 0}, - {3536390697, 0, 0}, - {3584683259, 0, 0}, - {3647606635, 0, 0}, - {3760372982, 0, 0}, - {3823959661, 0, 0}, - {3839389658, 0, 0}, - {4124281183, 0, 0}, - {4130950286, 0, 0}, - {4169878842, 0, 0}, - {4174489262, 0, 0}, - {4237497041, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 23}, - {0, 37, 8}, - {0, 45, 39}, - {0, 41, 14}, - {0, 48, 43}, - {0, 40, 31}, - {0, 19, 29}, - {0, 53, 26}, - {0, 10, 5}, - {0, 50, 24}, - {0, 27, 3}, - {0, 59, 32}, - {0, 51, 18}, - {0, 52, 55}, - {0, 60, 57}, - {0, 62, 61}, - {0, 36, 33}, - {0, 64, 63}, - {0, 65, 22}, - {0, 66, 46}, - {0, 6, 67}, - {0, 68, 13}, - {0, 21, 44}, - {0, 1, 69}, - {0, 30, 11}, - {0, 71, 70}, - {0, 12, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 16, 2}, - {0, 49, 35}, - {0, 77, 9}, - {0, 42, 28}, - {0, 15, 78}, - {0, 80, 79}, - {0, 82, 81}, - {0, 47, 83}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 20, 38}, - {0, 54, 90}, - {0, 34, 91}, - {0, 93, 92}, - {0, 25, 94}, - {0, 95, 7}, - {0, 97, 96}, - {0, 56, 98}, - {0, 100, 99}, - {0, 102, 101}, - {0, 104, 103}, - {0, 4, 105}, - {0, 107, 106}, - {0, 58, 108}, - {0, 110, 109}, - {0, 112, 111}, - {0, 114, 113}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(81, { - {0, 0, 0}, - {35240468, 0, 0}, - {36096192, 0, 0}, - {123060826, 0, 0}, - {184634770, 0, 0}, - {459968607, 0, 0}, - {619875033, 0, 0}, - {950731750, 0, 0}, - {1058429216, 0, 0}, - {1182296898, 0, 0}, - {1238120570, 0, 0}, - {1271484400, 0, 0}, - {1429389803, 0, 0}, - {1717510093, 0, 0}, - {1766422419, 0, 0}, - {1775308984, 0, 0}, - {1817271123, 0, 0}, - {1917336504, 0, 0}, - {1957265068, 0, 0}, - {1998433745, 0, 0}, - {2055664760, 0, 0}, - {2303184249, 0, 0}, - {2308565678, 0, 0}, - {2451531615, 0, 0}, - {2496297824, 0, 0}, - {2507457870, 0, 0}, - {2550501832, 0, 0}, - {2590402790, 0, 0}, - {2649103430, 0, 0}, - {2831059514, 0, 0}, - {2836440943, 0, 0}, - {3269075805, 0, 0}, - {3361419439, 0, 0}, - {3457269042, 0, 0}, - {3464197236, 0, 0}, - {3472029049, 0, 0}, - {3518630848, 0, 0}, - {3587381650, 0, 0}, - {3653985133, 0, 0}, - {4185590212, 0, 0}, - {4233562270, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 40, 37}, - {0, 22, 30}, - {0, 2, 7}, - {0, 24, 11}, - {0, 16, 33}, - {0, 6, 34}, - {0, 42, 27}, - {0, 5, 43}, - {0, 4, 44}, - {0, 36, 8}, - {0, 39, 45}, - {0, 46, 1}, - {0, 3, 47}, - {0, 48, 23}, - {0, 49, 9}, - {0, 50, 35}, - {0, 52, 51}, - {0, 32, 53}, - {0, 13, 10}, - {0, 26, 14}, - {0, 19, 54}, - {0, 55, 25}, - {0, 56, 38}, - {0, 17, 57}, - {0, 59, 58}, - {0, 61, 60}, - {0, 62, 29}, - {0, 12, 15}, - {0, 18, 63}, - {0, 28, 64}, - {0, 65, 31}, - {0, 67, 66}, - {0, 20, 41}, - {0, 69, 68}, - {0, 71, 70}, - {0, 21, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(61, { - {0, 0, 0}, - {37459569, 0, 0}, - {162167595, 0, 0}, - {535067202, 0, 0}, - {701281393, 0, 0}, - {837715723, 0, 0}, - {1320550031, 0, 0}, - {1630583316, 0, 0}, - {1913735398, 0, 0}, - {1918481917, 0, 0}, - {1955871800, 0, 0}, - {1977038330, 0, 0}, - {2053214130, 0, 0}, - {2443959748, 0, 0}, - {2564745684, 0, 0}, - {2622612602, 0, 0}, - {2677252364, 0, 0}, - {2736026107, 0, 0}, - {2790624748, 0, 0}, - {2882994691, 0, 0}, - {2888125966, 0, 0}, - {2970183398, 0, 0}, - {3253403867, 0, 0}, - {3427283542, 0, 0}, - {3570411982, 0, 0}, - {3619787319, 0, 0}, - {3662767579, 0, 0}, - {3884846406, 0, 0}, - {3910458990, 0, 0}, - {3927915220, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 20}, - {0, 6, 25}, - {0, 23, 3}, - {0, 2, 4}, - {0, 14, 17}, - {0, 11, 8}, - {0, 27, 10}, - {0, 19, 28}, - {0, 12, 16}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 15}, - {0, 41, 7}, - {0, 1, 21}, - {0, 24, 13}, - {0, 29, 42}, - {0, 44, 43}, - {0, 22, 45}, - {0, 47, 46}, - {0, 49, 48}, - {0, 50, 30}, - {0, 31, 51}, - {0, 53, 52}, - {0, 55, 54}, - {0, 56, 9}, - {0, 57, 26}, - {0, 59, 58}, - {0, 60, 18}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(39, { - {0, 0, 0}, - {744062262, 0, 0}, - {810488476, 0, 0}, - {1040775722, 0, 0}, - {1280126114, 0, 0}, - {1367301635, 0, 0}, - {1684282922, 0, 0}, - {1918481917, 0, 0}, - {1978689945, 0, 0}, - {1980341560, 0, 0}, - {2443959748, 0, 0}, - {2629265310, 0, 0}, - {2790624748, 0, 0}, - {2970183398, 0, 0}, - {3044188332, 0, 0}, - {3496407048, 0, 0}, - {3662767579, 0, 0}, - {3887377256, 0, 0}, - {3971481069, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 18, 15}, - {0, 21, 6}, - {0, 13, 11}, - {0, 4, 22}, - {0, 14, 1}, - {0, 24, 23}, - {0, 25, 8}, - {0, 27, 26}, - {0, 20, 17}, - {0, 5, 28}, - {0, 29, 9}, - {0, 16, 10}, - {0, 31, 30}, - {0, 32, 7}, - {0, 19, 33}, - {0, 35, 34}, - {0, 37, 36}, - {0, 38, 12}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {37459569, 0, 0}, - {837715723, 0, 0}, - {1352628475, 0, 0}, - {1918481917, 0, 0}, - {1978689945, 0, 0}, - {1980341560, 0, 0}, - {2096388952, 0, 0}, - {2622612602, 0, 0}, - {2790624748, 0, 0}, - {2970183398, 0, 0}, - {3510682541, 0, 0}, - {3783543823, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 11}, - {0, 2, 8}, - {0, 15, 12}, - {0, 1, 3}, - {0, 16, 6}, - {0, 18, 17}, - {0, 19, 14}, - {0, 20, 5}, - {0, 10, 21}, - {0, 22, 4}, - {0, 23, 13}, - {0, 25, 24}, - {0, 9, 26}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {1510333659, 0, 0}, - {1684282922, 0, 0}, - {1918481917, 0, 0}, - {2790624748, 0, 0}, - {3662767579, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 1}, - {0, 8, 2}, - {0, 9, 7}, - {0, 3, 10}, - {0, 6, 11}, - {0, 4, 12}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {161668409, 0, 0}, - {188347929, 0, 0}, - {653708953, 0, 0}, - {976111724, 0, 0}, - {1510333659, 0, 0}, - {1918481917, 0, 0}, - {2790624748, 0, 0}, - {3033873113, 0, 0}, - {3499234137, 0, 0}, - {3525913657, 0, 0}, - {3552593177, 0, 0}, - {3570411982, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 3}, - {0, 2, 9}, - {0, 10, 11}, - {0, 15, 1}, - {0, 17, 16}, - {0, 19, 18}, - {0, 5, 4}, - {0, 20, 6}, - {0, 12, 21}, - {0, 14, 22}, - {0, 24, 23}, - {0, 7, 25}, - {0, 13, 26}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(31, { - {0, 0, 0}, - {226836633, 0, 0}, - {296981500, 0, 0}, - {718877177, 0, 0}, - {745556697, 0, 0}, - {798915737, 0, 0}, - {1510333659, 0, 0}, - {1684282922, 0, 0}, - {2444465148, 0, 0}, - {2713718873, 0, 0}, - {3495546641, 0, 0}, - {3564402361, 0, 0}, - {4056442905, 0, 0}, - {4083122425, 0, 0}, - {4123141705, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 4}, - {0, 5, 3}, - {0, 9, 8}, - {0, 13, 12}, - {0, 1, 11}, - {0, 18, 17}, - {0, 2, 19}, - {0, 21, 20}, - {0, 23, 22}, - {0, 25, 24}, - {0, 26, 7}, - {0, 27, 16}, - {0, 10, 6}, - {0, 29, 28}, - {0, 15, 30}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 8), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {161668409, 0, 0}, - {188347929, 0, 0}, - {215027449, 0, 0}, - {296981500, 0, 0}, - {653708953, 0, 0}, - {680388473, 0, 0}, - {1119069977, 0, 0}, - {1510333659, 0, 0}, - {1584774136, 0, 0}, - {2049792025, 0, 0}, - {2444465148, 0, 0}, - {2568512089, 0, 0}, - {3033873113, 0, 0}, - {3499234137, 0, 0}, - {3525913657, 0, 0}, - {3552593177, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 6}, - {0, 10, 12}, - {0, 4, 3}, - {0, 16, 11}, - {0, 19, 14}, - {0, 5, 2}, - {0, 20, 13}, - {0, 21, 15}, - {0, 1, 22}, - {0, 24, 23}, - {0, 26, 25}, - {0, 28, 27}, - {0, 18, 29}, - {0, 8, 30}, - {0, 32, 31}, - {0, 9, 33}, - {0, 17, 34}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 9), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(25, { - {0, 0, 0}, - {825595257, 0, 0}, - {1064945649, 0, 0}, - {1290956281, 0, 0}, - {1510333659, 0, 0}, - {2096388952, 0, 0}, - {2248357849, 0, 0}, - {2713718873, 0, 0}, - {3187066832, 0, 0}, - {3205759417, 0, 0}, - {4064212479, 0, 0}, - {4163160985, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 3}, - {0, 2, 9}, - {0, 7, 6}, - {0, 5, 14}, - {0, 16, 15}, - {0, 17, 11}, - {0, 19, 18}, - {0, 20, 1}, - {0, 4, 13}, - {0, 22, 21}, - {0, 10, 23}, - {0, 12, 24}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 10), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {123108003, 0, 0}, - {296981500, 0, 0}, - {595410904, 0, 0}, - {1466938734, 0, 0}, - {1503477720, 0, 0}, - {1816558243, 0, 0}, - {1990431740, 0, 0}, - {2724625059, 0, 0}, - {2790624748, 0, 0}, - {2812498065, 0, 0}, - {3160388974, 0, 0}, - {3745223676, 0, 0}, - {3982311384, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 13}, - {0, 8, 1}, - {0, 12, 11}, - {0, 15, 3}, - {0, 6, 4}, - {0, 16, 7}, - {0, 17, 14}, - {0, 18, 2}, - {0, 19, 10}, - {0, 21, 20}, - {0, 23, 22}, - {0, 25, 24}, - {0, 9, 26}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 11), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(25, { - {0, 0, 0}, - {94145952, 0, 0}, - {1054641568, 0, 0}, - {1269075360, 0, 0}, - {1675922848, 0, 0}, - {2038205856, 0, 0}, - {2433519008, 0, 0}, - {2636942752, 0, 0}, - {2790624748, 0, 0}, - {2840366496, 0, 0}, - {2851900832, 0, 0}, - {2964622752, 0, 0}, - {3654061472, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 1}, - {0, 12, 6}, - {0, 14, 10}, - {0, 13, 4}, - {0, 11, 15}, - {0, 3, 16}, - {0, 2, 17}, - {0, 18, 5}, - {0, 9, 19}, - {0, 21, 20}, - {0, 23, 22}, - {0, 8, 24}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 12), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(45, { - {0, 0, 0}, - {107544081, 0, 0}, - {125015036, 0, 0}, - {586244865, 0, 0}, - {1033081852, 0, 0}, - {1064945649, 0, 0}, - {1155765244, 0, 0}, - {1304296041, 0, 0}, - {1543646433, 0, 0}, - {1782996825, 0, 0}, - {1941148668, 0, 0}, - {2002490364, 0, 0}, - {2022347217, 0, 0}, - {2063832060, 0, 0}, - {2487708241, 0, 0}, - {2726532092, 0, 0}, - {2849215484, 0, 0}, - {2966409025, 0, 0}, - {3445109809, 0, 0}, - {3458449569, 0, 0}, - {3634598908, 0, 0}, - {3695940604, 0, 0}, - {3923810593, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 2}, - {0, 14, 13}, - {0, 1, 23}, - {0, 6, 5}, - {0, 16, 15}, - {0, 24, 17}, - {0, 12, 25}, - {0, 22, 18}, - {0, 10, 26}, - {0, 28, 27}, - {0, 21, 29}, - {0, 31, 30}, - {0, 9, 8}, - {0, 11, 32}, - {0, 33, 19}, - {0, 3, 34}, - {0, 36, 35}, - {0, 38, 37}, - {0, 20, 39}, - {0, 41, 40}, - {0, 42, 4}, - {0, 44, 43}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 13), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {247698428, 0, 0}, - {309040124, 0, 0}, - {333554713, 0, 0}, - {572905105, 0, 0}, - {1033081852, 0, 0}, - {2002490364, 0, 0}, - {2009007457, 0, 0}, - {2487708241, 0, 0}, - {3634598908, 0, 0}, - {3695940604, 0, 0}, - {3923810593, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 1}, - {0, 9, 7}, - {0, 5, 12}, - {0, 14, 13}, - {0, 15, 8}, - {0, 3, 16}, - {0, 17, 11}, - {0, 10, 4}, - {0, 2, 18}, - {0, 20, 19}, - {0, 22, 21}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 14), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {247698428, 0, 0}, - {1033081852, 0, 0}, - {2002490364, 0, 0}, - {2910557180, 0, 0}, - {3757282300, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 4}, - {0, 7, 3}, - {0, 2, 8}, - {0, 1, 5}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 15), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {1033081852, 0, 0}, - {1094423548, 0, 0}, - {2002490364, 0, 0}, - {3757282300, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 6, 2}, - {0, 4, 7}, - {0, 8, 1}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 16), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {135486769, 0, 0}, - {450406196, 0, 0}, - {503094540, 0, 0}, - {543621065, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1322549027, 0, 0}, - {1784441183, 0, 0}, - {2194691858, 0, 0}, - {2448331885, 0, 0}, - {2468230023, 0, 0}, - {2547657777, 0, 0}, - {2549309392, 0, 0}, - {2550961007, 0, 0}, - {2934934694, 0, 0}, - {2936586309, 0, 0}, - {2938237924, 0, 0}, - {3094180193, 0, 0}, - {3095831808, 0, 0}, - {3183924418, 0, 0}, - {3561562003, 0, 0}, - {3563213618, 0, 0}, - {3564865233, 0, 0}, - {4028622909, 0, 0}, - {4039938779, 0, 0}, - {4050155669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 27, 28}, - {0, 10, 2}, - {0, 25, 24}, - {0, 1, 12}, - {0, 30, 3}, - {0, 20, 31}, - {0, 9, 32}, - {0, 34, 33}, - {0, 35, 22}, - {0, 26, 15}, - {0, 19, 36}, - {0, 18, 37}, - {0, 38, 16}, - {0, 39, 8}, - {0, 5, 40}, - {0, 6, 41}, - {0, 21, 42}, - {0, 11, 29}, - {0, 4, 43}, - {0, 13, 23}, - {0, 14, 17}, - {0, 7, 44}, - {0, 46, 45}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpVariable, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {37459569, 0, 0}, - {112745085, 0, 0}, - {137840602, 0, 0}, - {565334834, 0, 0}, - {625975427, 0, 0}, - {630964591, 0, 0}, - {680016782, 0, 0}, - {769422756, 0, 0}, - {1009983433, 0, 0}, - {1093210099, 0, 0}, - {1572088444, 0, 0}, - {1584774136, 0, 0}, - {1641565587, 0, 0}, - {1918481917, 0, 0}, - {2190437442, 0, 0}, - {2790624748, 0, 0}, - {3085467405, 0, 0}, - {3181646225, 0, 0}, - {3192069648, 0, 0}, - {3253403867, 0, 0}, - {3390051757, 0, 0}, - {3560665067, 0, 0}, - {3662767579, 0, 0}, - {4053789056, 0, 0}, - {4064212479, 0, 0}, - {4192247221, 0, 0}, - {4224872590, 0, 0}, - {4290024976, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 20}, - {0, 28, 10}, - {0, 13, 8}, - {0, 15, 17}, - {0, 30, 21}, - {0, 19, 31}, - {0, 4, 32}, - {0, 34, 33}, - {0, 35, 5}, - {0, 7, 24}, - {0, 9, 36}, - {0, 3, 37}, - {0, 38, 6}, - {0, 39, 23}, - {0, 27, 40}, - {0, 14, 41}, - {0, 25, 42}, - {0, 1, 29}, - {0, 12, 43}, - {0, 11, 26}, - {0, 18, 22}, - {0, 16, 44}, - {0, 46, 45}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpVariable, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {162255877, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {1154919607, 0, 0}, - {1343794461, 0, 0}, - {1951208733, 0, 0}, - {2263349224, 0, 0}, - {2320303498, 0, 0}, - {2924146124, 0, 0}, - {2984325996, 0, 0}, - {3334207724, 0, 0}, - {3868239231, 0, 0}, - {3869890846, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 9, 7}, - {0, 12, 4}, - {0, 16, 15}, - {0, 18, 17}, - {0, 14, 19}, - {0, 13, 10}, - {0, 20, 1}, - {0, 21, 8}, - {0, 2, 22}, - {0, 11, 23}, - {0, 6, 24}, - {0, 26, 25}, - })); - - codecs.emplace(std::pair(SpvOpLoad, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {169674806, 0, 0}, - {269823086, 0, 0}, - {408465899, 0, 0}, - {451264926, 0, 0}, - {543558236, 0, 0}, - {810488476, 0, 0}, - {850497536, 0, 0}, - {870594305, 0, 0}, - {883854656, 0, 0}, - {1033363654, 0, 0}, - {1069781886, 0, 0}, - {1141965917, 0, 0}, - {1323407757, 0, 0}, - {1570165302, 0, 0}, - {1684282922, 0, 0}, - {1742737136, 0, 0}, - {1901166356, 0, 0}, - {1949759310, 0, 0}, - {2043873558, 0, 0}, - {2087004702, 0, 0}, - {2096388952, 0, 0}, - {2157103435, 0, 0}, - {2219733501, 0, 0}, - {2356768706, 0, 0}, - {2443959748, 0, 0}, - {2517964682, 0, 0}, - {2614879967, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2959147533, 0, 0}, - {2970183398, 0, 0}, - {3044188332, 0, 0}, - {3091876332, 0, 0}, - {3187066832, 0, 0}, - {3244209297, 0, 0}, - {3487022798, 0, 0}, - {3496407048, 0, 0}, - {3570411982, 0, 0}, - {3692647551, 0, 0}, - {3713290482, 0, 0}, - {3831290364, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 1}, - {0, 35, 13}, - {0, 25, 11}, - {0, 7, 10}, - {0, 19, 36}, - {0, 43, 27}, - {0, 16, 29}, - {0, 22, 3}, - {0, 41, 30}, - {0, 44, 12}, - {0, 2, 24}, - {0, 40, 32}, - {0, 23, 45}, - {0, 46, 39}, - {0, 17, 33}, - {0, 48, 47}, - {0, 8, 49}, - {0, 51, 50}, - {0, 52, 20}, - {0, 53, 14}, - {0, 31, 54}, - {0, 15, 55}, - {0, 57, 56}, - {0, 59, 58}, - {0, 6, 26}, - {0, 61, 60}, - {0, 34, 62}, - {0, 64, 63}, - {0, 5, 37}, - {0, 9, 65}, - {0, 18, 28}, - {0, 66, 38}, - {0, 68, 67}, - {0, 69, 21}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 80, 42}, - {0, 82, 81}, - })); - - codecs.emplace(std::pair(SpvOpLoad, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {28782128, 0, 0}, - {30433743, 0, 0}, - {37459569, 0, 0}, - {137840602, 0, 0}, - {522971108, 0, 0}, - {565334834, 0, 0}, - {625975427, 0, 0}, - {630964591, 0, 0}, - {680016782, 0, 0}, - {1009983433, 0, 0}, - {1079999262, 0, 0}, - {1395113939, 0, 0}, - {1572088444, 0, 0}, - {1584774136, 0, 0}, - {1649426421, 0, 0}, - {1918481917, 0, 0}, - {1957218950, 0, 0}, - {2311941439, 0, 0}, - {2313593054, 0, 0}, - {2790624748, 0, 0}, - {2838165089, 0, 0}, - {2839816704, 0, 0}, - {2841468319, 0, 0}, - {3085467405, 0, 0}, - {3181646225, 0, 0}, - {3192069648, 0, 0}, - {3253403867, 0, 0}, - {3364388739, 0, 0}, - {3366040354, 0, 0}, - {3367691969, 0, 0}, - {3369343584, 0, 0}, - {3560665067, 0, 0}, - {3662767579, 0, 0}, - {3945795573, 0, 0}, - {4053789056, 0, 0}, - {4064212479, 0, 0}, - {4224872590, 0, 0}, - {4239834800, 0, 0}, - {4241486415, 0, 0}, - {4243138030, 0, 0}, - {4244789645, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 27}, - {0, 15, 2}, - {0, 10, 26}, - {0, 7, 24}, - {0, 9, 31}, - {0, 43, 30}, - {0, 29, 12}, - {0, 11, 41}, - {0, 40, 39}, - {0, 44, 23}, - {0, 22, 6}, - {0, 34, 35}, - {0, 18, 45}, - {0, 46, 21}, - {0, 17, 19}, - {0, 48, 47}, - {0, 28, 49}, - {0, 51, 50}, - {0, 52, 38}, - {0, 53, 33}, - {0, 4, 54}, - {0, 13, 55}, - {0, 57, 56}, - {0, 59, 58}, - {0, 37, 8}, - {0, 61, 60}, - {0, 5, 62}, - {0, 64, 63}, - {0, 36, 32}, - {0, 3, 65}, - {0, 14, 16}, - {0, 66, 25}, - {0, 68, 67}, - {0, 69, 20}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 80, 42}, - {0, 82, 81}, - })); - - codecs.emplace(std::pair(SpvOpLoad, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(49, { - {0, 0, 0}, - {137840602, 0, 0}, - {522971108, 0, 0}, - {769422756, 0, 0}, - {1009983433, 0, 0}, - {1079999262, 0, 0}, - {1558345254, 0, 0}, - {1572088444, 0, 0}, - {1641565587, 0, 0}, - {1918481917, 0, 0}, - {2311941439, 0, 0}, - {2313593054, 0, 0}, - {2790624748, 0, 0}, - {2838165089, 0, 0}, - {2994529201, 0, 0}, - {2996180816, 0, 0}, - {2997832431, 0, 0}, - {3027538652, 0, 0}, - {3253403867, 0, 0}, - {3364388739, 0, 0}, - {3560665067, 0, 0}, - {3662767579, 0, 0}, - {3945795573, 0, 0}, - {4192247221, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 17}, - {0, 16, 15}, - {0, 13, 11}, - {0, 10, 3}, - {0, 22, 18}, - {0, 6, 8}, - {0, 19, 2}, - {0, 27, 26}, - {0, 28, 5}, - {0, 30, 29}, - {0, 32, 31}, - {0, 34, 33}, - {0, 4, 35}, - {0, 37, 36}, - {0, 21, 1}, - {0, 39, 38}, - {0, 40, 24}, - {0, 7, 23}, - {0, 20, 9}, - {0, 42, 41}, - {0, 43, 25}, - {0, 44, 12}, - {0, 46, 45}, - {0, 48, 47}, - })); - - codecs.emplace(std::pair(SpvOpStore, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {139011596, 0, 0}, - {177111659, 0, 0}, - {296981500, 0, 0}, - {408465899, 0, 0}, - {495107308, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {1367301635, 0, 0}, - {1901166356, 0, 0}, - {2055836767, 0, 0}, - {2087004702, 0, 0}, - {2096388952, 0, 0}, - {2204920111, 0, 0}, - {2517964682, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2842919847, 0, 0}, - {2855506940, 0, 0}, - {2959147533, 0, 0}, - {3044188332, 0, 0}, - {3187066832, 0, 0}, - {3504158761, 0, 0}, - {3570411982, 0, 0}, - {3619787319, 0, 0}, - {3653838348, 0, 0}, - {3692647551, 0, 0}, - {3764205609, 0, 0}, - {3831290364, 0, 0}, - {3913885196, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 20, 29}, - {0, 25, 8}, - {0, 5, 1}, - {0, 24, 26}, - {0, 14, 9}, - {0, 27, 16}, - {0, 31, 7}, - {0, 33, 32}, - {0, 17, 34}, - {0, 35, 13}, - {0, 22, 6}, - {0, 3, 2}, - {0, 23, 36}, - {0, 28, 37}, - {0, 19, 4}, - {0, 38, 10}, - {0, 39, 15}, - {0, 40, 18}, - {0, 42, 41}, - {0, 43, 12}, - {0, 44, 21}, - {0, 45, 11}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 30, 58}, - })); - - codecs.emplace(std::pair(SpvOpStore, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {440421571, 0, 0}, - {827698488, 0, 0}, - {907126242, 0, 0}, - {908777857, 0, 0}, - {910429472, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {2080953106, 0, 0}, - {2468230023, 0, 0}, - {2547657777, 0, 0}, - {2549309392, 0, 0}, - {2550961007, 0, 0}, - {3094857332, 0, 0}, - {3561562003, 0, 0}, - {3563213618, 0, 0}, - {3564865233, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 16, 12}, - {0, 17, 13}, - {0, 14, 19}, - {0, 18, 20}, - {0, 5, 21}, - {0, 11, 7}, - {0, 15, 22}, - {0, 9, 8}, - {0, 24, 23}, - {0, 25, 4}, - {0, 27, 26}, - {0, 28, 3}, - {0, 29, 10}, - {0, 6, 1}, - {0, 31, 30}, - {0, 32, 2}, - {0, 34, 33}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(99, { - {0, 0, 0}, - {27130513, 0, 0}, - {28782128, 0, 0}, - {30433743, 0, 0}, - {32085358, 0, 0}, - {155458798, 0, 0}, - {157110413, 0, 0}, - {163402553, 0, 0}, - {165054168, 0, 0}, - {213642219, 0, 0}, - {215293834, 0, 0}, - {216945449, 0, 0}, - {221900294, 0, 0}, - {545986953, 0, 0}, - {979993429, 0, 0}, - {1079999262, 0, 0}, - {1302400505, 0, 0}, - {1313182965, 0, 0}, - {1314834580, 0, 0}, - {1315613425, 0, 0}, - {1317265040, 0, 0}, - {1558345254, 0, 0}, - {1649426421, 0, 0}, - {2311941439, 0, 0}, - {2313593054, 0, 0}, - {2602027658, 0, 0}, - {2838165089, 0, 0}, - {2839816704, 0, 0}, - {2841468319, 0, 0}, - {2863084840, 0, 0}, - {2994529201, 0, 0}, - {2996180816, 0, 0}, - {2997832431, 0, 0}, - {3027538652, 0, 0}, - {3187387500, 0, 0}, - {3189039115, 0, 0}, - {3364388739, 0, 0}, - {3366040354, 0, 0}, - {3367691969, 0, 0}, - {3369343584, 0, 0}, - {3716914380, 0, 0}, - {3928842969, 0, 0}, - {3930494584, 0, 0}, - {3932146199, 0, 0}, - {3945482286, 0, 0}, - {4105051793, 0, 0}, - {4239834800, 0, 0}, - {4241486415, 0, 0}, - {4243138030, 0, 0}, - {4244789645, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 29, 10}, - {0, 17, 18}, - {0, 13, 14}, - {0, 44, 25}, - {0, 8, 7}, - {0, 20, 11}, - {0, 33, 19}, - {0, 6, 45}, - {0, 42, 43}, - {0, 40, 5}, - {0, 9, 16}, - {0, 1, 4}, - {0, 35, 34}, - {0, 12, 21}, - {0, 52, 51}, - {0, 31, 30}, - {0, 41, 32}, - {0, 54, 53}, - {0, 55, 2}, - {0, 3, 56}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 22}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 39, 68}, - {0, 38, 69}, - {0, 47, 70}, - {0, 49, 71}, - {0, 28, 48}, - {0, 37, 15}, - {0, 73, 72}, - {0, 74, 27}, - {0, 23, 75}, - {0, 76, 26}, - {0, 24, 77}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 46}, - {0, 36, 83}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 50, 98}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(101, { - {0, 0, 0}, - {112745085, 0, 0}, - {116376005, 0, 0}, - {137840602, 0, 0}, - {400248103, 0, 0}, - {406044930, 0, 0}, - {468372467, 0, 0}, - {522971108, 0, 0}, - {615341051, 0, 0}, - {625975427, 0, 0}, - {630964591, 0, 0}, - {680016782, 0, 0}, - {763027711, 0, 0}, - {977312655, 0, 0}, - {1009983433, 0, 0}, - {1062250709, 0, 0}, - {1395113939, 0, 0}, - {1410849099, 0, 0}, - {1642805350, 0, 0}, - {1692932387, 0, 0}, - {1698730948, 0, 0}, - {1827244161, 0, 0}, - {1918481917, 0, 0}, - {2096472894, 0, 0}, - {2190437442, 0, 0}, - {2299842241, 0, 0}, - {2433358586, 0, 0}, - {2593325766, 0, 0}, - {2785441472, 0, 0}, - {2790624748, 0, 0}, - {2879917723, 0, 0}, - {2882994691, 0, 0}, - {2902069960, 0, 0}, - {3090408469, 0, 0}, - {3181646225, 0, 0}, - {3255947500, 0, 0}, - {3263901372, 0, 0}, - {3268751013, 0, 0}, - {3347863687, 0, 0}, - {3390051757, 0, 0}, - {3560665067, 0, 0}, - {3617689692, 0, 0}, - {3662767579, 0, 0}, - {3717523241, 0, 0}, - {3854557817, 0, 0}, - {3910458990, 0, 0}, - {3941049054, 0, 0}, - {3945795573, 0, 0}, - {4080527786, 0, 0}, - {4101009465, 0, 0}, - {4290024976, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 32, 44}, - {0, 41, 26}, - {0, 16, 10}, - {0, 27, 45}, - {0, 25, 38}, - {0, 12, 18}, - {0, 6, 35}, - {0, 46, 23}, - {0, 20, 37}, - {0, 52, 19}, - {0, 53, 21}, - {0, 54, 48}, - {0, 33, 55}, - {0, 3, 8}, - {0, 28, 56}, - {0, 13, 57}, - {0, 59, 58}, - {0, 1, 49}, - {0, 47, 60}, - {0, 61, 14}, - {0, 63, 62}, - {0, 64, 43}, - {0, 7, 4}, - {0, 65, 15}, - {0, 67, 66}, - {0, 68, 17}, - {0, 36, 2}, - {0, 30, 69}, - {0, 71, 70}, - {0, 34, 5}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 24, 78}, - {0, 39, 31}, - {0, 80, 79}, - {0, 9, 11}, - {0, 42, 81}, - {0, 83, 82}, - {0, 29, 50}, - {0, 84, 51}, - {0, 86, 85}, - {0, 22, 40}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 100, 99}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(69, { - {0, 0, 0}, - {51041423, 0, 0}, - {142465290, 0, 0}, - {144116905, 0, 0}, - {290391815, 0, 0}, - {438318340, 0, 0}, - {529742207, 0, 0}, - {677668732, 0, 0}, - {917019124, 0, 0}, - {1064945649, 0, 0}, - {1156369516, 0, 0}, - {1158021131, 0, 0}, - {1304296041, 0, 0}, - {1452222566, 0, 0}, - {1543646433, 0, 0}, - {1691572958, 0, 0}, - {1782996825, 0, 0}, - {1784648440, 0, 0}, - {1930923350, 0, 0}, - {2170273742, 0, 0}, - {2318200267, 0, 0}, - {2466126792, 0, 0}, - {2557550659, 0, 0}, - {2705477184, 0, 0}, - {2796901051, 0, 0}, - {2798552666, 0, 0}, - {2944827576, 0, 0}, - {3092754101, 0, 0}, - {3184177968, 0, 0}, - {3332104493, 0, 0}, - {3571454885, 0, 0}, - {3810805277, 0, 0}, - {3958731802, 0, 0}, - {4106658327, 0, 0}, - {4198082194, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 27, 33}, - {0, 21, 5}, - {0, 26, 13}, - {0, 20, 8}, - {0, 15, 7}, - {0, 37, 36}, - {0, 32, 29}, - {0, 38, 4}, - {0, 30, 1}, - {0, 9, 12}, - {0, 39, 18}, - {0, 22, 40}, - {0, 42, 41}, - {0, 44, 43}, - {0, 45, 35}, - {0, 46, 34}, - {0, 6, 14}, - {0, 28, 23}, - {0, 48, 47}, - {0, 49, 31}, - {0, 51, 50}, - {0, 19, 24}, - {0, 52, 10}, - {0, 2, 53}, - {0, 55, 54}, - {0, 25, 56}, - {0, 11, 57}, - {0, 59, 58}, - {0, 3, 17}, - {0, 61, 60}, - {0, 16, 62}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(85, { - {0, 0, 0}, - {142465290, 0, 0}, - {144116905, 0, 0}, - {198967948, 0, 0}, - {290391815, 0, 0}, - {529742207, 0, 0}, - {586244865, 0, 0}, - {677668732, 0, 0}, - {825595257, 0, 0}, - {917019124, 0, 0}, - {973521782, 0, 0}, - {1064945649, 0, 0}, - {1156369516, 0, 0}, - {1158021131, 0, 0}, - {1212872174, 0, 0}, - {1304296041, 0, 0}, - {1452222566, 0, 0}, - {1543646433, 0, 0}, - {1600149091, 0, 0}, - {1782996825, 0, 0}, - {1784648440, 0, 0}, - {1839499483, 0, 0}, - {1930923350, 0, 0}, - {2170273742, 0, 0}, - {2226776400, 0, 0}, - {2318200267, 0, 0}, - {2466126792, 0, 0}, - {2557550659, 0, 0}, - {2614053317, 0, 0}, - {2796901051, 0, 0}, - {2798552666, 0, 0}, - {2853403709, 0, 0}, - {2944827576, 0, 0}, - {3184177968, 0, 0}, - {3240680626, 0, 0}, - {3480031018, 0, 0}, - {3571454885, 0, 0}, - {3810805277, 0, 0}, - {3867307935, 0, 0}, - {3958731802, 0, 0}, - {4106658327, 0, 0}, - {4198082194, 0, 0}, - {4254584852, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 11}, - {0, 15, 4}, - {0, 32, 25}, - {0, 44, 39}, - {0, 36, 22}, - {0, 45, 17}, - {0, 24, 46}, - {0, 10, 9}, - {0, 6, 27}, - {0, 28, 18}, - {0, 42, 34}, - {0, 31, 14}, - {0, 41, 38}, - {0, 26, 3}, - {0, 47, 33}, - {0, 21, 8}, - {0, 5, 35}, - {0, 40, 16}, - {0, 37, 23}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 68, 12}, - {0, 29, 69}, - {0, 70, 1}, - {0, 30, 2}, - {0, 43, 71}, - {0, 73, 72}, - {0, 74, 20}, - {0, 75, 19}, - {0, 77, 76}, - {0, 13, 78}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {144116905, 0, 0}, - {1158021131, 0, 0}, - {1784648440, 0, 0}, - {2798552666, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 4, 2}, - {0, 6, 3}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {142465290, 0, 0}, - {1782996825, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - {0, 4, 3}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 6, 1}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {177111659, 0, 0}, - {413918748, 0, 0}, - {529383565, 0, 0}, - {646282397, 0, 0}, - {837715723, 0, 0}, - {1019457583, 0, 0}, - {1022544883, 0, 0}, - {1054461787, 0, 0}, - {1097775533, 0, 0}, - {1136775085, 0, 0}, - {1191015885, 0, 0}, - {1196280518, 0, 0}, - {1203545131, 0, 0}, - {1352628475, 0, 0}, - {1367301635, 0, 0}, - {1918742169, 0, 0}, - {1922045399, 0, 0}, - {2055836767, 0, 0}, - {2183547611, 0, 0}, - {2204920111, 0, 0}, - {2358141757, 0, 0}, - {2572638469, 0, 0}, - {2597020383, 0, 0}, - {2842919847, 0, 0}, - {3619787319, 0, 0}, - {3701632935, 0, 0}, - {3783543823, 0, 0}, - {4245257809, 0, 0}, - {4265894873, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 23}, - {0, 12, 2}, - {0, 9, 7}, - {0, 21, 19}, - {0, 4, 29}, - {0, 10, 28}, - {0, 17, 16}, - {0, 27, 3}, - {0, 32, 31}, - {0, 33, 22}, - {0, 6, 34}, - {0, 35, 8}, - {0, 36, 24}, - {0, 38, 37}, - {0, 1, 14}, - {0, 39, 20}, - {0, 5, 40}, - {0, 42, 41}, - {0, 43, 26}, - {0, 45, 44}, - {0, 47, 46}, - {0, 48, 18}, - {0, 15, 49}, - {0, 50, 25}, - {0, 51, 13}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 30, 58}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {236660303, 0, 0}, - {342159236, 0, 0}, - {371428004, 0, 0}, - {373079619, 0, 0}, - {488500848, 0, 0}, - {495107308, 0, 0}, - {864295921, 0, 0}, - {1071164424, 0, 0}, - {1136911283, 0, 0}, - {1178317551, 0, 0}, - {1510422521, 0, 0}, - {1570165302, 0, 0}, - {1822823090, 0, 0}, - {1858116930, 0, 0}, - {1977038330, 0, 0}, - {2096388952, 0, 0}, - {2157103435, 0, 0}, - {2231688008, 0, 0}, - {2604576561, 0, 0}, - {2622612602, 0, 0}, - {2771938750, 0, 0}, - {2777172031, 0, 0}, - {2996594997, 0, 0}, - {3187066832, 0, 0}, - {3496407048, 0, 0}, - {3570411982, 0, 0}, - {3609540589, 0, 0}, - {3713290482, 0, 0}, - {3797761273, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 18, 8}, - {0, 27, 9}, - {0, 21, 10}, - {0, 14, 24}, - {0, 12, 19}, - {0, 11, 15}, - {0, 23, 2}, - {0, 7, 13}, - {0, 31, 22}, - {0, 32, 4}, - {0, 33, 29}, - {0, 34, 1}, - {0, 35, 3}, - {0, 37, 36}, - {0, 38, 28}, - {0, 39, 5}, - {0, 41, 40}, - {0, 42, 17}, - {0, 16, 43}, - {0, 45, 44}, - {0, 46, 6}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 25, 53}, - {0, 54, 20}, - {0, 55, 26}, - {0, 57, 56}, - {0, 30, 58}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(47, { - {0, 0, 0}, - {236660303, 0, 0}, - {342159236, 0, 0}, - {488500848, 0, 0}, - {495107308, 0, 0}, - {864295921, 0, 0}, - {1178317551, 0, 0}, - {1510422521, 0, 0}, - {1570165302, 0, 0}, - {1858116930, 0, 0}, - {1977038330, 0, 0}, - {2096388952, 0, 0}, - {2157103435, 0, 0}, - {2231688008, 0, 0}, - {2604576561, 0, 0}, - {2622612602, 0, 0}, - {2771938750, 0, 0}, - {2777172031, 0, 0}, - {2996594997, 0, 0}, - {3496407048, 0, 0}, - {3570411982, 0, 0}, - {3609540589, 0, 0}, - {3713290482, 0, 0}, - {3797761273, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 21, 13}, - {0, 16, 6}, - {0, 14, 9}, - {0, 7, 10}, - {0, 18, 2}, - {0, 17, 5}, - {0, 25, 8}, - {0, 22, 12}, - {0, 26, 23}, - {0, 27, 1}, - {0, 28, 3}, - {0, 30, 29}, - {0, 32, 31}, - {0, 34, 33}, - {0, 35, 11}, - {0, 36, 4}, - {0, 38, 37}, - {0, 40, 39}, - {0, 41, 15}, - {0, 42, 19}, - {0, 20, 43}, - {0, 45, 44}, - {0, 24, 46}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {679771963, 0, 0}, - {1146476634, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 9, 6}, - {0, 8, 7}, - {0, 11, 10}, - {0, 4, 12}, - {0, 5, 13}, - {0, 14, 1}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(79, { - {0, 0, 0}, - {107497541, 0, 0}, - {289648234, 0, 0}, - {348584153, 0, 0}, - {369686787, 0, 0}, - {429277936, 0, 0}, - {449954059, 0, 0}, - {508217552, 0, 0}, - {742917749, 0, 0}, - {1032593647, 0, 0}, - {1158929937, 0, 0}, - {1209418480, 0, 0}, - {1319785741, 0, 0}, - {1321616112, 0, 0}, - {1417363940, 0, 0}, - {1541020250, 0, 0}, - {1564342316, 0, 0}, - {1578775276, 0, 0}, - {1631434666, 0, 0}, - {1636389511, 0, 0}, - {2012838864, 0, 0}, - {2262137600, 0, 0}, - {2281956980, 0, 0}, - {2359973133, 0, 0}, - {2464905186, 0, 0}, - {2613179511, 0, 0}, - {2621255555, 0, 0}, - {2817335337, 0, 0}, - {2881302403, 0, 0}, - {3063300848, 0, 0}, - {3151638847, 0, 0}, - {3233393284, 0, 0}, - {3323682385, 0, 0}, - {3337532056, 0, 0}, - {3456899824, 0, 0}, - {3547456240, 0, 0}, - {3675926744, 0, 0}, - {3753486980, 0, 0}, - {3931641900, 0, 0}, - {3970432934, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 1}, - {0, 6, 4}, - {0, 8, 19}, - {0, 39, 24}, - {0, 3, 2}, - {0, 34, 14}, - {0, 10, 9}, - {0, 18, 38}, - {0, 32, 15}, - {0, 27, 16}, - {0, 28, 35}, - {0, 13, 26}, - {0, 20, 23}, - {0, 21, 11}, - {0, 36, 33}, - {0, 5, 22}, - {0, 42, 41}, - {0, 43, 29}, - {0, 45, 44}, - {0, 7, 46}, - {0, 48, 47}, - {0, 30, 31}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 55, 17}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 62, 12}, - {0, 64, 63}, - {0, 66, 65}, - {0, 67, 37}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 40, 78}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {153013225, 0, 0}, - {296836635, 0, 0}, - {296981500, 0, 0}, - {778500192, 0, 0}, - {810488476, 0, 0}, - {848380423, 0, 0}, - {900522183, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1141965917, 0, 0}, - {1287304304, 0, 0}, - {1323407757, 0, 0}, - {1417363940, 0, 0}, - {1471851763, 0, 0}, - {1526654696, 0, 0}, - {1654776395, 0, 0}, - {1684282922, 0, 0}, - {1739837626, 0, 0}, - {1791352211, 0, 0}, - {2195550588, 0, 0}, - {2319227476, 0, 0}, - {2491124112, 0, 0}, - {2789375411, 0, 0}, - {2807448986, 0, 0}, - {2817579280, 0, 0}, - {2835131395, 0, 0}, - {2847102741, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {3079287749, 0, 0}, - {3091876332, 0, 0}, - {3168953855, 0, 0}, - {3374978006, 0, 0}, - {3399062057, 0, 0}, - {3510257966, 0, 0}, - {3554463148, 0, 0}, - {3579593979, 0, 0}, - {3757851979, 0, 0}, - {3759503594, 0, 0}, - {3761155209, 0, 0}, - {3762806824, 0, 0}, - {3902853271, 0, 0}, - {4140081844, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 38, 42}, - {0, 14, 23}, - {0, 26, 18}, - {0, 39, 35}, - {0, 6, 40}, - {0, 16, 13}, - {0, 33, 34}, - {0, 12, 4}, - {0, 27, 41}, - {0, 25, 21}, - {0, 24, 1}, - {0, 37, 19}, - {0, 32, 22}, - {0, 2, 8}, - {0, 20, 17}, - {0, 43, 36}, - {0, 29, 15}, - {0, 46, 45}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 7, 55}, - {0, 56, 30}, - {0, 57, 5}, - {0, 59, 58}, - {0, 60, 11}, - {0, 9, 61}, - {0, 63, 62}, - {0, 65, 64}, - {0, 66, 31}, - {0, 68, 67}, - {0, 10, 69}, - {0, 71, 70}, - {0, 28, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 79, 3}, - {0, 81, 80}, - {0, 83, 82}, - {0, 85, 84}, - {0, 44, 86}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(81, { - {0, 0, 0}, - {14244860, 0, 0}, - {150820676, 0, 0}, - {153013225, 0, 0}, - {269823086, 0, 0}, - {289648234, 0, 0}, - {296981500, 0, 0}, - {678695941, 0, 0}, - {810488476, 0, 0}, - {850592577, 0, 0}, - {870594305, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1206571206, 0, 0}, - {1287304304, 0, 0}, - {1323407757, 0, 0}, - {1471851763, 0, 0}, - {1526654696, 0, 0}, - {1684282922, 0, 0}, - {1734446471, 0, 0}, - {1758530522, 0, 0}, - {2117320444, 0, 0}, - {2118972059, 0, 0}, - {2120623674, 0, 0}, - {2122275289, 0, 0}, - {2219733501, 0, 0}, - {2262321736, 0, 0}, - {2807448986, 0, 0}, - {2817579280, 0, 0}, - {2835131395, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {2951272396, 0, 0}, - {3079287749, 0, 0}, - {3168953855, 0, 0}, - {3502816184, 0, 0}, - {3510257966, 0, 0}, - {3554463148, 0, 0}, - {3997952447, 0, 0}, - {4140081844, 0, 0}, - {4182141402, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 21, 26}, - {0, 29, 16}, - {0, 22, 36}, - {0, 1, 23}, - {0, 20, 5}, - {0, 19, 35}, - {0, 10, 38}, - {0, 13, 24}, - {0, 28, 7}, - {0, 27, 3}, - {0, 40, 2}, - {0, 34, 9}, - {0, 32, 11}, - {0, 33, 18}, - {0, 39, 37}, - {0, 31, 17}, - {0, 43, 42}, - {0, 45, 44}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 8, 52}, - {0, 15, 53}, - {0, 55, 54}, - {0, 56, 14}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 25}, - {0, 63, 62}, - {0, 4, 64}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 71, 12}, - {0, 6, 72}, - {0, 30, 73}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 41, 80}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(111, { - {0, 0, 0}, - {34183582, 0, 0}, - {93914936, 0, 0}, - {94303122, 0, 0}, - {117998987, 0, 0}, - {153013225, 0, 0}, - {296981500, 0, 0}, - {451264926, 0, 0}, - {473485679, 0, 0}, - {476788909, 0, 0}, - {478440524, 0, 0}, - {480092139, 0, 0}, - {481743754, 0, 0}, - {810488476, 0, 0}, - {871966503, 0, 0}, - {910398460, 0, 0}, - {918189168, 0, 0}, - {933769938, 0, 0}, - {959681532, 0, 0}, - {1149665466, 0, 0}, - {1166917451, 0, 0}, - {1227221002, 0, 0}, - {1310740861, 0, 0}, - {1323407757, 0, 0}, - {1341516288, 0, 0}, - {1373166395, 0, 0}, - {1445161581, 0, 0}, - {1461645203, 0, 0}, - {1471851763, 0, 0}, - {1526654696, 0, 0}, - {1561718045, 0, 0}, - {1593584949, 0, 0}, - {1684282922, 0, 0}, - {1800404122, 0, 0}, - {1862284649, 0, 0}, - {2213411495, 0, 0}, - {2668680621, 0, 0}, - {2805256437, 0, 0}, - {2807448986, 0, 0}, - {2835131395, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {3000904950, 0, 0}, - {3107413701, 0, 0}, - {3168953855, 0, 0}, - {3333131702, 0, 0}, - {3365041621, 0, 0}, - {3456899824, 0, 0}, - {3505028338, 0, 0}, - {3510257966, 0, 0}, - {3554463148, 0, 0}, - {3606320646, 0, 0}, - {3692647551, 0, 0}, - {3861006967, 0, 0}, - {4126287524, 0, 0}, - {4140081844, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 33}, - {0, 35, 25}, - {0, 27, 17}, - {0, 8, 20}, - {0, 3, 54}, - {0, 1, 19}, - {0, 10, 46}, - {0, 11, 9}, - {0, 39, 28}, - {0, 53, 49}, - {0, 12, 2}, - {0, 34, 4}, - {0, 47, 36}, - {0, 23, 45}, - {0, 5, 37}, - {0, 24, 38}, - {0, 43, 26}, - {0, 48, 51}, - {0, 44, 32}, - {0, 15, 16}, - {0, 57, 22}, - {0, 55, 50}, - {0, 29, 58}, - {0, 60, 59}, - {0, 41, 61}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 13, 70}, - {0, 71, 7}, - {0, 42, 31}, - {0, 73, 72}, - {0, 75, 74}, - {0, 21, 30}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 18}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 52, 91}, - {0, 6, 92}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 99, 40}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 56, 110}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(155, { - {0, 0, 0}, - {18776483, 0, 0}, - {37009196, 0, 0}, - {277023757, 0, 0}, - {296981500, 0, 0}, - {348988933, 0, 0}, - {451264926, 0, 0}, - {564884461, 0, 0}, - {804899022, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {876864198, 0, 0}, - {900522183, 0, 0}, - {928261291, 0, 0}, - {959681532, 0, 0}, - {1164724902, 0, 0}, - {1323407757, 0, 0}, - {1332774287, 0, 0}, - {1404739463, 0, 0}, - {1447712361, 0, 0}, - {1450415100, 0, 0}, - {1513770932, 0, 0}, - {1620634991, 0, 0}, - {1692600167, 0, 0}, - {1860649552, 0, 0}, - {1932614728, 0, 0}, - {2087004702, 0, 0}, - {2148510256, 0, 0}, - {2220475432, 0, 0}, - {2388524817, 0, 0}, - {2460489993, 0, 0}, - {2676385521, 0, 0}, - {2748350697, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {2916400082, 0, 0}, - {2988365258, 0, 0}, - {3061856840, 0, 0}, - {3063508455, 0, 0}, - {3065160070, 0, 0}, - {3066811685, 0, 0}, - {3068463300, 0, 0}, - {3070114915, 0, 0}, - {3071766530, 0, 0}, - {3073418145, 0, 0}, - {3075069760, 0, 0}, - {3076721375, 0, 0}, - {3078372990, 0, 0}, - {3080024605, 0, 0}, - {3081676220, 0, 0}, - {3083327835, 0, 0}, - {3084979450, 0, 0}, - {3086631065, 0, 0}, - {3088282680, 0, 0}, - {3114708520, 0, 0}, - {3116360135, 0, 0}, - {3118011750, 0, 0}, - {3119663365, 0, 0}, - {3121314980, 0, 0}, - {3124618210, 0, 0}, - {3126269825, 0, 0}, - {3127921440, 0, 0}, - {3129573055, 0, 0}, - {3131224670, 0, 0}, - {3132876285, 0, 0}, - {3134527900, 0, 0}, - {3136179515, 0, 0}, - {3204260786, 0, 0}, - {3264086791, 0, 0}, - {3276225962, 0, 0}, - {3444275347, 0, 0}, - {3516240523, 0, 0}, - {3588205699, 0, 0}, - {3732136051, 0, 0}, - {3804101227, 0, 0}, - {3874089391, 0, 0}, - {4044115788, 0, 0}, - {4116080964, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 45, 43}, - {0, 3, 46}, - {0, 71, 36}, - {0, 44, 34}, - {0, 76, 54}, - {0, 73, 55}, - {0, 57, 67}, - {0, 51, 56}, - {0, 31, 27}, - {0, 38, 37}, - {0, 40, 39}, - {0, 42, 41}, - {0, 49, 47}, - {0, 35, 50}, - {0, 21, 70}, - {0, 19, 5}, - {0, 8, 58}, - {0, 17, 11}, - {0, 24, 18}, - {0, 30, 29}, - {0, 52, 9}, - {0, 77, 22}, - {0, 62, 48}, - {0, 25, 53}, - {0, 20, 59}, - {0, 26, 60}, - {0, 72, 6}, - {0, 79, 69}, - {0, 80, 7}, - {0, 81, 2}, - {0, 12, 13}, - {0, 82, 68}, - {0, 65, 61}, - {0, 74, 63}, - {0, 23, 83}, - {0, 64, 10}, - {0, 84, 32}, - {0, 66, 28}, - {0, 15, 85}, - {0, 86, 16}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 1, 93}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 100, 75}, - {0, 102, 101}, - {0, 104, 103}, - {0, 106, 105}, - {0, 107, 14}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 131, 130}, - {0, 133, 132}, - {0, 135, 134}, - {0, 137, 136}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 33, 148}, - {0, 4, 149}, - {0, 78, 150}, - {0, 152, 151}, - {0, 154, 153}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 2}, - {0, 4, 7}, - {0, 1, 8}, - {0, 9, 5}, - {0, 3, 10}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(49, { - {0, 0, 0}, - {126463145, 0, 0}, - {171307615, 0, 0}, - {342159236, 0, 0}, - {354479447, 0, 0}, - {593829839, 0, 0}, - {743407979, 0, 0}, - {898191441, 0, 0}, - {900522183, 0, 0}, - {1265796414, 0, 0}, - {1287304304, 0, 0}, - {1356063462, 0, 0}, - {1368383673, 0, 0}, - {1526654696, 0, 0}, - {1766994680, 0, 0}, - {1793544760, 0, 0}, - {1811839150, 0, 0}, - {2234361374, 0, 0}, - {2279700640, 0, 0}, - {2383939514, 0, 0}, - {2780898906, 0, 0}, - {2996594997, 0, 0}, - {3413713311, 0, 0}, - {3554463148, 0, 0}, - {3635542517, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 15}, - {0, 20, 14}, - {0, 7, 18}, - {0, 6, 1}, - {0, 12, 10}, - {0, 23, 19}, - {0, 13, 5}, - {0, 24, 17}, - {0, 21, 3}, - {0, 22, 16}, - {0, 26, 2}, - {0, 27, 8}, - {0, 4, 28}, - {0, 29, 9}, - {0, 31, 30}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 45, 44}, - {0, 47, 46}, - {0, 25, 48}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(153, { - {0, 0, 0}, - {13107491, 0, 0}, - {257136089, 0, 0}, - {293528591, 0, 0}, - {321459212, 0, 0}, - {425022309, 0, 0}, - {490769168, 0, 0}, - {495107308, 0, 0}, - {517919178, 0, 0}, - {617312262, 0, 0}, - {708736129, 0, 0}, - {753756604, 0, 0}, - {765238787, 0, 0}, - {796985462, 0, 0}, - {819503463, 0, 0}, - {850497536, 0, 0}, - {948086521, 0, 0}, - {1004589179, 0, 0}, - {1120149824, 0, 0}, - {1165671422, 0, 0}, - {1203545131, 0, 0}, - {1297165140, 0, 0}, - {1335363438, 0, 0}, - {1351676723, 0, 0}, - {1391866096, 0, 0}, - {1584369690, 0, 0}, - {1631216488, 0, 0}, - {1691646294, 0, 0}, - {1779143013, 0, 0}, - {1858116930, 0, 0}, - {1890300748, 0, 0}, - {1915438939, 0, 0}, - {1918742169, 0, 0}, - {1922045399, 0, 0}, - {1961990747, 0, 0}, - {2037710159, 0, 0}, - {2037814253, 0, 0}, - {2043873558, 0, 0}, - {2096388952, 0, 0}, - {2169307971, 0, 0}, - {2257843797, 0, 0}, - {2262220987, 0, 0}, - {2338272340, 0, 0}, - {2405770322, 0, 0}, - {2498042266, 0, 0}, - {2563789125, 0, 0}, - {2588618056, 0, 0}, - {2645120714, 0, 0}, - {2864863800, 0, 0}, - {2909957084, 0, 0}, - {2975894973, 0, 0}, - {3041450802, 0, 0}, - {3151638847, 0, 0}, - {3187066832, 0, 0}, - {3244716568, 0, 0}, - {3271748023, 0, 0}, - {3304438238, 0, 0}, - {3312467582, 0, 0}, - {3325419312, 0, 0}, - {3370185097, 0, 0}, - {3419674548, 0, 0}, - {3435931956, 0, 0}, - {3504158761, 0, 0}, - {3602522282, 0, 0}, - {3653059026, 0, 0}, - {3716353056, 0, 0}, - {3782099915, 0, 0}, - {3838648480, 0, 0}, - {3847846774, 0, 0}, - {3913593633, 0, 0}, - {3989799199, 0, 0}, - {3997038726, 0, 0}, - {4046301857, 0, 0}, - {4092654294, 0, 0}, - {4176581069, 0, 0}, - {4242327928, 0, 0}, - {4285652249, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 74, 38}, - {0, 12, 56}, - {0, 28, 24}, - {0, 60, 43}, - {0, 65, 72}, - {0, 18, 2}, - {0, 52, 3}, - {0, 19, 10}, - {0, 49, 36}, - {0, 67, 66}, - {0, 41, 17}, - {0, 53, 11}, - {0, 29, 68}, - {0, 26, 55}, - {0, 70, 76}, - {0, 73, 47}, - {0, 51, 22}, - {0, 39, 21}, - {0, 5, 9}, - {0, 40, 48}, - {0, 59, 44}, - {0, 6, 69}, - {0, 32, 31}, - {0, 4, 33}, - {0, 13, 54}, - {0, 14, 50}, - {0, 35, 75}, - {0, 58, 23}, - {0, 16, 34}, - {0, 27, 63}, - {0, 45, 61}, - {0, 20, 46}, - {0, 71, 1}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 84, 8}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 64, 99}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 106, 62}, - {0, 108, 107}, - {0, 110, 109}, - {0, 7, 111}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 30, 124}, - {0, 126, 125}, - {0, 128, 127}, - {0, 130, 129}, - {0, 132, 131}, - {0, 134, 133}, - {0, 135, 25}, - {0, 57, 136}, - {0, 138, 137}, - {0, 42, 139}, - {0, 37, 140}, - {0, 142, 141}, - {0, 143, 15}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 151, 150}, - {0, 152, 77}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(47, { - {0, 0, 0}, - {545678922, 0, 0}, - {630592085, 0, 0}, - {679771963, 0, 0}, - {899570100, 0, 0}, - {906176560, 0, 0}, - {929101967, 0, 0}, - {1100599986, 0, 0}, - {1103903216, 0, 0}, - {1107206446, 0, 0}, - {1369578001, 0, 0}, - {1372881231, 0, 0}, - {2320303498, 0, 0}, - {2926633629, 0, 0}, - {3249265647, 0, 0}, - {3334207724, 0, 0}, - {3486057732, 0, 0}, - {3674863070, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {3822983876, 0, 0}, - {4141567741, 0, 0}, - {4292991777, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 9, 17}, - {0, 20, 11}, - {0, 25, 5}, - {0, 2, 14}, - {0, 23, 13}, - {0, 16, 26}, - {0, 27, 24}, - {0, 28, 8}, - {0, 29, 18}, - {0, 22, 30}, - {0, 6, 31}, - {0, 21, 32}, - {0, 3, 33}, - {0, 35, 34}, - {0, 1, 12}, - {0, 10, 36}, - {0, 37, 19}, - {0, 4, 15}, - {0, 39, 38}, - {0, 7, 40}, - {0, 42, 41}, - {0, 44, 43}, - {0, 46, 45}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(103, { - {0, 0, 0}, - {125792961, 0, 0}, - {132755933, 0, 0}, - {156014509, 0, 0}, - {436066778, 0, 0}, - {463084678, 0, 0}, - {531559080, 0, 0}, - {565233904, 0, 0}, - {578132535, 0, 0}, - {600906020, 0, 0}, - {602222721, 0, 0}, - {694743357, 0, 0}, - {760554870, 0, 0}, - {996663016, 0, 0}, - {1022309772, 0, 0}, - {1351676723, 0, 0}, - {1496901698, 0, 0}, - {1502470404, 0, 0}, - {1522901980, 0, 0}, - {1548254487, 0, 0}, - {1637661947, 0, 0}, - {1788504755, 0, 0}, - {2092468906, 0, 0}, - {2094647776, 0, 0}, - {2127660080, 0, 0}, - {2213946343, 0, 0}, - {2225172640, 0, 0}, - {2259467579, 0, 0}, - {2263866576, 0, 0}, - {2600961503, 0, 0}, - {2727022058, 0, 0}, - {2752967311, 0, 0}, - {2864705739, 0, 0}, - {3021406120, 0, 0}, - {3044723416, 0, 0}, - {3052439312, 0, 0}, - {3136865519, 0, 0}, - {3297860332, 0, 0}, - {3352361837, 0, 0}, - {3670298840, 0, 0}, - {3712946115, 0, 0}, - {3732709413, 0, 0}, - {3764662384, 0, 0}, - {3788324110, 0, 0}, - {3928555688, 0, 0}, - {4083347580, 0, 0}, - {4098876453, 0, 0}, - {4147239510, 0, 0}, - {4199470013, 0, 0}, - {4211577142, 0, 0}, - {4218799564, 0, 0}, - {4290374884, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 2}, - {0, 9, 8}, - {0, 17, 10}, - {0, 20, 18}, - {0, 22, 21}, - {0, 26, 23}, - {0, 31, 29}, - {0, 35, 34}, - {0, 45, 36}, - {0, 5, 3}, - {0, 12, 6}, - {0, 15, 14}, - {0, 25, 19}, - {0, 28, 27}, - {0, 38, 33}, - {0, 43, 39}, - {0, 47, 46}, - {0, 50, 49}, - {0, 7, 51}, - {0, 1, 48}, - {0, 37, 24}, - {0, 44, 42}, - {0, 13, 11}, - {0, 41, 40}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 30, 16}, - {0, 73, 32}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 52, 102}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(93, { - {0, 0, 0}, - {17185761, 0, 0}, - {117250846, 0, 0}, - {296981500, 0, 0}, - {330388453, 0, 0}, - {346929928, 0, 0}, - {533021259, 0, 0}, - {564302770, 0, 0}, - {680157484, 0, 0}, - {721450866, 0, 0}, - {798549062, 0, 0}, - {853200279, 0, 0}, - {864295921, 0, 0}, - {900522183, 0, 0}, - {973908139, 0, 0}, - {983243705, 0, 0}, - {1033363654, 0, 0}, - {1037370721, 0, 0}, - {1464587427, 0, 0}, - {1670691893, 0, 0}, - {1686512349, 0, 0}, - {1849065716, 0, 0}, - {1917602962, 0, 0}, - {1965902997, 0, 0}, - {2121980967, 0, 0}, - {2311072371, 0, 0}, - {2339901602, 0, 0}, - {2517964682, 0, 0}, - {2542834724, 0, 0}, - {2558655180, 0, 0}, - {2736881867, 0, 0}, - {2855506940, 0, 0}, - {2888753905, 0, 0}, - {2950446516, 0, 0}, - {3044188332, 0, 0}, - {3079287749, 0, 0}, - {3153451899, 0, 0}, - {3214537066, 0, 0}, - {3234673086, 0, 0}, - {3349230696, 0, 0}, - {3504158761, 0, 0}, - {3570411982, 0, 0}, - {3652695478, 0, 0}, - {3764205609, 0, 0}, - {3940720663, 0, 0}, - {4180570743, 0, 0}, - {4221373527, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 24, 18}, - {0, 4, 2}, - {0, 15, 14}, - {0, 21, 20}, - {0, 29, 26}, - {0, 42, 36}, - {0, 7, 45}, - {0, 37, 9}, - {0, 8, 5}, - {0, 32, 11}, - {0, 39, 38}, - {0, 12, 10}, - {0, 28, 19}, - {0, 1, 46}, - {0, 17, 6}, - {0, 30, 23}, - {0, 44, 33}, - {0, 35, 13}, - {0, 16, 48}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 55, 40}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 25, 22}, - {0, 63, 62}, - {0, 3, 64}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 34, 71}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 27, 43}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 84, 31}, - {0, 86, 85}, - {0, 41, 87}, - {0, 89, 88}, - {0, 91, 90}, - {0, 47, 92}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(115, { - {0, 0, 0}, - {132755933, 0, 0}, - {156014509, 0, 0}, - {255227811, 0, 0}, - {371186900, 0, 0}, - {371428004, 0, 0}, - {374731234, 0, 0}, - {531559080, 0, 0}, - {565233904, 0, 0}, - {578132535, 0, 0}, - {591140762, 0, 0}, - {600906020, 0, 0}, - {602222721, 0, 0}, - {656610661, 0, 0}, - {760554870, 0, 0}, - {996663016, 0, 0}, - {1022309772, 0, 0}, - {1496901698, 0, 0}, - {1502470404, 0, 0}, - {1522901980, 0, 0}, - {1536350567, 0, 0}, - {1543280290, 0, 0}, - {1548254487, 0, 0}, - {1788504755, 0, 0}, - {2064733527, 0, 0}, - {2092468906, 0, 0}, - {2094647776, 0, 0}, - {2162986400, 0, 0}, - {2225172640, 0, 0}, - {2259467579, 0, 0}, - {2263866576, 0, 0}, - {2360004627, 0, 0}, - {2507709226, 0, 0}, - {2600961503, 0, 0}, - {2727022058, 0, 0}, - {2752967311, 0, 0}, - {2864705739, 0, 0}, - {3021406120, 0, 0}, - {3052439312, 0, 0}, - {3136865519, 0, 0}, - {3297860332, 0, 0}, - {3352361837, 0, 0}, - {3598957382, 0, 0}, - {3619787319, 0, 0}, - {3655201337, 0, 0}, - {3670298840, 0, 0}, - {3774892253, 0, 0}, - {3788324110, 0, 0}, - {3808408202, 0, 0}, - {3951925872, 0, 0}, - {3952316364, 0, 0}, - {4098876453, 0, 0}, - {4147239510, 0, 0}, - {4199470013, 0, 0}, - {4211577142, 0, 0}, - {4217306348, 0, 0}, - {4218799564, 0, 0}, - {4290374884, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 43}, - {0, 4, 1}, - {0, 11, 9}, - {0, 13, 12}, - {0, 19, 18}, - {0, 25, 23}, - {0, 28, 26}, - {0, 35, 33}, - {0, 39, 38}, - {0, 2, 49}, - {0, 7, 3}, - {0, 16, 14}, - {0, 29, 22}, - {0, 37, 30}, - {0, 45, 41}, - {0, 51, 47}, - {0, 54, 52}, - {0, 57, 56}, - {0, 53, 8}, - {0, 32, 10}, - {0, 42, 40}, - {0, 24, 46}, - {0, 15, 50}, - {0, 55, 20}, - {0, 59, 44}, - {0, 61, 60}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 31, 17}, - {0, 36, 34}, - {0, 79, 78}, - {0, 81, 80}, - {0, 27, 82}, - {0, 5, 21}, - {0, 48, 83}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 58, 114}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {3866587616, 0, 0}, - {3868239231, 0, 0}, - {3869890846, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {1164218401, 0, 0}, - {2036361232, 0, 0}, - {2637132451, 0, 0}, - {3237903670, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 1, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {543558236, 0, 0}, - {1069781886, 0, 0}, - {1596005536, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1949759310, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {236660303, 0, 0}, - {347505241, 0, 0}, - {426360862, 0, 0}, - {439998433, 0, 0}, - {488500848, 0, 0}, - {495107308, 0, 0}, - {868652905, 0, 0}, - {1191735827, 0, 0}, - {1265998516, 0, 0}, - {1309728002, 0, 0}, - {1365842164, 0, 0}, - {1396344138, 0, 0}, - {1508074873, 0, 0}, - {1553476262, 0, 0}, - {1642818143, 0, 0}, - {1851510470, 0, 0}, - {1858116930, 0, 0}, - {1863199739, 0, 0}, - {1979978194, 0, 0}, - {1986584654, 0, 0}, - {2092100514, 0, 0}, - {2098706974, 0, 0}, - {2231688008, 0, 0}, - {2232491275, 0, 0}, - {2329992200, 0, 0}, - {2637935122, 0, 0}, - {2693892518, 0, 0}, - {2759250216, 0, 0}, - {2839765116, 0, 0}, - {2855895374, 0, 0}, - {2913136690, 0, 0}, - {3012980338, 0, 0}, - {3327770644, 0, 0}, - {3362344229, 0, 0}, - {3398925952, 0, 0}, - {3448018532, 0, 0}, - {3457985288, 0, 0}, - {3566035349, 0, 0}, - {3657635382, 0, 0}, - {3702405475, 0, 0}, - {3757479030, 0, 0}, - {3797204453, 0, 0}, - {4291477370, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 32, 28}, - {0, 9, 35}, - {0, 31, 11}, - {0, 10, 30}, - {0, 25, 21}, - {0, 40, 2}, - {0, 15, 19}, - {0, 24, 36}, - {0, 42, 4}, - {0, 18, 16}, - {0, 29, 26}, - {0, 43, 7}, - {0, 45, 8}, - {0, 37, 13}, - {0, 47, 46}, - {0, 48, 33}, - {0, 49, 14}, - {0, 3, 22}, - {0, 50, 12}, - {0, 41, 39}, - {0, 51, 34}, - {0, 52, 20}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 23}, - {0, 63, 62}, - {0, 65, 64}, - {0, 27, 66}, - {0, 67, 38}, - {0, 68, 17}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 5, 77}, - {0, 78, 1}, - {0, 80, 79}, - {0, 82, 81}, - {0, 83, 6}, - {0, 85, 84}, - {0, 44, 86}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {883854656, 0, 0}, - {1962971231, 0, 0}, - {2036361232, 0, 0}, - {2356768706, 0, 0}, - {2637132451, 0, 0}, - {3237903670, 0, 0}, - {3829682756, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 2}, - {0, 6, 9}, - {0, 10, 7}, - {0, 4, 5}, - {0, 12, 11}, - {0, 3, 13}, - {0, 14, 1}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {150685616, 0, 0}, - {255302575, 0, 0}, - {414620710, 0, 0}, - {557400685, 0, 0}, - {575205902, 0, 0}, - {618761615, 0, 0}, - {646282397, 0, 0}, - {686024761, 0, 0}, - {740921498, 0, 0}, - {921246433, 0, 0}, - {1057578789, 0, 0}, - {1162127370, 0, 0}, - {1329499601, 0, 0}, - {1352628475, 0, 0}, - {1502028603, 0, 0}, - {1519723107, 0, 0}, - {1543798545, 0, 0}, - {1545450160, 0, 0}, - {1570165302, 0, 0}, - {1600392975, 0, 0}, - {1641415225, 0, 0}, - {2204920111, 0, 0}, - {2257971049, 0, 0}, - {2276405827, 0, 0}, - {2339018837, 0, 0}, - {2340670452, 0, 0}, - {2517964682, 0, 0}, - {2532518896, 0, 0}, - {2674090849, 0, 0}, - {2754074729, 0, 0}, - {2804281092, 0, 0}, - {2816338013, 0, 0}, - {2841008029, 0, 0}, - {3234673086, 0, 0}, - {3249261197, 0, 0}, - {3619787319, 0, 0}, - {3627739127, 0, 0}, - {3669223677, 0, 0}, - {3787567939, 0, 0}, - {3898287302, 0, 0}, - {4142016703, 0, 0}, - {4237092412, 0, 0}, - {4285779501, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 16, 15}, - {0, 2, 33}, - {0, 41, 35}, - {0, 32, 30}, - {0, 39, 38}, - {0, 5, 1}, - {0, 9, 43}, - {0, 40, 22}, - {0, 29, 12}, - {0, 4, 3}, - {0, 25, 37}, - {0, 34, 26}, - {0, 45, 19}, - {0, 31, 24}, - {0, 47, 46}, - {0, 48, 20}, - {0, 49, 6}, - {0, 8, 21}, - {0, 50, 11}, - {0, 13, 10}, - {0, 51, 42}, - {0, 52, 23}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 28}, - {0, 63, 62}, - {0, 65, 64}, - {0, 17, 66}, - {0, 67, 18}, - {0, 68, 7}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 14, 77}, - {0, 78, 27}, - {0, 80, 79}, - {0, 82, 81}, - {0, 83, 36}, - {0, 85, 84}, - {0, 44, 86}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {2855506940, 0, 0}, - {3266548732, 0, 0}, - {3732640764, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - {0, 5, 4}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(139, { - {0, 0, 0}, - {27177503, 0, 0}, - {30663912, 0, 0}, - {151672195, 0, 0}, - {162608772, 0, 0}, - {180913835, 0, 0}, - {371621315, 0, 0}, - {414444763, 0, 0}, - {421602934, 0, 0}, - {443347828, 0, 0}, - {458937500, 0, 0}, - {587888644, 0, 0}, - {601656217, 0, 0}, - {665789406, 0, 0}, - {712168842, 0, 0}, - {730943059, 0, 0}, - {750870327, 0, 0}, - {875212982, 0, 0}, - {899320334, 0, 0}, - {973908139, 0, 0}, - {989813600, 0, 0}, - {1057606514, 0, 0}, - {1171541710, 0, 0}, - {1243764146, 0, 0}, - {1310404265, 0, 0}, - {1366337101, 0, 0}, - {1443547269, 0, 0}, - {1472185378, 0, 0}, - {1473799048, 0, 0}, - {1543935193, 0, 0}, - {1572834111, 0, 0}, - {1623013158, 0, 0}, - {1686512349, 0, 0}, - {1705716306, 0, 0}, - {1747355813, 0, 0}, - {1755165354, 0, 0}, - {1781864804, 0, 0}, - {1916983087, 0, 0}, - {1941403425, 0, 0}, - {2023008475, 0, 0}, - {2043684541, 0, 0}, - {2274226560, 0, 0}, - {2285438321, 0, 0}, - {2315690100, 0, 0}, - {2344328209, 0, 0}, - {2414725163, 0, 0}, - {2493146691, 0, 0}, - {2495155989, 0, 0}, - {2558655180, 0, 0}, - {2577859137, 0, 0}, - {2857814560, 0, 0}, - {2895151306, 0, 0}, - {2986830770, 0, 0}, - {3006548167, 0, 0}, - {3127329373, 0, 0}, - {3157581152, 0, 0}, - {3216471040, 0, 0}, - {3296722158, 0, 0}, - {3367298820, 0, 0}, - {3376009661, 0, 0}, - {3450001968, 0, 0}, - {3526837441, 0, 0}, - {3609540589, 0, 0}, - {3743398113, 0, 0}, - {3858973601, 0, 0}, - {3953984401, 0, 0}, - {3999472204, 0, 0}, - {4088613871, 0, 0}, - {4184019303, 0, 0}, - {4258229445, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 31, 16}, - {0, 58, 47}, - {0, 21, 61}, - {0, 6, 14}, - {0, 65, 23}, - {0, 35, 5}, - {0, 2, 7}, - {0, 10, 25}, - {0, 40, 22}, - {0, 9, 50}, - {0, 20, 11}, - {0, 38, 36}, - {0, 13, 12}, - {0, 67, 28}, - {0, 71, 68}, - {0, 73, 72}, - {0, 3, 29}, - {0, 27, 8}, - {0, 44, 37}, - {0, 74, 63}, - {0, 76, 75}, - {0, 18, 1}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 26, 15}, - {0, 83, 43}, - {0, 85, 84}, - {0, 19, 86}, - {0, 48, 32}, - {0, 33, 46}, - {0, 87, 49}, - {0, 89, 88}, - {0, 91, 90}, - {0, 41, 30}, - {0, 52, 42}, - {0, 64, 55}, - {0, 92, 53}, - {0, 94, 93}, - {0, 51, 39}, - {0, 45, 95}, - {0, 66, 54}, - {0, 97, 96}, - {0, 57, 98}, - {0, 99, 69}, - {0, 101, 100}, - {0, 56, 102}, - {0, 4, 59}, - {0, 34, 17}, - {0, 103, 24}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 60, 110}, - {0, 111, 62}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 70, 130}, - {0, 132, 131}, - {0, 134, 133}, - {0, 136, 135}, - {0, 138, 137}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {883854656, 0, 0}, - {1962971231, 0, 0}, - {2036361232, 0, 0}, - {2366506734, 0, 0}, - {3829682756, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 2}, - {0, 6, 7}, - {0, 8, 5}, - {0, 3, 9}, - {0, 1, 10}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(73, { - {0, 0, 0}, - {178571546, 0, 0}, - {223310468, 0, 0}, - {388034151, 0, 0}, - {449954059, 0, 0}, - {694743357, 0, 0}, - {797415788, 0, 0}, - {835638766, 0, 0}, - {1002144380, 0, 0}, - {1221183390, 0, 0}, - {1570165302, 0, 0}, - {1663234329, 0, 0}, - {1750829822, 0, 0}, - {1894133125, 0, 0}, - {1967643923, 0, 0}, - {1980341560, 0, 0}, - {2278706468, 0, 0}, - {2326990117, 0, 0}, - {2464905186, 0, 0}, - {2511346984, 0, 0}, - {2517964682, 0, 0}, - {2616085763, 0, 0}, - {2710583246, 0, 0}, - {2745872368, 0, 0}, - {2924263085, 0, 0}, - {3027500544, 0, 0}, - {3044723416, 0, 0}, - {3202324433, 0, 0}, - {3289213933, 0, 0}, - {3323682385, 0, 0}, - {3366848728, 0, 0}, - {3417583519, 0, 0}, - {3732916270, 0, 0}, - {3787909072, 0, 0}, - {3877813395, 0, 0}, - {4028028350, 0, 0}, - {4178218543, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 36, 31}, - {0, 15, 3}, - {0, 17, 1}, - {0, 24, 12}, - {0, 35, 34}, - {0, 28, 27}, - {0, 21, 38}, - {0, 6, 13}, - {0, 14, 7}, - {0, 39, 25}, - {0, 40, 30}, - {0, 42, 41}, - {0, 32, 43}, - {0, 23, 9}, - {0, 11, 44}, - {0, 45, 22}, - {0, 47, 46}, - {0, 2, 16}, - {0, 49, 48}, - {0, 4, 50}, - {0, 51, 18}, - {0, 53, 52}, - {0, 33, 54}, - {0, 26, 55}, - {0, 57, 56}, - {0, 5, 58}, - {0, 59, 8}, - {0, 19, 60}, - {0, 10, 61}, - {0, 29, 62}, - {0, 37, 63}, - {0, 65, 64}, - {0, 67, 66}, - {0, 20, 68}, - {0, 70, 69}, - {0, 72, 71}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2855506940, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {3533637837, 0, 0}, - {3535289452, 0, 0}, - {3536941067, 0, 0}, - {3538592682, 0, 0}, - {3540244297, 0, 0}, - {3541895912, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 7}, - {0, 2, 8}, - {0, 9, 3}, - {0, 4, 10}, - {0, 5, 11}, - {0, 12, 6}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 2, 6}, - {0, 1, 3}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(45, { - {0, 0, 0}, - {328661377, 0, 0}, - {464259778, 0, 0}, - {920941800, 0, 0}, - {969500141, 0, 0}, - {1449907751, 0, 0}, - {1451831482, 0, 0}, - {1543798545, 0, 0}, - {1545450160, 0, 0}, - {1626224034, 0, 0}, - {1669930486, 0, 0}, - {1770165905, 0, 0}, - {2278571792, 0, 0}, - {2432827426, 0, 0}, - {2656211099, 0, 0}, - {2736844435, 0, 0}, - {2870852215, 0, 0}, - {2919626325, 0, 0}, - {2923708820, 0, 0}, - {3325419312, 0, 0}, - {3678875745, 0, 0}, - {4182141402, 0, 0}, - {4241374559, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 9, 13}, - {0, 5, 15}, - {0, 4, 11}, - {0, 20, 22}, - {0, 10, 1}, - {0, 18, 14}, - {0, 16, 3}, - {0, 12, 21}, - {0, 8, 7}, - {0, 24, 17}, - {0, 19, 25}, - {0, 27, 26}, - {0, 29, 28}, - {0, 31, 30}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 23, 44}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(89, { - {0, 0, 0}, - {135920445, 0, 0}, - {176166202, 0, 0}, - {294390719, 0, 0}, - {296981500, 0, 0}, - {743407979, 0, 0}, - {810488476, 0, 0}, - {837715723, 0, 0}, - {885020215, 0, 0}, - {922996215, 0, 0}, - {959681532, 0, 0}, - {963902061, 0, 0}, - {1136775085, 0, 0}, - {1189681639, 0, 0}, - {1203545131, 0, 0}, - {1297294717, 0, 0}, - {1317058015, 0, 0}, - {1352397672, 0, 0}, - {1367301635, 0, 0}, - {1412908157, 0, 0}, - {1570165302, 0, 0}, - {1763758554, 0, 0}, - {1791427568, 0, 0}, - {1992893964, 0, 0}, - {2013867381, 0, 0}, - {2096388952, 0, 0}, - {2219733501, 0, 0}, - {2383939514, 0, 0}, - {2517964682, 0, 0}, - {2555315060, 0, 0}, - {2572638469, 0, 0}, - {2762094724, 0, 0}, - {2770161927, 0, 0}, - {2855506940, 0, 0}, - {3044188332, 0, 0}, - {3187066832, 0, 0}, - {3319278167, 0, 0}, - {3653838348, 0, 0}, - {3675926744, 0, 0}, - {3701632935, 0, 0}, - {3712946115, 0, 0}, - {3732709413, 0, 0}, - {3743748793, 0, 0}, - {3783543823, 0, 0}, - {3930727258, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 15, 12}, - {0, 38, 16}, - {0, 41, 40}, - {0, 1, 33}, - {0, 21, 34}, - {0, 9, 2}, - {0, 24, 7}, - {0, 39, 44}, - {0, 29, 22}, - {0, 17, 19}, - {0, 36, 32}, - {0, 26, 18}, - {0, 30, 3}, - {0, 11, 8}, - {0, 42, 35}, - {0, 46, 31}, - {0, 27, 5}, - {0, 48, 47}, - {0, 28, 49}, - {0, 51, 50}, - {0, 52, 23}, - {0, 54, 53}, - {0, 13, 14}, - {0, 6, 55}, - {0, 57, 56}, - {0, 59, 58}, - {0, 60, 43}, - {0, 62, 61}, - {0, 37, 63}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 70, 4}, - {0, 10, 71}, - {0, 72, 20}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - {0, 81, 25}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 45, 88}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(103, { - {0, 0, 0}, - {126463145, 0, 0}, - {220008971, 0, 0}, - {246375791, 0, 0}, - {503145996, 0, 0}, - {628331516, 0, 0}, - {643418617, 0, 0}, - {743407979, 0, 0}, - {837715723, 0, 0}, - {858902117, 0, 0}, - {870594305, 0, 0}, - {939671928, 0, 0}, - {959681532, 0, 0}, - {1051471757, 0, 0}, - {1092948665, 0, 0}, - {1097775533, 0, 0}, - {1136775085, 0, 0}, - {1140367371, 0, 0}, - {1332643570, 0, 0}, - {1367301635, 0, 0}, - {1558001705, 0, 0}, - {1684282922, 0, 0}, - {2096388952, 0, 0}, - {2183547611, 0, 0}, - {2219733501, 0, 0}, - {2358141757, 0, 0}, - {2359973133, 0, 0}, - {2383939514, 0, 0}, - {2444465148, 0, 0}, - {2517964682, 0, 0}, - {2567901801, 0, 0}, - {2598189097, 0, 0}, - {2655147757, 0, 0}, - {2683080096, 0, 0}, - {2705434194, 0, 0}, - {2738307068, 0, 0}, - {2780898906, 0, 0}, - {3030911670, 0, 0}, - {3032677281, 0, 0}, - {3063300848, 0, 0}, - {3277199633, 0, 0}, - {3289969989, 0, 0}, - {3401762422, 0, 0}, - {3436143898, 0, 0}, - {3560552546, 0, 0}, - {3656163446, 0, 0}, - {3675926744, 0, 0}, - {3701632935, 0, 0}, - {3743748793, 0, 0}, - {3752211294, 0, 0}, - {3794803132, 0, 0}, - {4241374559, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 21}, - {0, 17, 11}, - {0, 36, 35}, - {0, 46, 45}, - {0, 50, 49}, - {0, 9, 3}, - {0, 20, 47}, - {0, 37, 31}, - {0, 2, 34}, - {0, 40, 13}, - {0, 51, 32}, - {0, 41, 10}, - {0, 38, 19}, - {0, 18, 44}, - {0, 43, 16}, - {0, 48, 24}, - {0, 26, 5}, - {0, 53, 8}, - {0, 15, 7}, - {0, 25, 23}, - {0, 54, 27}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 39, 42}, - {0, 62, 61}, - {0, 30, 63}, - {0, 4, 64}, - {0, 65, 28}, - {0, 66, 22}, - {0, 68, 67}, - {0, 69, 14}, - {0, 70, 33}, - {0, 71, 6}, - {0, 73, 72}, - {0, 75, 74}, - {0, 29, 76}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 91, 12}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 52, 102}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 1, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(159, { - {0, 0, 0}, - {50385656, 0, 0}, - {117250846, 0, 0}, - {171494987, 0, 0}, - {195244192, 0, 0}, - {210754155, 0, 0}, - {265392489, 0, 0}, - {333855951, 0, 0}, - {416853049, 0, 0}, - {529068443, 0, 0}, - {533021259, 0, 0}, - {615982737, 0, 0}, - {660038281, 0, 0}, - {663341511, 0, 0}, - {669812542, 0, 0}, - {716890919, 0, 0}, - {1081536219, 0, 0}, - {1119744229, 0, 0}, - {1123617794, 0, 0}, - {1139547465, 0, 0}, - {1162789888, 0, 0}, - {1178317551, 0, 0}, - {1190147516, 0, 0}, - {1193734351, 0, 0}, - {1215030156, 0, 0}, - {1220749418, 0, 0}, - {1318479490, 0, 0}, - {1461398554, 0, 0}, - {1486207619, 0, 0}, - {1551372768, 0, 0}, - {1763758554, 0, 0}, - {1797960910, 0, 0}, - {1850331254, 0, 0}, - {1894417995, 0, 0}, - {1964254745, 0, 0}, - {1965902997, 0, 0}, - {1989327599, 0, 0}, - {2095027856, 0, 0}, - {2123683379, 0, 0}, - {2124837447, 0, 0}, - {2137526937, 0, 0}, - {2269114589, 0, 0}, - {2269130237, 0, 0}, - {2330636993, 0, 0}, - {2481746922, 0, 0}, - {2503770904, 0, 0}, - {2589449658, 0, 0}, - {2603020391, 0, 0}, - {2604576561, 0, 0}, - {2795773560, 0, 0}, - {2835131395, 0, 0}, - {2852854788, 0, 0}, - {2890638791, 0, 0}, - {2895413148, 0, 0}, - {2950446516, 0, 0}, - {2963744582, 0, 0}, - {3079287749, 0, 0}, - {3088785099, 0, 0}, - {3280064277, 0, 0}, - {3335250889, 0, 0}, - {3510242586, 0, 0}, - {3517169445, 0, 0}, - {3518703473, 0, 0}, - {3536471583, 0, 0}, - {3579593979, 0, 0}, - {3591222197, 0, 0}, - {3673811979, 0, 0}, - {3727034815, 0, 0}, - {3730093054, 0, 0}, - {3898287302, 0, 0}, - {3944781937, 0, 0}, - {3950980241, 0, 0}, - {4033586023, 0, 0}, - {4041974454, 0, 0}, - {4052965752, 0, 0}, - {4083161638, 0, 0}, - {4167600590, 0, 0}, - {4185661467, 0, 0}, - {4237092412, 0, 0}, - {4244540017, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 44, 18}, - {0, 69, 57}, - {0, 24, 16}, - {0, 79, 5}, - {0, 59, 4}, - {0, 76, 40}, - {0, 53, 45}, - {0, 14, 2}, - {0, 62, 61}, - {0, 33, 75}, - {0, 38, 37}, - {0, 42, 58}, - {0, 66, 47}, - {0, 63, 67}, - {0, 1, 7}, - {0, 10, 3}, - {0, 13, 12}, - {0, 23, 22}, - {0, 32, 28}, - {0, 36, 35}, - {0, 72, 49}, - {0, 74, 73}, - {0, 77, 55}, - {0, 27, 41}, - {0, 31, 15}, - {0, 6, 54}, - {0, 78, 17}, - {0, 81, 56}, - {0, 83, 82}, - {0, 85, 84}, - {0, 48, 30}, - {0, 71, 60}, - {0, 65, 51}, - {0, 87, 86}, - {0, 50, 34}, - {0, 89, 88}, - {0, 90, 9}, - {0, 25, 8}, - {0, 92, 91}, - {0, 93, 26}, - {0, 95, 94}, - {0, 52, 39}, - {0, 29, 20}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 64, 102}, - {0, 104, 103}, - {0, 106, 105}, - {0, 21, 107}, - {0, 108, 68}, - {0, 109, 46}, - {0, 110, 11}, - {0, 112, 111}, - {0, 114, 113}, - {0, 116, 115}, - {0, 117, 70}, - {0, 43, 118}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 126, 125}, - {0, 128, 127}, - {0, 129, 19}, - {0, 131, 130}, - {0, 133, 132}, - {0, 135, 134}, - {0, 137, 136}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 151, 150}, - {0, 153, 152}, - {0, 155, 154}, - {0, 157, 156}, - {0, 158, 80}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(103, { - {0, 0, 0}, - {50998433, 0, 0}, - {171494987, 0, 0}, - {249378857, 0, 0}, - {296981500, 0, 0}, - {508007510, 0, 0}, - {610429940, 0, 0}, - {660038281, 0, 0}, - {663341511, 0, 0}, - {836581417, 0, 0}, - {1027242654, 0, 0}, - {1167160774, 0, 0}, - {1191015885, 0, 0}, - {1200870684, 0, 0}, - {1203545131, 0, 0}, - {1265796414, 0, 0}, - {1319785741, 0, 0}, - {1669959736, 0, 0}, - {1684282922, 0, 0}, - {1752686878, 0, 0}, - {1850331254, 0, 0}, - {1901166356, 0, 0}, - {1906988301, 0, 0}, - {2055836767, 0, 0}, - {2095027856, 0, 0}, - {2096388952, 0, 0}, - {2144962711, 0, 0}, - {2217833278, 0, 0}, - {2500819054, 0, 0}, - {2525173102, 0, 0}, - {2575525651, 0, 0}, - {2660843182, 0, 0}, - {2855506940, 0, 0}, - {2918750759, 0, 0}, - {2919787747, 0, 0}, - {3091876332, 0, 0}, - {3187066832, 0, 0}, - {3244209297, 0, 0}, - {3423702268, 0, 0}, - {3508792859, 0, 0}, - {3548535223, 0, 0}, - {3619787319, 0, 0}, - {3653838348, 0, 0}, - {3692647551, 0, 0}, - {3713290482, 0, 0}, - {3753486980, 0, 0}, - {3783756895, 0, 0}, - {3797961332, 0, 0}, - {3836822275, 0, 0}, - {4043078107, 0, 0}, - {4052965752, 0, 0}, - {4091394002, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 31, 49}, - {0, 24, 19}, - {0, 46, 45}, - {0, 6, 48}, - {0, 12, 33}, - {0, 17, 21}, - {0, 43, 11}, - {0, 7, 2}, - {0, 9, 8}, - {0, 28, 13}, - {0, 44, 38}, - {0, 30, 50}, - {0, 26, 22}, - {0, 29, 51}, - {0, 34, 37}, - {0, 53, 40}, - {0, 23, 54}, - {0, 55, 25}, - {0, 27, 18}, - {0, 1, 10}, - {0, 57, 56}, - {0, 59, 58}, - {0, 5, 47}, - {0, 60, 20}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - {0, 67, 39}, - {0, 69, 68}, - {0, 16, 70}, - {0, 3, 71}, - {0, 73, 72}, - {0, 41, 15}, - {0, 35, 74}, - {0, 76, 75}, - {0, 78, 77}, - {0, 36, 79}, - {0, 81, 80}, - {0, 83, 82}, - {0, 14, 84}, - {0, 86, 85}, - {0, 88, 87}, - {0, 32, 89}, - {0, 42, 90}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 52, 99}, - {0, 100, 4}, - {0, 102, 101}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(157, { - {0, 0, 0}, - {49456560, 0, 0}, - {170690025, 0, 0}, - {243178923, 0, 0}, - {295017943, 0, 0}, - {296981500, 0, 0}, - {330249537, 0, 0}, - {435256475, 0, 0}, - {443558693, 0, 0}, - {456043370, 0, 0}, - {470277359, 0, 0}, - {592180731, 0, 0}, - {663258455, 0, 0}, - {706238670, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {877895868, 0, 0}, - {900522183, 0, 0}, - {1077859090, 0, 0}, - {1082941229, 0, 0}, - {1104362365, 0, 0}, - {1132589448, 0, 0}, - {1173092699, 0, 0}, - {1203545131, 0, 0}, - {1265796414, 0, 0}, - {1278818058, 0, 0}, - {1285705317, 0, 0}, - {1319785741, 0, 0}, - {1382106590, 0, 0}, - {1461897718, 0, 0}, - {1474506522, 0, 0}, - {1530183840, 0, 0}, - {1558001705, 0, 0}, - {1558990974, 0, 0}, - {1616846013, 0, 0}, - {1633850097, 0, 0}, - {1684282922, 0, 0}, - {1725011064, 0, 0}, - {1767704813, 0, 0}, - {1923453688, 0, 0}, - {1941148668, 0, 0}, - {1955104493, 0, 0}, - {2022961611, 0, 0}, - {2162274327, 0, 0}, - {2212501241, 0, 0}, - {2219733501, 0, 0}, - {2234361374, 0, 0}, - {2272221101, 0, 0}, - {2305269460, 0, 0}, - {2488410748, 0, 0}, - {2566666743, 0, 0}, - {2598189097, 0, 0}, - {2775815164, 0, 0}, - {2793529873, 0, 0}, - {2844616706, 0, 0}, - {2970183398, 0, 0}, - {3103302036, 0, 0}, - {3110479131, 0, 0}, - {3115038057, 0, 0}, - {3116932970, 0, 0}, - {3152745753, 0, 0}, - {3187066832, 0, 0}, - {3244209297, 0, 0}, - {3383007207, 0, 0}, - {3392887901, 0, 0}, - {3508792859, 0, 0}, - {3737376990, 0, 0}, - {3753486980, 0, 0}, - {3765247327, 0, 0}, - {3817149113, 0, 0}, - {3839047923, 0, 0}, - {3886529747, 0, 0}, - {4044928561, 0, 0}, - {4061558677, 0, 0}, - {4069720347, 0, 0}, - {4069810315, 0, 0}, - {4128942283, 0, 0}, - {4164704452, 0, 0}, - {4273793488, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 74, 47}, - {0, 34, 33}, - {0, 36, 14}, - {0, 61, 48}, - {0, 13, 31}, - {0, 39, 25}, - {0, 37, 29}, - {0, 65, 54}, - {0, 4, 73}, - {0, 38, 10}, - {0, 15, 43}, - {0, 6, 35}, - {0, 9, 16}, - {0, 30, 19}, - {0, 49, 44}, - {0, 57, 53}, - {0, 60, 58}, - {0, 72, 66}, - {0, 59, 76}, - {0, 1, 68}, - {0, 70, 42}, - {0, 63, 3}, - {0, 28, 69}, - {0, 17, 55}, - {0, 45, 64}, - {0, 81, 80}, - {0, 7, 82}, - {0, 12, 11}, - {0, 21, 50}, - {0, 83, 18}, - {0, 22, 84}, - {0, 85, 26}, - {0, 20, 86}, - {0, 87, 40}, - {0, 56, 88}, - {0, 90, 89}, - {0, 92, 91}, - {0, 93, 2}, - {0, 95, 94}, - {0, 97, 96}, - {0, 98, 41}, - {0, 100, 99}, - {0, 101, 52}, - {0, 103, 102}, - {0, 77, 71}, - {0, 104, 78}, - {0, 105, 46}, - {0, 32, 8}, - {0, 106, 51}, - {0, 108, 107}, - {0, 23, 109}, - {0, 110, 27}, - {0, 112, 111}, - {0, 113, 75}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 124, 62}, - {0, 126, 125}, - {0, 128, 127}, - {0, 67, 129}, - {0, 131, 130}, - {0, 5, 132}, - {0, 134, 133}, - {0, 136, 135}, - {0, 138, 137}, - {0, 139, 24}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 151, 150}, - {0, 153, 152}, - {0, 79, 154}, - {0, 156, 155}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 1, 7}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(41, { - {0, 0, 0}, - {342197850, 0, 0}, - {885020215, 0, 0}, - {963902061, 0, 0}, - {1041368449, 0, 0}, - {1352397672, 0, 0}, - {1791427568, 0, 0}, - {2013867381, 0, 0}, - {2513230733, 0, 0}, - {2555315060, 0, 0}, - {2562485583, 0, 0}, - {2567901801, 0, 0}, - {2655147757, 0, 0}, - {2680283743, 0, 0}, - {2752766693, 0, 0}, - {2806716850, 0, 0}, - {3030911670, 0, 0}, - {3401762422, 0, 0}, - {3697738938, 0, 0}, - {4164704452, 0, 0}, - {4273793488, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 10}, - {0, 7, 16}, - {0, 1, 15}, - {0, 9, 6}, - {0, 4, 12}, - {0, 18, 5}, - {0, 13, 2}, - {0, 19, 3}, - {0, 17, 20}, - {0, 23, 22}, - {0, 24, 8}, - {0, 26, 25}, - {0, 27, 11}, - {0, 29, 28}, - {0, 31, 30}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 21, 40}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(129, { - {0, 0, 0}, - {126463145, 0, 0}, - {129135650, 0, 0}, - {200922300, 0, 0}, - {328661377, 0, 0}, - {354479447, 0, 0}, - {360730278, 0, 0}, - {451264926, 0, 0}, - {529068443, 0, 0}, - {593829839, 0, 0}, - {742917749, 0, 0}, - {761731755, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {894529125, 0, 0}, - {959681532, 0, 0}, - {1054461787, 0, 0}, - {1077859090, 0, 0}, - {1086964761, 0, 0}, - {1158929937, 0, 0}, - {1168927492, 0, 0}, - {1196280518, 0, 0}, - {1203545131, 0, 0}, - {1367301635, 0, 0}, - {1508550646, 0, 0}, - {1618544981, 0, 0}, - {1661163736, 0, 0}, - {1684282922, 0, 0}, - {1766994680, 0, 0}, - {1830851200, 0, 0}, - {1901166356, 0, 0}, - {1955104493, 0, 0}, - {2055836767, 0, 0}, - {2096388952, 0, 0}, - {2100052708, 0, 0}, - {2161102232, 0, 0}, - {2197904616, 0, 0}, - {2262137600, 0, 0}, - {2278571792, 0, 0}, - {2281956980, 0, 0}, - {2438466459, 0, 0}, - {2443959748, 0, 0}, - {2517964682, 0, 0}, - {2557754096, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2736844435, 0, 0}, - {2780898906, 0, 0}, - {3044188332, 0, 0}, - {3059119137, 0, 0}, - {3194725903, 0, 0}, - {3270430997, 0, 0}, - {3337532056, 0, 0}, - {3407526215, 0, 0}, - {3496407048, 0, 0}, - {3504158761, 0, 0}, - {3534518722, 0, 0}, - {3570411982, 0, 0}, - {3701632935, 0, 0}, - {3929248764, 0, 0}, - {3944781937, 0, 0}, - {3970432934, 0, 0}, - {4008405264, 0, 0}, - {4245257809, 0, 0}, - {4253051659, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 26}, - {0, 46, 24}, - {0, 64, 50}, - {0, 7, 17}, - {0, 40, 57}, - {0, 56, 49}, - {0, 34, 10}, - {0, 32, 61}, - {0, 36, 44}, - {0, 8, 43}, - {0, 4, 18}, - {0, 25, 23}, - {0, 9, 54}, - {0, 45, 41}, - {0, 13, 21}, - {0, 47, 31}, - {0, 39, 53}, - {0, 11, 3}, - {0, 29, 20}, - {0, 38, 58}, - {0, 37, 14}, - {0, 66, 52}, - {0, 67, 35}, - {0, 48, 68}, - {0, 1, 69}, - {0, 70, 28}, - {0, 27, 63}, - {0, 72, 71}, - {0, 74, 73}, - {0, 75, 60}, - {0, 77, 76}, - {0, 5, 51}, - {0, 15, 78}, - {0, 30, 79}, - {0, 55, 80}, - {0, 42, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 86, 2}, - {0, 19, 16}, - {0, 87, 59}, - {0, 62, 88}, - {0, 90, 89}, - {0, 22, 91}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 12, 102}, - {0, 104, 103}, - {0, 33, 105}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 65, 128}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(127, { - {0, 0, 0}, - {13319433, 0, 0}, - {15502752, 0, 0}, - {162608772, 0, 0}, - {171307615, 0, 0}, - {296981500, 0, 0}, - {354479447, 0, 0}, - {413918748, 0, 0}, - {443490822, 0, 0}, - {487719832, 0, 0}, - {593829839, 0, 0}, - {615982737, 0, 0}, - {703543228, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {875212982, 0, 0}, - {959681532, 0, 0}, - {1019457583, 0, 0}, - {1203545131, 0, 0}, - {1278448636, 0, 0}, - {1325348861, 0, 0}, - {1368383673, 0, 0}, - {1400019344, 0, 0}, - {1646147798, 0, 0}, - {1679946323, 0, 0}, - {1684282922, 0, 0}, - {1747355813, 0, 0}, - {1755648697, 0, 0}, - {1793544760, 0, 0}, - {1811839150, 0, 0}, - {1901166356, 0, 0}, - {1947620272, 0, 0}, - {1992893964, 0, 0}, - {2042001863, 0, 0}, - {2096388952, 0, 0}, - {2123388694, 0, 0}, - {2128251367, 0, 0}, - {2130747644, 0, 0}, - {2135340676, 0, 0}, - {2161102232, 0, 0}, - {2443959748, 0, 0}, - {2513230733, 0, 0}, - {2557754096, 0, 0}, - {2580096524, 0, 0}, - {2589449658, 0, 0}, - {2614879967, 0, 0}, - {2698156268, 0, 0}, - {2970183398, 0, 0}, - {3002890475, 0, 0}, - {3133016299, 0, 0}, - {3142155593, 0, 0}, - {3187066832, 0, 0}, - {3266548732, 0, 0}, - {3287039847, 0, 0}, - {3357301402, 0, 0}, - {3413713311, 0, 0}, - {3434076295, 0, 0}, - {3496407048, 0, 0}, - {3504158761, 0, 0}, - {3882634684, 0, 0}, - {3929248764, 0, 0}, - {3987079331, 0, 0}, - {4076840151, 0, 0}, - {4243119782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 31, 8}, - {0, 14, 56}, - {0, 7, 12}, - {0, 9, 30}, - {0, 42, 36}, - {0, 19, 11}, - {0, 22, 40}, - {0, 15, 3}, - {0, 57, 26}, - {0, 58, 61}, - {0, 55, 51}, - {0, 48, 34}, - {0, 20, 1}, - {0, 24, 23}, - {0, 46, 35}, - {0, 59, 49}, - {0, 21, 63}, - {0, 62, 44}, - {0, 6, 50}, - {0, 28, 18}, - {0, 66, 65}, - {0, 41, 32}, - {0, 39, 54}, - {0, 53, 67}, - {0, 68, 37}, - {0, 33, 69}, - {0, 43, 70}, - {0, 71, 38}, - {0, 72, 27}, - {0, 13, 47}, - {0, 45, 73}, - {0, 75, 74}, - {0, 76, 5}, - {0, 77, 17}, - {0, 79, 78}, - {0, 52, 80}, - {0, 2, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 4, 88}, - {0, 16, 29}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 60, 95}, - {0, 97, 96}, - {0, 98, 10}, - {0, 25, 99}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 64, 126}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 7, 1}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(153, { - {0, 0, 0}, - {10142671, 0, 0}, - {27865391, 0, 0}, - {29517006, 0, 0}, - {41739659, 0, 0}, - {97231530, 0, 0}, - {171334650, 0, 0}, - {200553094, 0, 0}, - {257136089, 0, 0}, - {294390719, 0, 0}, - {375530199, 0, 0}, - {380957745, 0, 0}, - {388034151, 0, 0}, - {455591063, 0, 0}, - {462664429, 0, 0}, - {491456522, 0, 0}, - {502863753, 0, 0}, - {626480004, 0, 0}, - {643418617, 0, 0}, - {651464351, 0, 0}, - {701281393, 0, 0}, - {744817486, 0, 0}, - {783918780, 0, 0}, - {862784766, 0, 0}, - {930804377, 0, 0}, - {952536201, 0, 0}, - {955476870, 0, 0}, - {1043738701, 0, 0}, - {1047011733, 0, 0}, - {1080545747, 0, 0}, - {1137442027, 0, 0}, - {1235468610, 0, 0}, - {1412908157, 0, 0}, - {1431749301, 0, 0}, - {1434223270, 0, 0}, - {1440646342, 0, 0}, - {1508570930, 0, 0}, - {1510422521, 0, 0}, - {1548121999, 0, 0}, - {1582841441, 0, 0}, - {1612225949, 0, 0}, - {1665981878, 0, 0}, - {1680746207, 0, 0}, - {1696076631, 0, 0}, - {1702168830, 0, 0}, - {1761469971, 0, 0}, - {1799299383, 0, 0}, - {1910240213, 0, 0}, - {1917451875, 0, 0}, - {1945006185, 0, 0}, - {1998444837, 0, 0}, - {2045285083, 0, 0}, - {2217966239, 0, 0}, - {2279273489, 0, 0}, - {2289803479, 0, 0}, - {2348676810, 0, 0}, - {2353194283, 0, 0}, - {2403632109, 0, 0}, - {2409539315, 0, 0}, - {2414984922, 0, 0}, - {2477389837, 0, 0}, - {2524531022, 0, 0}, - {2573160348, 0, 0}, - {2639720559, 0, 0}, - {2773229577, 0, 0}, - {2796513469, 0, 0}, - {2881225774, 0, 0}, - {2890570341, 0, 0}, - {2952850186, 0, 0}, - {3023287679, 0, 0}, - {3118548424, 0, 0}, - {3877813395, 0, 0}, - {3931288033, 0, 0}, - {3972309363, 0, 0}, - {4117704995, 0, 0}, - {4140081844, 0, 0}, - {4258414038, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 74, 53}, - {0, 58, 52}, - {0, 65, 60}, - {0, 41, 5}, - {0, 1, 67}, - {0, 24, 28}, - {0, 27, 26}, - {0, 55, 31}, - {0, 36, 61}, - {0, 13, 49}, - {0, 56, 48}, - {0, 16, 64}, - {0, 76, 42}, - {0, 45, 29}, - {0, 23, 6}, - {0, 72, 12}, - {0, 35, 19}, - {0, 20, 7}, - {0, 21, 46}, - {0, 71, 78}, - {0, 80, 79}, - {0, 47, 17}, - {0, 81, 70}, - {0, 34, 25}, - {0, 83, 82}, - {0, 85, 84}, - {0, 37, 86}, - {0, 87, 73}, - {0, 10, 4}, - {0, 40, 30}, - {0, 88, 57}, - {0, 54, 89}, - {0, 50, 90}, - {0, 11, 91}, - {0, 39, 15}, - {0, 59, 44}, - {0, 92, 66}, - {0, 69, 93}, - {0, 95, 94}, - {0, 14, 96}, - {0, 98, 97}, - {0, 62, 51}, - {0, 100, 99}, - {0, 102, 101}, - {0, 104, 103}, - {0, 32, 43}, - {0, 105, 38}, - {0, 107, 106}, - {0, 109, 108}, - {0, 22, 9}, - {0, 33, 110}, - {0, 2, 111}, - {0, 112, 3}, - {0, 114, 113}, - {0, 116, 115}, - {0, 68, 63}, - {0, 118, 117}, - {0, 120, 119}, - {0, 121, 8}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 131, 130}, - {0, 133, 132}, - {0, 75, 18}, - {0, 135, 134}, - {0, 137, 136}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 150, 77}, - {0, 152, 151}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(131, { - {0, 0, 0}, - {5908395, 0, 0}, - {139011596, 0, 0}, - {296981500, 0, 0}, - {342615870, 0, 0}, - {370232173, 0, 0}, - {492958971, 0, 0}, - {528662843, 0, 0}, - {551924251, 0, 0}, - {604894932, 0, 0}, - {610429940, 0, 0}, - {780957373, 0, 0}, - {810488476, 0, 0}, - {872544165, 0, 0}, - {878733439, 0, 0}, - {918849409, 0, 0}, - {959681532, 0, 0}, - {1013756921, 0, 0}, - {1038982109, 0, 0}, - {1081611718, 0, 0}, - {1125913837, 0, 0}, - {1209418480, 0, 0}, - {1318081294, 0, 0}, - {1367301635, 0, 0}, - {1417425499, 0, 0}, - {1625742020, 0, 0}, - {1684282922, 0, 0}, - {1746004874, 0, 0}, - {1758287856, 0, 0}, - {1777640493, 0, 0}, - {2066323109, 0, 0}, - {2094550054, 0, 0}, - {2096388952, 0, 0}, - {2144962711, 0, 0}, - {2434845539, 0, 0}, - {2480811229, 0, 0}, - {2552825357, 0, 0}, - {2636946065, 0, 0}, - {2651956495, 0, 0}, - {2669086217, 0, 0}, - {2680819379, 0, 0}, - {2709694527, 0, 0}, - {2715304020, 0, 0}, - {2790648021, 0, 0}, - {2802261839, 0, 0}, - {2806296851, 0, 0}, - {2864543087, 0, 0}, - {2952260510, 0, 0}, - {2963184673, 0, 0}, - {3091876332, 0, 0}, - {3098991995, 0, 0}, - {3131890669, 0, 0}, - {3138977758, 0, 0}, - {3198541202, 0, 0}, - {3260579369, 0, 0}, - {3263841912, 0, 0}, - {3335250889, 0, 0}, - {3345856521, 0, 0}, - {3381478137, 0, 0}, - {3489269251, 0, 0}, - {3510242586, 0, 0}, - {3820814597, 0, 0}, - {3900859293, 0, 0}, - {4041974454, 0, 0}, - {4244540017, 0, 0}, - {4265894873, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 15, 52}, - {0, 20, 18}, - {0, 39, 29}, - {0, 9, 43}, - {0, 22, 13}, - {0, 46, 27}, - {0, 51, 48}, - {0, 19, 57}, - {0, 34, 24}, - {0, 64, 59}, - {0, 5, 7}, - {0, 38, 37}, - {0, 45, 47}, - {0, 2, 56}, - {0, 67, 8}, - {0, 17, 68}, - {0, 69, 61}, - {0, 70, 6}, - {0, 55, 54}, - {0, 72, 71}, - {0, 4, 73}, - {0, 74, 40}, - {0, 30, 11}, - {0, 42, 36}, - {0, 75, 58}, - {0, 31, 76}, - {0, 1, 77}, - {0, 44, 14}, - {0, 78, 50}, - {0, 79, 23}, - {0, 26, 80}, - {0, 81, 12}, - {0, 83, 82}, - {0, 84, 21}, - {0, 32, 85}, - {0, 87, 86}, - {0, 35, 10}, - {0, 88, 62}, - {0, 90, 89}, - {0, 41, 91}, - {0, 92, 53}, - {0, 93, 63}, - {0, 95, 94}, - {0, 33, 96}, - {0, 98, 97}, - {0, 99, 3}, - {0, 100, 28}, - {0, 101, 49}, - {0, 102, 60}, - {0, 104, 103}, - {0, 106, 105}, - {0, 108, 107}, - {0, 110, 109}, - {0, 65, 111}, - {0, 25, 112}, - {0, 114, 113}, - {0, 116, 115}, - {0, 117, 16}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 128, 66}, - {0, 130, 129}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(95, { - {0, 0, 0}, - {116093251, 0, 0}, - {149720480, 0, 0}, - {183103444, 0, 0}, - {251209228, 0, 0}, - {296981500, 0, 0}, - {357505993, 0, 0}, - {394654115, 0, 0}, - {410274915, 0, 0}, - {452208841, 0, 0}, - {788046331, 0, 0}, - {797934924, 0, 0}, - {810488476, 0, 0}, - {1144188012, 0, 0}, - {1220127364, 0, 0}, - {1321616112, 0, 0}, - {1324351672, 0, 0}, - {1348149915, 0, 0}, - {1459457331, 0, 0}, - {1465623797, 0, 0}, - {1531216990, 0, 0}, - {1543672828, 0, 0}, - {1578775276, 0, 0}, - {1738815671, 0, 0}, - {1904128160, 0, 0}, - {2071351379, 0, 0}, - {2119793999, 0, 0}, - {2274779301, 0, 0}, - {2291766425, 0, 0}, - {2357410109, 0, 0}, - {2438466459, 0, 0}, - {2496463830, 0, 0}, - {2630220147, 0, 0}, - {2682510803, 0, 0}, - {3047649911, 0, 0}, - {3085703811, 0, 0}, - {3235459678, 0, 0}, - {3261703164, 0, 0}, - {3331487616, 0, 0}, - {3462674048, 0, 0}, - {3570219049, 0, 0}, - {3585315836, 0, 0}, - {3602108619, 0, 0}, - {3724004880, 0, 0}, - {3931641900, 0, 0}, - {3955205564, 0, 0}, - {4073492988, 0, 0}, - {4127308103, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 24, 37}, - {0, 13, 38}, - {0, 17, 39}, - {0, 35, 23}, - {0, 18, 36}, - {0, 46, 19}, - {0, 20, 33}, - {0, 47, 6}, - {0, 1, 45}, - {0, 3, 27}, - {0, 8, 49}, - {0, 50, 29}, - {0, 10, 51}, - {0, 43, 31}, - {0, 53, 52}, - {0, 54, 26}, - {0, 7, 55}, - {0, 56, 32}, - {0, 57, 41}, - {0, 59, 58}, - {0, 61, 60}, - {0, 63, 62}, - {0, 64, 25}, - {0, 2, 34}, - {0, 65, 14}, - {0, 67, 66}, - {0, 12, 21}, - {0, 9, 68}, - {0, 69, 16}, - {0, 71, 70}, - {0, 72, 44}, - {0, 11, 73}, - {0, 74, 30}, - {0, 4, 75}, - {0, 28, 15}, - {0, 76, 42}, - {0, 5, 77}, - {0, 78, 40}, - {0, 80, 79}, - {0, 82, 81}, - {0, 22, 83}, - {0, 85, 84}, - {0, 86, 48}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(121, { - {0, 0, 0}, - {14113753, 0, 0}, - {102358168, 0, 0}, - {179458548, 0, 0}, - {330388453, 0, 0}, - {386525753, 0, 0}, - {470277359, 0, 0}, - {497658126, 0, 0}, - {508007510, 0, 0}, - {815034111, 0, 0}, - {826214242, 0, 0}, - {849867303, 0, 0}, - {885645401, 0, 0}, - {939415664, 0, 0}, - {968885186, 0, 0}, - {1105835505, 0, 0}, - {1159301677, 0, 0}, - {1461897718, 0, 0}, - {1482251215, 0, 0}, - {1486206763, 0, 0}, - {1527762373, 0, 0}, - {1558990974, 0, 0}, - {1618754372, 0, 0}, - {1669959736, 0, 0}, - {1752686878, 0, 0}, - {2004567202, 0, 0}, - {2055637638, 0, 0}, - {2113506324, 0, 0}, - {2154320787, 0, 0}, - {2162274327, 0, 0}, - {2306141594, 0, 0}, - {2345566651, 0, 0}, - {2457690657, 0, 0}, - {2473053808, 0, 0}, - {2500422644, 0, 0}, - {2504802016, 0, 0}, - {2506771164, 0, 0}, - {2793529873, 0, 0}, - {2801333547, 0, 0}, - {2879050471, 0, 0}, - {3032677281, 0, 0}, - {3045470312, 0, 0}, - {3181546731, 0, 0}, - {3240977890, 0, 0}, - {3262572726, 0, 0}, - {3307100165, 0, 0}, - {3425841570, 0, 0}, - {3560552546, 0, 0}, - {3641833815, 0, 0}, - {3652695478, 0, 0}, - {3782362128, 0, 0}, - {3797961332, 0, 0}, - {3837583704, 0, 0}, - {3886529747, 0, 0}, - {3907920335, 0, 0}, - {4043078107, 0, 0}, - {4044928561, 0, 0}, - {4069720347, 0, 0}, - {4180570743, 0, 0}, - {4245743275, 0, 0}, - {4285201458, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 44, 28}, - {0, 13, 45}, - {0, 19, 15}, - {0, 32, 31}, - {0, 43, 42}, - {0, 16, 52}, - {0, 33, 22}, - {0, 57, 55}, - {0, 24, 21}, - {0, 2, 59}, - {0, 10, 3}, - {0, 18, 12}, - {0, 41, 39}, - {0, 60, 46}, - {0, 4, 25}, - {0, 58, 49}, - {0, 14, 1}, - {0, 27, 17}, - {0, 50, 36}, - {0, 23, 54}, - {0, 5, 30}, - {0, 11, 7}, - {0, 38, 29}, - {0, 37, 8}, - {0, 48, 56}, - {0, 20, 6}, - {0, 34, 26}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 9, 76}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 40, 35}, - {0, 85, 47}, - {0, 86, 51}, - {0, 88, 87}, - {0, 90, 89}, - {0, 53, 91}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 61, 120}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(127, { - {0, 0, 0}, - {100979271, 0, 0}, - {269576093, 0, 0}, - {314809953, 0, 0}, - {354479447, 0, 0}, - {497658126, 0, 0}, - {882718761, 0, 0}, - {968885186, 0, 0}, - {973908139, 0, 0}, - {1019457583, 0, 0}, - {1191015885, 0, 0}, - {1266262705, 0, 0}, - {1310404265, 0, 0}, - {1325348861, 0, 0}, - {1367301635, 0, 0}, - {1368383673, 0, 0}, - {1570165302, 0, 0}, - {1618544981, 0, 0}, - {1646147798, 0, 0}, - {1674464100, 0, 0}, - {1679946323, 0, 0}, - {1686512349, 0, 0}, - {1766401548, 0, 0}, - {1774052499, 0, 0}, - {1788301425, 0, 0}, - {2023008475, 0, 0}, - {2055836767, 0, 0}, - {2096388952, 0, 0}, - {2123388694, 0, 0}, - {2129301998, 0, 0}, - {2212501241, 0, 0}, - {2274226560, 0, 0}, - {2362972044, 0, 0}, - {2378763734, 0, 0}, - {2506771164, 0, 0}, - {2558655180, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2698156268, 0, 0}, - {2801333547, 0, 0}, - {2850246066, 0, 0}, - {2895151306, 0, 0}, - {2970183398, 0, 0}, - {2986830770, 0, 0}, - {3001444829, 0, 0}, - {3133016299, 0, 0}, - {3152745753, 0, 0}, - {3187066832, 0, 0}, - {3261122899, 0, 0}, - {3496407048, 0, 0}, - {3513669836, 0, 0}, - {3536390697, 0, 0}, - {3570411982, 0, 0}, - {3653838348, 0, 0}, - {3713290482, 0, 0}, - {3858973601, 0, 0}, - {3873587660, 0, 0}, - {3877583949, 0, 0}, - {3882634684, 0, 0}, - {3907920335, 0, 0}, - {3997432565, 0, 0}, - {4169226615, 0, 0}, - {4219766939, 0, 0}, - {4243119782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 12}, - {0, 41, 29}, - {0, 56, 44}, - {0, 1, 3}, - {0, 48, 24}, - {0, 33, 60}, - {0, 8, 50}, - {0, 35, 21}, - {0, 11, 7}, - {0, 34, 23}, - {0, 59, 57}, - {0, 10, 62}, - {0, 40, 2}, - {0, 5, 49}, - {0, 39, 17}, - {0, 9, 61}, - {0, 30, 6}, - {0, 19, 46}, - {0, 53, 54}, - {0, 31, 52}, - {0, 55, 43}, - {0, 66, 65}, - {0, 16, 67}, - {0, 51, 68}, - {0, 70, 69}, - {0, 26, 36}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 37, 83}, - {0, 85, 84}, - {0, 13, 86}, - {0, 20, 18}, - {0, 38, 28}, - {0, 58, 45}, - {0, 87, 63}, - {0, 15, 88}, - {0, 32, 22}, - {0, 89, 4}, - {0, 90, 14}, - {0, 91, 42}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 27, 47}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 126, 64}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(137, { - {0, 0, 0}, - {11698369, 0, 0}, - {146392076, 0, 0}, - {151810803, 0, 0}, - {223800276, 0, 0}, - {227103506, 0, 0}, - {253329281, 0, 0}, - {346929928, 0, 0}, - {461040879, 0, 0}, - {629859130, 0, 0}, - {680157484, 0, 0}, - {783918780, 0, 0}, - {810488476, 0, 0}, - {824323032, 0, 0}, - {870594305, 0, 0}, - {959681532, 0, 0}, - {975807626, 0, 0}, - {1081642571, 0, 0}, - {1084574846, 0, 0}, - {1094817798, 0, 0}, - {1141965917, 0, 0}, - {1164137269, 0, 0}, - {1166917451, 0, 0}, - {1204787336, 0, 0}, - {1232501371, 0, 0}, - {1318479490, 0, 0}, - {1369818198, 0, 0}, - {1372785527, 0, 0}, - {1526654696, 0, 0}, - {1543672828, 0, 0}, - {1548121999, 0, 0}, - {1635292159, 0, 0}, - {1641070431, 0, 0}, - {1684282922, 0, 0}, - {1767704813, 0, 0}, - {1781765116, 0, 0}, - {1838763297, 0, 0}, - {1901166356, 0, 0}, - {1904846533, 0, 0}, - {2011183308, 0, 0}, - {2032069771, 0, 0}, - {2071351379, 0, 0}, - {2087004702, 0, 0}, - {2244928358, 0, 0}, - {2314864456, 0, 0}, - {2374216296, 0, 0}, - {2394332122, 0, 0}, - {2443610186, 0, 0}, - {2524697596, 0, 0}, - {2526961521, 0, 0}, - {2568098594, 0, 0}, - {2807907995, 0, 0}, - {3103302036, 0, 0}, - {3117071189, 0, 0}, - {3188115516, 0, 0}, - {3417584874, 0, 0}, - {3554463148, 0, 0}, - {3561482820, 0, 0}, - {3691770462, 0, 0}, - {3729929345, 0, 0}, - {3733675151, 0, 0}, - {3831290364, 0, 0}, - {3866493821, 0, 0}, - {3929248764, 0, 0}, - {4060703604, 0, 0}, - {4092487128, 0, 0}, - {4167600590, 0, 0}, - {4214779116, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 36, 13}, - {0, 49, 60}, - {0, 51, 9}, - {0, 3, 62}, - {0, 67, 41}, - {0, 4, 31}, - {0, 66, 5}, - {0, 55, 32}, - {0, 2, 1}, - {0, 30, 16}, - {0, 7, 38}, - {0, 19, 10}, - {0, 34, 20}, - {0, 45, 46}, - {0, 22, 11}, - {0, 25, 23}, - {0, 40, 39}, - {0, 21, 57}, - {0, 6, 35}, - {0, 61, 8}, - {0, 52, 26}, - {0, 70, 59}, - {0, 71, 14}, - {0, 68, 47}, - {0, 73, 72}, - {0, 29, 74}, - {0, 76, 75}, - {0, 77, 17}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 18}, - {0, 83, 42}, - {0, 85, 84}, - {0, 87, 86}, - {0, 27, 37}, - {0, 53, 43}, - {0, 89, 88}, - {0, 64, 54}, - {0, 90, 65}, - {0, 92, 91}, - {0, 58, 93}, - {0, 56, 48}, - {0, 94, 28}, - {0, 96, 95}, - {0, 98, 97}, - {0, 44, 99}, - {0, 101, 100}, - {0, 15, 12}, - {0, 103, 102}, - {0, 104, 33}, - {0, 106, 105}, - {0, 108, 107}, - {0, 24, 109}, - {0, 111, 110}, - {0, 113, 112}, - {0, 114, 50}, - {0, 116, 115}, - {0, 118, 117}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 126, 125}, - {0, 128, 127}, - {0, 129, 63}, - {0, 131, 130}, - {0, 133, 132}, - {0, 135, 134}, - {0, 136, 69}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpDot, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(97, { - {0, 0, 0}, - {78001013, 0, 0}, - {170690025, 0, 0}, - {206688607, 0, 0}, - {443490822, 0, 0}, - {461476226, 0, 0}, - {537830163, 0, 0}, - {669982125, 0, 0}, - {790502615, 0, 0}, - {805072272, 0, 0}, - {1173092699, 0, 0}, - {1220643281, 0, 0}, - {1448448666, 0, 0}, - {1466804584, 0, 0}, - {1473411044, 0, 0}, - {1515695460, 0, 0}, - {1587730355, 0, 0}, - {1625742020, 0, 0}, - {2071351379, 0, 0}, - {2250055803, 0, 0}, - {2291766425, 0, 0}, - {2416108131, 0, 0}, - {2427834344, 0, 0}, - {2436009347, 0, 0}, - {2455417440, 0, 0}, - {2480811229, 0, 0}, - {2654325647, 0, 0}, - {2919796598, 0, 0}, - {3047649911, 0, 0}, - {3088511797, 0, 0}, - {3104643263, 0, 0}, - {3198541202, 0, 0}, - {3204986803, 0, 0}, - {3272233597, 0, 0}, - {3383007207, 0, 0}, - {3602108619, 0, 0}, - {3622349409, 0, 0}, - {3714664910, 0, 0}, - {3717942504, 0, 0}, - {3732000233, 0, 0}, - {3759072440, 0, 0}, - {3765247327, 0, 0}, - {3805423332, 0, 0}, - {3829325073, 0, 0}, - {3866493821, 0, 0}, - {4058280485, 0, 0}, - {4061558677, 0, 0}, - {4148979936, 0, 0}, - {4155586396, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 13, 38}, - {0, 39, 14}, - {0, 44, 9}, - {0, 48, 47}, - {0, 23, 15}, - {0, 33, 25}, - {0, 1, 42}, - {0, 5, 46}, - {0, 31, 3}, - {0, 36, 28}, - {0, 16, 12}, - {0, 32, 22}, - {0, 41, 21}, - {0, 6, 50}, - {0, 51, 29}, - {0, 45, 34}, - {0, 37, 8}, - {0, 19, 52}, - {0, 11, 4}, - {0, 43, 40}, - {0, 27, 53}, - {0, 54, 10}, - {0, 24, 55}, - {0, 57, 56}, - {0, 58, 26}, - {0, 2, 59}, - {0, 61, 60}, - {0, 63, 62}, - {0, 65, 64}, - {0, 20, 66}, - {0, 30, 35}, - {0, 67, 17}, - {0, 68, 7}, - {0, 70, 69}, - {0, 71, 18}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 49, 96}, - })); - - codecs.emplace(std::pair(SpvOpDot, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(117, { - {0, 0, 0}, - {50385656, 0, 0}, - {181902171, 0, 0}, - {560078433, 0, 0}, - {615982737, 0, 0}, - {674428451, 0, 0}, - {837715723, 0, 0}, - {886972033, 0, 0}, - {900101778, 0, 0}, - {983299427, 0, 0}, - {1237148906, 0, 0}, - {1364157225, 0, 0}, - {1367301635, 0, 0}, - {1380160211, 0, 0}, - {1451831482, 0, 0}, - {1499923635, 0, 0}, - {1570165302, 0, 0}, - {1735295265, 0, 0}, - {1766401548, 0, 0}, - {1796311149, 0, 0}, - {1826456251, 0, 0}, - {1839669171, 0, 0}, - {2012838864, 0, 0}, - {2024071551, 0, 0}, - {2096388952, 0, 0}, - {2161102232, 0, 0}, - {2197874825, 0, 0}, - {2279700640, 0, 0}, - {2289183712, 0, 0}, - {2351620600, 0, 0}, - {2362972044, 0, 0}, - {2472176885, 0, 0}, - {2477434291, 0, 0}, - {2530899578, 0, 0}, - {2531826164, 0, 0}, - {2558133383, 0, 0}, - {2589449658, 0, 0}, - {2621255555, 0, 0}, - {2622612602, 0, 0}, - {2872580757, 0, 0}, - {2881302403, 0, 0}, - {2891091137, 0, 0}, - {2923708820, 0, 0}, - {2936040203, 0, 0}, - {2970183398, 0, 0}, - {3187066832, 0, 0}, - {3224952074, 0, 0}, - {3244383472, 0, 0}, - {3261122899, 0, 0}, - {3362830643, 0, 0}, - {3538158875, 0, 0}, - {3635542517, 0, 0}, - {3682213068, 0, 0}, - {3721902098, 0, 0}, - {3826846522, 0, 0}, - {3877583949, 0, 0}, - {3997432565, 0, 0}, - {4093615095, 0, 0}, - {4106828015, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 52, 28}, - {0, 33, 20}, - {0, 46, 57}, - {0, 47, 54}, - {0, 21, 17}, - {0, 31, 58}, - {0, 12, 53}, - {0, 29, 3}, - {0, 35, 34}, - {0, 48, 41}, - {0, 8, 5}, - {0, 7, 55}, - {0, 37, 32}, - {0, 60, 38}, - {0, 61, 16}, - {0, 14, 62}, - {0, 23, 63}, - {0, 13, 19}, - {0, 64, 9}, - {0, 65, 39}, - {0, 2, 66}, - {0, 67, 42}, - {0, 69, 68}, - {0, 25, 70}, - {0, 1, 49}, - {0, 6, 71}, - {0, 72, 15}, - {0, 73, 11}, - {0, 75, 74}, - {0, 77, 76}, - {0, 4, 78}, - {0, 56, 50}, - {0, 80, 79}, - {0, 10, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 86, 27}, - {0, 43, 40}, - {0, 88, 87}, - {0, 44, 24}, - {0, 30, 89}, - {0, 51, 36}, - {0, 45, 90}, - {0, 18, 91}, - {0, 93, 92}, - {0, 22, 94}, - {0, 26, 95}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 59, 114}, - {0, 116, 115}, - })); - - codecs.emplace(std::pair(SpvOpDot, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(179, { - {0, 0, 0}, - {27177503, 0, 0}, - {50385656, 0, 0}, - {129748122, 0, 0}, - {139011596, 0, 0}, - {162608772, 0, 0}, - {181902171, 0, 0}, - {225200779, 0, 0}, - {342159236, 0, 0}, - {386293029, 0, 0}, - {429023543, 0, 0}, - {443558693, 0, 0}, - {504514034, 0, 0}, - {615982737, 0, 0}, - {669812542, 0, 0}, - {674428451, 0, 0}, - {837715723, 0, 0}, - {861753115, 0, 0}, - {875212982, 0, 0}, - {876867882, 0, 0}, - {899320334, 0, 0}, - {900101778, 0, 0}, - {938517572, 0, 0}, - {1347339159, 0, 0}, - {1356063462, 0, 0}, - {1373856501, 0, 0}, - {1376656865, 0, 0}, - {1451831482, 0, 0}, - {1522979646, 0, 0}, - {1548491889, 0, 0}, - {1570165302, 0, 0}, - {1735295265, 0, 0}, - {1747355813, 0, 0}, - {1766401548, 0, 0}, - {1871105284, 0, 0}, - {1918742169, 0, 0}, - {1922045399, 0, 0}, - {1978689945, 0, 0}, - {2024071551, 0, 0}, - {2059975069, 0, 0}, - {2076833303, 0, 0}, - {2096388952, 0, 0}, - {2181030375, 0, 0}, - {2197874825, 0, 0}, - {2362972044, 0, 0}, - {2414725163, 0, 0}, - {2517964682, 0, 0}, - {2564745684, 0, 0}, - {2577387676, 0, 0}, - {2589449658, 0, 0}, - {2604242419, 0, 0}, - {2683080096, 0, 0}, - {2696349144, 0, 0}, - {2763960513, 0, 0}, - {2817823941, 0, 0}, - {2852854788, 0, 0}, - {2891091137, 0, 0}, - {2919626325, 0, 0}, - {2923708820, 0, 0}, - {2936040203, 0, 0}, - {2963744582, 0, 0}, - {2970183398, 0, 0}, - {2984459037, 0, 0}, - {2996594997, 0, 0}, - {3015046341, 0, 0}, - {3055195668, 0, 0}, - {3127329373, 0, 0}, - {3187066832, 0, 0}, - {3193597927, 0, 0}, - {3200890815, 0, 0}, - {3224258475, 0, 0}, - {3224480461, 0, 0}, - {3261122899, 0, 0}, - {3609540589, 0, 0}, - {3619404941, 0, 0}, - {3619626927, 0, 0}, - {3727034815, 0, 0}, - {3742724777, 0, 0}, - {3742946763, 0, 0}, - {3836179806, 0, 0}, - {3913885196, 0, 0}, - {3927338499, 0, 0}, - {3927466635, 0, 0}, - {3997432565, 0, 0}, - {3999472204, 0, 0}, - {4010499223, 0, 0}, - {4032662899, 0, 0}, - {4110915453, 0, 0}, - {4145966869, 0, 0}, - {4228303141, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 23, 87}, - {0, 9, 28}, - {0, 42, 17}, - {0, 74, 70}, - {0, 86, 77}, - {0, 18, 5}, - {0, 31, 32}, - {0, 34, 3}, - {0, 38, 68}, - {0, 50, 29}, - {0, 72, 62}, - {0, 21, 15}, - {0, 14, 54}, - {0, 56, 22}, - {0, 48, 88}, - {0, 2, 76}, - {0, 6, 47}, - {0, 26, 79}, - {0, 65, 12}, - {0, 37, 81}, - {0, 91, 60}, - {0, 30, 92}, - {0, 25, 7}, - {0, 45, 40}, - {0, 66, 52}, - {0, 71, 69}, - {0, 78, 75}, - {0, 84, 82}, - {0, 94, 93}, - {0, 27, 95}, - {0, 97, 96}, - {0, 99, 98}, - {0, 100, 39}, - {0, 55, 101}, - {0, 58, 102}, - {0, 89, 103}, - {0, 35, 11}, - {0, 104, 36}, - {0, 53, 10}, - {0, 1, 64}, - {0, 73, 20}, - {0, 105, 13}, - {0, 107, 106}, - {0, 8, 16}, - {0, 24, 19}, - {0, 85, 63}, - {0, 109, 108}, - {0, 111, 110}, - {0, 4, 112}, - {0, 114, 113}, - {0, 116, 115}, - {0, 118, 117}, - {0, 83, 119}, - {0, 121, 120}, - {0, 123, 122}, - {0, 49, 44}, - {0, 124, 57}, - {0, 125, 59}, - {0, 126, 67}, - {0, 128, 127}, - {0, 130, 129}, - {0, 132, 131}, - {0, 134, 133}, - {0, 135, 51}, - {0, 137, 136}, - {0, 138, 61}, - {0, 43, 41}, - {0, 140, 139}, - {0, 142, 141}, - {0, 144, 143}, - {0, 146, 145}, - {0, 148, 147}, - {0, 149, 33}, - {0, 80, 150}, - {0, 152, 151}, - {0, 154, 153}, - {0, 156, 155}, - {0, 158, 157}, - {0, 160, 159}, - {0, 162, 161}, - {0, 164, 163}, - {0, 166, 165}, - {0, 168, 167}, - {0, 46, 169}, - {0, 171, 170}, - {0, 90, 172}, - {0, 174, 173}, - {0, 176, 175}, - {0, 178, 177}, - })); - - codecs.emplace(std::pair(SpvOpDot, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1036475267, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpLabel, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1036475267, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpBranch, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(119, { - {0, 0, 0}, - {57149555, 0, 0}, - {139011596, 0, 0}, - {255835594, 0, 0}, - {330249537, 0, 0}, - {388686774, 0, 0}, - {508217552, 0, 0}, - {550831114, 0, 0}, - {559246409, 0, 0}, - {599185303, 0, 0}, - {649208064, 0, 0}, - {679061455, 0, 0}, - {810488476, 0, 0}, - {951841533, 0, 0}, - {1008886329, 0, 0}, - {1022544883, 0, 0}, - {1215030156, 0, 0}, - {1305703280, 0, 0}, - {1367301635, 0, 0}, - {1453447304, 0, 0}, - {1487177499, 0, 0}, - {1603937321, 0, 0}, - {1617826947, 0, 0}, - {1643868273, 0, 0}, - {1672607981, 0, 0}, - {1681941034, 0, 0}, - {1755165354, 0, 0}, - {1781864804, 0, 0}, - {1795715718, 0, 0}, - {1977038330, 0, 0}, - {2096388952, 0, 0}, - {2204920111, 0, 0}, - {2244470522, 0, 0}, - {2330636993, 0, 0}, - {2400601988, 0, 0}, - {2424848261, 0, 0}, - {2603020391, 0, 0}, - {2622612602, 0, 0}, - {2645135839, 0, 0}, - {2660843182, 0, 0}, - {2708915136, 0, 0}, - {2724166585, 0, 0}, - {2728667725, 0, 0}, - {2890638791, 0, 0}, - {2901034693, 0, 0}, - {2941648648, 0, 0}, - {2970183398, 0, 0}, - {2998120306, 0, 0}, - {3123244280, 0, 0}, - {3187066832, 0, 0}, - {3209399506, 0, 0}, - {3230260738, 0, 0}, - {3344189994, 0, 0}, - {3345707173, 0, 0}, - {3367298820, 0, 0}, - {3397078357, 0, 0}, - {3569736966, 0, 0}, - {3816961131, 0, 0}, - {4091670162, 0, 0}, - {4237497041, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 44}, - {0, 25, 20}, - {0, 29, 34}, - {0, 18, 2}, - {0, 54, 49}, - {0, 28, 7}, - {0, 47, 52}, - {0, 23, 56}, - {0, 55, 26}, - {0, 24, 61}, - {0, 13, 62}, - {0, 63, 45}, - {0, 27, 15}, - {0, 64, 8}, - {0, 65, 59}, - {0, 35, 22}, - {0, 53, 38}, - {0, 58, 51}, - {0, 11, 66}, - {0, 10, 3}, - {0, 46, 67}, - {0, 69, 68}, - {0, 1, 50}, - {0, 42, 19}, - {0, 70, 6}, - {0, 31, 71}, - {0, 16, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 79, 4}, - {0, 5, 37}, - {0, 14, 36}, - {0, 80, 57}, - {0, 81, 48}, - {0, 83, 82}, - {0, 39, 84}, - {0, 86, 85}, - {0, 40, 87}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 21, 9}, - {0, 41, 32}, - {0, 12, 43}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 100, 33}, - {0, 60, 101}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 110, 30}, - {0, 112, 111}, - {0, 114, 113}, - {0, 116, 115}, - {0, 118, 117}, - })); - - codecs.emplace(std::pair(SpvOpReturnValue, 0), std::move(codec)); - } - - return codecs; -} - -std::unordered_set GetDescriptorsWithCodingScheme() { - std::unordered_set descriptors_with_coding_scheme = { - 3816961131, - 3569736966, - 3397078357, - 3344189994, - 3230260738, - 2941648648, - 2901034693, - 2728667725, - 2400601988, - 1795715718, - 1681941034, - 1487177499, - 1453447304, - 679061455, - 649208064, - 559246409, - 388686774, - 4228303141, - 4110915453, - 4010499223, - 3927466635, - 3927338499, - 3836179806, - 3742724777, - 3619404941, - 3224480461, - 3224258475, - 3200890815, - 3742946763, - 3193597927, - 2604242419, - 2577387676, - 2181030375, - 1376656865, - 1347339159, - 938517572, - 876867882, - 429023543, - 129748122, - 4106828015, - 4093615095, - 3826846522, - 3721902098, - 3244383472, - 2891091137, - 2872580757, - 2558133383, - 2477434291, - 1839669171, - 2059975069, - 1735295265, - 1364157225, - 1237148906, - 886972033, - 674428451, - 4148979936, - 3805423332, - 3732000233, - 3717942504, - 3714664910, - 3622349409, - 3272233597, - 3204986803, - 3088511797, - 1672607981, - 2416108131, - 2250055803, - 1796311149, - 1515695460, - 537830163, - 461476226, - 206688607, - 78001013, - 3866493821, - 3417584874, - 3188115516, - 2526961521, - 2443610186, - 2394332122, - 2374216296, - 2032069771, - 2011183308, - 1904846533, - 1641070431, - 1635292159, - 1372785527, - 1369818198, - 1204787336, - 1826456251, - 1164137269, - 1081642571, - 629859130, - 253329281, - 227103506, - 11698369, - 4219766939, - 4169226615, - 3997432565, - 3873587660, - 3513669836, - 3261122899, - 2129301998, - 1774052499, - 1266262705, - 4285201458, - 4245743275, - 3907920335, - 3837583704, - 3641833815, - 3307100165, - 1232501371, - 3262572726, - 3045470312, - 2879050471, - 2801333547, - 2506771164, - 2504802016, - 2500422644, - 2473053808, - 2457690657, - 2345566651, - 2306141594, - 2154320787, - 2055637638, - 1527762373, - 1486206763, - 1159301677, - 1105835505, - 968885186, - 885645401, - 849867303, - 815034111, - 497658126, - 386525753, - 179458548, - 102358168, - 4127308103, - 4073492988, - 1473411044, - 805072272, - 3724004880, - 3602108619, - 3585315836, - 3331487616, - 3261703164, - 3235459678, - 3085703811, - 3047649911, - 2357410109, - 2291766425, - 2071351379, - 1904128160, - 1738815671, - 1531216990, - 1465623797, - 1324351672, - 1220127364, - 1144188012, - 183103444, - 116093251, - 3900859293, - 3345856521, - 3691770462, - 3263841912, - 3198541202, - 3098991995, - 3682213068, - 2963184673, - 2864543087, - 2802261839, - 2790648021, - 900101778, - 2715304020, - 100979271, - 2709694527, - 2669086217, - 2531826164, - 2651956495, - 2552825357, - 2480811229, - 3138977758, - 2434845539, - 2066323109, - 1777640493, - 1758287856, - 1746004874, - 3945482286, - 3932146199, - 3129573055, - 3126269825, - 3716914380, - 985750227, - 1543672828, - 3189039115, - 1839499483, - 2696349144, - 1536350567, - 3971481069, - 3001444829, - 4028622909, - 215293834, - 213642219, - 153085016, - 1189681639, - 165054168, - 29517006, - 2614879967, - 27865391, - 1649426421, - 4239834800, - 1947620272, - 28782128, - 3207966516, - 3713290482, - 2042001863, - 2724166585, - 2356768706, - 1793544760, - 4092654294, - 2157103435, - 2087004702, - 2043873558, - 27177503, - 1033363654, - 4214779116, - 408465899, - 451264926, - 2377112119, - 1182296898, - 760554870, - 3566035349, - 2630220147, - 4192247221, - 1572088444, - 3538592682, - 769422756, - 1674803691, - 630964591, - 3458449569, - 565334834, - 137840602, - 3955205564, - 2009007457, - 1258105452, - 333554713, - 3923810593, - 126463145, - 3445109809, - 2966409025, - 2849215484, - 1910240213, - 3131890669, - 586244865, - 2320303498, - 3116932970, - 1317265040, - 2812498065, - 1466938734, - 4064212479, - 2613179511, - 2095546797, - 1671139745, - 2568512089, - 3695940604, - 1119069977, - 215027449, - 4123141705, - 3495546641, - 1978689945, - 3202324433, - 3783543823, - 2674422363, - 1352628475, - 1290956281, - 1894417995, - 740921498, - 4211577142, - 1033081852, - 3884846406, - 3253403867, - 2790624748, - 2538917932, - 2144962711, - 3323202731, - 4290024976, - 2564745684, - 2963744582, - 2443959748, - 354479447, - 750870327, - 1918481917, - 4032662899, - 3587381650, - 2414725163, - 1081611718, - 1625742020, - 2308565678, - 1871105284, - 2807907995, - 2121980967, - 1054641568, - 413918748, - 1917336504, - 1816558243, - 4130950286, - 1522979646, - 1669959736, - 1320550031, - 3104643263, - 3823959661, - 3525913657, - 3584683259, - 2918750759, - 3536390697, - 94303122, - 3296691317, - 801484894, - 2496463830, - 3266028549, - 3085157904, - 973908139, - 3787909072, - 3107413701, - 2378763734, - 920604853, - 2516325050, - 1838993983, - 1603937321, - 3183924418, - 1945006185, - 3982311384, - 2682510803, - 680388473, - 979993429, - 2405770322, - 461040879, - 2817579280, - 14113753, - 2894979602, - 168339452, - 951841533, - 4154758669, - 2637132451, - 3877583949, - 1949856502, - 922996215, - 3941049054, - 4182141402, - 2262220987, - 1957218950, - 2094550054, - 1846856260, - 3499234137, - 3086631065, - 3054834317, - 593829839, - 522971108, - 1162127370, - 4233562270, - 2780190687, - 1558345254, - 3716353056, - 3518630848, - 1158929937, - 2038205856, - 86116519, - 4185661467, - 975807626, - 3910458990, - 4124281183, - 3361419439, - 171334650, - 2590402790, - 2890570341, - 2303184249, - 385229009, - 1998433745, - 1717510093, - 4022124023, - 1429389803, - 945128292, - 904486530, - 3869890846, - 619875033, - 459968607, - 3743748793, - 359054425, - 1417363940, - 3653985133, - 255835594, - 1047011733, - 2763232252, - 1329499601, - 328661377, - 2162274327, - 2100532220, - 4255182614, - 4243119782, - 3982047273, - 4053789056, - 401211099, - 950731750, - 1319785741, - 32085358, - 3882634684, - 3117071189, - 3554463148, - 3570219049, - 3535289452, - 2314864456, - 3913885196, - 2763960513, - 1079999262, - 27130513, - 3033873113, - 2976581453, - 2598189097, - 595410904, - 1572834111, - 13319433, - 1084574846, - 2123388694, - 560078433, - 1679946323, - 3518703473, - 184634770, - 296981500, - 1646147798, - 455591063, - 1325348861, - 3224952074, - 1027242654, - 2281956980, - 4221373527, - 1289566249, - 4044928561, - 882718761, - 1510333659, - 836581417, - 1901166356, - 2276405827, - 4052965752, - 1155765244, - 503145996, - 251209228, - 495107308, - 3944781937, - 37459569, - 4248015868, - 4198082194, - 1302400505, - 4106658327, - 680016782, - 2319227476, - 2738307068, - 3929248764, - 2850246066, - 1824526196, - 3912967080, - 3044723416, - 3133016299, - 2517964682, - 3647586740, - 3653838348, - 929101967, - 3571454885, - 2806296851, - 977312655, - 646282397, - 3448018532, - 824323032, - 204234270, - 1579585816, - 3712763835, - 1212872174, - 3953984401, - 3168953855, - 2944827576, - 1582841441, - 2796901051, - 3323682385, - 1317058015, - 2557550659, - 1620634991, - 2986830770, - 2490492987, - 1817271123, - 40653745, - 1696076631, - 2466126792, - 4169878842, - 3251128023, - 2444465148, - 678695941, - 2481746922, - 2836440943, - 774727851, - 2246405597, - 4028028350, - 2524697596, - 1977038330, - 2817823941, - 2219733501, - 688216667, - 3634598908, - 3232633974, - 2724625059, - 3269075805, - 3732640764, - 2263349224, - 1680746207, - 2414984922, - 2507457870, - 50998433, - 3092528578, - 3712946115, - 1543935193, - 807276090, - 1221183390, - 172029722, - 2122275289, - 3990925720, - 2261697609, - 2736881867, - 295017943, - 3278176820, - 3748965853, - 3174324790, - 1103903216, - 3184177968, - 1113409935, - 2299842241, - 2162986400, - 1538342947, - 4056442905, - 1631434666, - 205885885, - 1594733696, - 1955104493, - 1022309772, - 3820814597, - 993150979, - 1209418480, - 1784441183, - 3958731802, - 2250225826, - 3065160070, - 2024071551, - 107497541, - 628544021, - 2732195517, - 4241486415, - 3969279737, - 870594305, - 2916400082, - 1193734351, - 3202349435, - 3831290364, - 3282979782, - 3928764629, - 1308462133, - 3216471040, - 2433519008, - 2022961611, - 3604842236, - 3374978006, - 2855895374, - 3496407048, - 1482251215, - 3994511488, - 2997832431, - 1132589448, - 1348149915, - 2092468906, - 2451531615, - 779021139, - 3730093054, - 3413713311, - 1022915255, - 2204920111, - 2660843182, - 1080545747, - 1642805350, - 1766422419, - 4141567741, - 1558990974, - 4185590212, - 2841468319, - 701281393, - 3325419312, - 451957774, - 357505993, - 1156369516, - 3187387500, - 2259467579, - 2678954464, - 3154597438, - 543558236, - 2359973133, - 1990431740, - 2705477184, - 1041368449, - 3122368657, - 3181646225, - 1094423548, - 2955375511, - 2888125966, - 153013225, - 2936040203, - 1758530522, - 573901046, - 3030911670, - 1675922848, - 4235213885, - 4091916710, - 2633682514, - 4254584852, - 2328748202, - 3357301402, - 3877813395, - 2004567202, - 2496297824, - 3334207724, - 1600149091, - 293528591, - 1782996825, - 3757282300, - 1107206446, - 1092948665, - 1797960910, - 1206726575, - 1496351055, - 3021406120, - 99347751, - 3797204453, - 1468919488, - 797415788, - 1314843976, - 2934934694, - 490769168, - 1474506522, - 3811268385, - 864295921, - 3081676220, - 151810803, - 2588618056, - 2998120306, - 416853049, - 3495967422, - 3233393284, - 508007510, - 759277550, - 1971252067, - 869050696, - 810488476, - 745556697, - 789872778, - 3362723943, - 1617826947, - 3260309823, - 2197904616, - 1199157863, - 1643868273, - 2430404313, - 321630747, - 2503194620, - 3194725903, - 2881225774, - 3997952447, - 1389644742, - 2713718873, - 3585511591, - 1684282922, - 3366848728, - 284226441, - 1541020250, - 4018237905, - 1369578001, - 2424848261, - 2654325647, - 1626224034, - 1081536219, - 309040124, - 123060826, - 3997038726, - 1670691893, - 1543280290, - 443347828, - 1776629361, - 3118548424, - 478440524, - 679771963, - 3729929345, - 4244789645, - 2366506734, - 2838165089, - 1619778288, - 1313182965, - 3240680626, - 1323407757, - 883854656, - 2194691858, - 15502752, - 3760372982, - 1366337101, - 3656163446, - 295018543, - 825595257, - 57149555, - 2563789125, - 2353194283, - 2636942752, - 4026740269, - 3570411982, - 123108003, - 3782362128, - 1280126114, - 1410849099, - 4228502127, - 3609540589, - 3365041621, - 269823086, - 348988933, - 1636389511, - 2936586309, - 2761603302, - 2318200267, - 449954059, - 2895413148, - 1755165354, - 4274214049, - 778500192, - 3345707173, - 3732136051, - 721450866, - 1600392975, - 2466255445, - 4050155669, - 3541895912, - 1139547465, - 394654115, - 1380991098, - 3516240523, - 2234361374, - 1094817798, - 744817486, - 3564402361, - 1452222566, - 1851510470, - 3619787319, - 4265894873, - 216945449, - 3061690214, - 2910557180, - 255227811, - 4167600590, - 1587209598, - 3157581152, - 3184381405, - 2572638469, - 615748604, - 2532518896, - 1774874546, - 599185303, - 1561718045, - 1742737136, - 1674464100, - 3136865519, - 706016261, - 2793529873, - 3504981554, - 4155122613, - 2080953106, - 1104362365, - 2879917501, - 850497536, - 1392080469, - 1287937401, - 718877177, - 1917966999, - 1822823090, - 3701632935, - 3591222197, - 2817335337, - 1941148668, - 3110479131, - 3289213933, - 583624926, - 468372467, - 1633850097, - 2110223508, - 898191441, - 112745085, - 4018820793, - 3085119011, - 2919626325, - 3094857332, - 2348201466, - 2192810893, - 4163160985, - 1269075360, - 3952316364, - 2881886868, - 439764402, - 1584774136, - 169674806, - 3759072440, - 102542696, - 2996180816, - 804899022, - 1015552308, - 963902061, - 3504158761, - 2002490364, - 2806716850, - 265778447, - 4083122425, - 181902171, - 1238120570, - 75986790, - 1265796414, - 899570100, - 2988365258, - 3655201337, - 3654061472, - 3061856840, - 1077859090, - 615341051, - 3678875745, - 3349230696, - 3647606635, - 2549309392, - 1508570930, - 1766401548, - 1448448666, - 1499923635, - 2882994691, - 3674863070, - 3056042030, - 4240893633, - 1395113939, - 2964622752, - 1951208733, - 3536941067, - 4176581069, - 1203545131, - 3092754101, - 246375791, - 2736026107, - 1069781886, - 3687777340, - 1564342316, - 535067202, - 1395923345, - 3240977890, - 1447712361, - 2602027658, - 718301639, - 3123244280, - 1032593647, - 2840366496, - 2680819379, - 3839389658, - 277023757, - 1172110445, - 1755648697, - 2472176885, - 223800276, - 625975427, - 976111724, - 4145966869, - 2789375411, - 618087261, - 249378857, - 4058280485, - 827698488, - 1558001705, - 3561482820, - 2562485583, - 4243138030, - 615982737, - 1220643281, - 150685616, - 3091876332, - 1040775722, - 669982125, - 4116080964, - 3582002820, - 910398460, - 1036475267, - 3800912395, - 146392076, - 1686512349, - 2326636627, - 2839816704, - 3502816184, - 226836633, - 3953733490, - 257136089, - 819503463, - 2863084840, - 1949759310, - 210754155, - 1367301635, - 3822983876, - 4273793488, - 3635397748, - 3930494584, - 3127921440, - 3167253437, - 3868239231, - 1859128680, - 3480031018, - 3810805277, - 2677252364, - 156014509, - 3627739127, - 2321729979, - 1146476634, - 4039938779, - 1964254745, - 2055836767, - 119981689, - 2629265310, - 2448331885, - 3737376990, - 144116905, - 2272221101, - 2197874825, - 1277245109, - 2503770904, - 360730278, - 3489360962, - 1166917451, - 707478563, - 4155586396, - 162255877, - 347505241, - 4215670524, - 3187066832, - 2399809085, - 2754074729, - 4060703604, - 628331516, - 1304296041, - 616435646, - 4080527786, - 1443829854, - 2512398201, - 708736129, - 13107491, - 3794803132, - 2049792025, - 2455417440, - 3367313400, - 3357250579, - 3694383800, - 2339901602, - 3242843022, - 2282454607, - 1243764146, - 835458563, - 1297706389, - 464259778, - 1766994680, - 1294403159, - 2568098594, - 3107165180, - 4040340620, - 3352361837, - 1031290113, - 2903897222, - 1677700667, - 3160388974, - 107544081, - 3044188332, - 2285081596, - 2835131395, - 2984459037, - 4174489262, - 1236389532, - 2938237924, - 321459212, - 3407526215, - 300939750, - 3441531391, - 2909957084, - 3192069648, - 1849065716, - 2524531022, - 505940164, - 4121643374, - 3774892253, - 3197739982, - 2161102232, - 2715370488, - 1992893964, - 1781864804, - 587888644, - 1039111164, - 4237497041, - 451382997, - 969500141, - 1415510495, - 3743398113, - 3027538652, - 2525173102, - 1708264968, - 3366040354, - 1100599986, - 188347929, - 2597020383, - 2705434194, - 2593884753, - 3472123498, - 2975894973, - 3152745753, - 1154919607, - 1930923350, - 3287039847, - 1372881231, - 2280400314, - 3369343584, - 2351620600, - 2645135839, - 2752766693, - 1471851763, - 1989520052, - 1141965917, - 1503477720, - 653708953, - 1765126703, - 2432827426, - 95470391, - 2567901801, - 2589449658, - 4218799564, - 3249265647, - 3673811979, - 210116709, - 1593584949, - 1791352211, - 3457985288, - 3345288309, - 531559080, - 2491124112, - 3410158390, - 4224872590, - 3705139860, - 162608772, - 4258229445, - 925559698, - 3928842969, - 4253051659, - 3633746133, - 3867307935, - 3560665067, - 798915737, - 2945369269, - 2677264274, - 2278571792, - 177111659, - 85880059, - 1297165140, - 1630583316, - 2232491275, - 1848784182, - 2487708241, - 626480004, - 3427283542, - 2108571893, - 304448521, - 3332104493, - 2244470522, - 436416061, - 221900294, - 1502470404, - 3552593177, - 440421571, - 450406196, - 503094540, - 3836822275, - 2708915136, - 3750617468, - 1119744229, - 3614752756, - 921246433, - 2285438321, - 626892406, - 2362972044, - 72782198, - 2929019254, - 2795773560, - 907126242, - 155458798, - 2798552666, - 1404739463, - 4285652249, - 1998444837, - 908777857, - 872544165, - 910429472, - 135486769, - 3457269042, - 426360862, - 1725011064, - 296836635, - 1322549027, - 2044728014, - 1530183840, - 529742207, - 4272200782, - 1341516288, - 2608484640, - 41739659, - 3260579369, - 2745872368, - 2894051250, - 862784766, - 3077271274, - 3094180193, - 3619626927, - 3745223676, - 2976066508, - 2854085372, - 2959147533, - 3266548732, - 1776526161, - 3712296962, - 1955871800, - 2580096524, - 2507709226, - 3564865233, - 948086521, - 1548254487, - 142465290, - 1472185378, - 1459457331, - 2274226560, - 3153451899, - 492958971, - 3563213618, - 1285705317, - 410274915, - 3710645347, - 1309728002, - 2119793999, - 1343794461, - 4024173916, - 2383939514, - 955476870, - 2698156268, - 35240468, - 2655147757, - 3764205609, - 3802564010, - 170690025, - 2311941439, - 3181546731, - 3866587616, - 3648138580, - 93914936, - 170378107, - 2120623674, - 1064945649, - 1618754372, - 244668133, - 247698428, - 3669223677, - 470277359, - 1781765116, - 1691572958, - 1373856501, - 2668769415, - 1087394637, - 1009983433, - 2180701723, - 4008405264, - 2831059514, - 2645120714, - 2649103430, - 2664825925, - 790502615, - 1739837626, - 2293247016, - 1784648440, - 1887808856, - 1788504755, - 112452386, - 1979978194, - 3462674048, - 2170273742, - 538168945, - 753954113, - 374731234, - 3715846592, - 1962971231, - 1860649552, - 1378082995, - 665789406, - 1717555224, - 139011596, - 1375043498, - 1618544981, - 1889460471, - 2262321736, - 1788301425, - 1652168174, - 2668680621, - 2636946065, - 2856623532, - 2759951687, - 959681532, - 3209399506, - 3055195668, - 1227221002, - 508217552, - 3289969989, - 243178923, - 2956189845, - 3075866530, - 2274779301, - 3940720663, - 3998230222, - 1178317551, - 4016096296, - 1545450160, - 2842919847, - 314809953, - 2952850186, - 3747079365, - 4147239510, - 169135842, - 1332643570, - 2994529201, - 973521782, - 1584369690, - 1043738701, - 2851900832, - 290391815, - 283209196, - 2468230023, - 1164221089, - 1991787192, - 3358097187, - 51041423, - 52882140, - 2339018837, - 2053214130, - 3757479030, - 158160339, - 853200279, - 1986584654, - 438318340, - 827246872, - 3299488628, - 2924263085, - 3472029049, - 2736844435, - 677668732, - 604894932, - 1158021131, - 1400019344, - 2268204687, - 1450415100, - 3854557817, - 1543646433, - 1278448636, - 342615870, - 1554194368, - 3080024605, - 3423702268, - 1675764636, - 1622381564, - 2078849875, - 2113115132, - 1380160211, - 3132876285, - 125015036, - 269576093, - 94145952, - 2777172031, - 2683080096, - 3812456892, - 488500848, - 3270430997, - 2895151306, - 116376005, - 400248103, - 406044930, - 1616846013, - 10142671, - 763027711, - 225200779, - 1062250709, - 2013867381, - 2113506324, - 1692932387, - 1827244161, - 3124618210, - 2096472894, - 2924146124, - 2128251367, - 2433358586, - 1939359710, - 2593325766, - 2879917723, - 694743357, - 2902069960, - 220008971, - 3090408469, - 917019124, - 1705716306, - 3263901372, - 3347863687, - 3447882276, - 1661163736, - 3617689692, - 3928555688, - 1057578789, - 435256475, - 4101009465, - 1941403425, - 198967948, - 3733675151, - 2043684541, - 3517169445, - 2226776400, - 2853403709, - 529383565, - 2807448986, - 4234287173, - 1019457583, - 1022544883, - 2493146691, - 1054461787, - 1008886329, - 1136775085, - 1191015885, - 1196280518, - 1979847999, - 50385656, - 1918742169, - 3999472204, - 3697687030, - 2220475432, - 2358141757, - 2360004627, - 4245257809, - 236660303, - 429277936, - 342159236, - 2622612602, - 371428004, - 373079619, - 643418617, - 2095027856, - 1071164424, - 1136911283, - 1548491889, - 2169307971, - 375530199, - 1510422521, - 3151638847, - 1698730948, - 2231688008, - 2604576561, - 2771938750, - 2996594997, - 289648234, - 348584153, - 2748350697, - 2926633629, - 2123683379, - 369686787, - 742917749, - 3538158875, - 2937761472, - 1545298048, - 1321616112, - 2855506940, - 900522183, - 1578775276, - 2217833278, - 2012838864, - 3753486980, - 2839765116, - 2464905186, - 2621255555, - 1305703280, - 861753115, - 3319278167, - 3063300848, - 149720480, - 1082941229, - 3337532056, - 2248357849, - 3675926744, - 1508550646, - 2289803479, - 3456899824, - 3931641900, - 3970432934, - 3419674548, - 1093210099, - 456043370, - 848380423, - 1287304304, - 1526654696, - 2055664760, - 1373166395, - 4291477370, - 2195550588, - 2847102741, - 3399062057, - 1641565587, - 2888753905, - 3579593979, - 3653059026, - 3757851979, - 2922615804, - 2919796598, - 1553476262, - 2566666743, - 3759503594, - 550831114, - 3761155209, - 3762806824, - 3902853271, - 4140081844, - 14244860, - 3847846774, - 150820676, - 1278818058, - 850592577, - 1206571206, - 1734446471, - 2117320444, - 1382106590, - 2436009347, - 2118972059, - 2951272396, - 36096192, - 117998987, - 473485679, - 2244928358, - 476788909, - 3489269251, - 610429940, - 480092139, - 481743754, - 871966503, - 918189168, - 601656217, - 933769938, - 939671928, - 1799299383, - 3312467582, - 1149665466, - 3006548167, - 1310740861, - 3602693817, - 1461645203, - 3367691969, - 1800404122, - 3486057732, - 1862284649, - 2076833303, - 2213411495, - 2805256437, - 3927915220, - 3000904950, - 2094647776, - 3333131702, - 1315613425, - 3752211294, - 603915804, - 3505028338, - 663258455, - 3322500634, - 1612225949, - 3606320646, - 157110413, - 1352397672, - 3861006967, - 452208841, - 18776483, - 1058429216, - 37009196, - 564884461, - 876864198, - 2952260510, - 2860348412, - 928261291, - 1164724902, - 2775815164, - 1332774287, - 780957373, - 939415664, - 1513770932, - 788046331, - 1692600167, - 4069810315, - 673708384, - 4024252457, - 1932614728, - 2148510256, - 3131224670, - 2388524817, - 2460489993, - 2676385521, - 826214242, - 3692647551, - 3063508455, - 3071766530, - 2063832060, - 1525861001, - 3073418145, - 837715723, - 3075069760, - 3076721375, - 3078372990, - 983243705, - 3083327835, - 171307615, - 1824016656, - 3084979450, - 1310404265, - 1775308984, - 3114708520, - 3116360135, - 3121314980, - 3134527900, - 1691646294, - 2804281092, - 97231530, - 3136179515, - 3204260786, - 3276225962, - 1220749418, - 3588205699, - 3874089391, - 4044115788, - 3268751013, - 743407979, - 166253838, - 1356063462, - 1368383673, - 2279700640, - 2130747644, - 3945795573, - 2780898906, - 3635542517, - 425022309, - 517919178, - 4061558677, - 2190437442, - 543621065, - 753756604, - 2500819054, - 1004589179, - 1165671422, - 30433743, - 3444275347, - 1335363438, - 1913735398, - 1265998516, - 3829325073, - 3662767579, - 463084678, - 1351676723, - 1391866096, - 3398925952, - 1631216488, - 815757910, - 1915438939, - 2427834344, - 1445161581, - 1890300748, - 2864863800, - 1961990747, - 575205902, - 2037710159, - 2037814253, - 617312262, - 3732916270, - 783918780, - 2257843797, - 2096388952, - 2338272340, - 1434223270, - 578132535, - 1980341560, - 1002144380, - 3244716568, - 4258414038, - 3271748023, - 3304438238, - 3717523241, - 3370185097, - 3435931956, - 1957265068, - 3602522282, - 2547657777, - 439998433, - 3838648480, - 3913593633, - 3989799199, - 906176560, - 1894133125, - 4046301857, - 4242327928, - 630592085, - 2693892518, - 4292991777, - 545678922, - 125792961, - 3015046341, - 132755933, - 2615111110, - 1570165302, - 1440646342, - 436066778, - 565233904, - 600906020, - 602222721, - 3951925872, - 1496901698, - 1522901980, - 2785441472, - 3041450802, - 1637661947, - 2127660080, - 3487022798, - 2269114589, - 1314834580, - 2315690100, - 3817149113, - 4091670162, - 1431749301, - 1858116930, - 2213946343, - 2225172640, - 2263866576, - 2727022058, - 2752967311, - 2864705739, - 3052439312, - 3510257966, - 2614053317, - 3297860332, - 3670298840, - 3732709413, - 3788324110, - 4098876453, - 4290374884, - 1623013158, - 3381478137, - 17185761, - 3931288033, - 2890638791, - 330388453, - 346929928, - 2022347217, - 4083347580, - 533021259, - 564302770, - 1917602962, - 680157484, - 3264086791, - 3727034815, - 798549062, - 3068463300, - 669812542, - 1965902997, - 2311072371, - 3079287749, - 2542834724, - 1587730355, - 2558655180, - 1838763297, - 4172568578, - 2160380860, - 2950446516, - 1830851200, - 3214537066, - 3234673086, - 3652695478, - 3103302036, - 3465954368, - 4180570743, - 3534518722, - 371186900, - 4091394002, - 1013756921, - 443558693, - 591140762, - 656610661, - 2064733527, - 3808408202, - 983299427, - 4217306348, - 1164218401, - 2036361232, - 3237903670, - 2970183398, - 2293637521, - 135920445, - 1596005536, - 868652905, - 1191735827, - 3987079331, - 1365842164, - 1508074873, - 1642818143, - 3436143898, - 4105051793, - 1863199739, - 3425841570, - 1070791291, - 2135340676, - 2639720559, - 3364388739, - 3797761273, - 2092100514, - 2098706974, - 2329992200, - 414444763, - 2759250216, - 2913136690, - 3012980338, - 3327770644, - 4128942283, - 3362344229, - 161668409, - 3401762422, - 2852854788, - 4237092412, - 1245448751, - 3702405475, - 918849409, - 3829682756, - 1612361408, - 255302575, - 414620710, - 386293029, - 618761615, - 686024761, - 744062262, - 1502028603, - 1543798545, - 1641415225, - 1548121999, - 2257971049, - 2124837447, - 878733439, - 2340670452, - 2674090849, - 3118011750, - 2816338013, - 178571546, - 2841008029, - 3249261197, - 370232173, - 4092487128, - 3787567939, - 3898287302, - 4142016703, - 4285779501, - 30663912, - 151672195, - 180913835, - 3534235309, - 34183582, - 4083161638, - 651464351, - 1410311776, - 371621315, - 421602934, - 458937500, - 2710583246, - 712168842, - 730943059, - 1519723107, - 875212982, - 1247793383, - 4217322139, - 989813600, - 1057606514, - 3764662384, - 1443547269, - 3066811685, - 3598957382, - 1791427568, - 1171541710, - 3930727258, - 1473799048, - 1296054774, - 1747355813, - 765238787, - 2023008475, - 1190147516, - 2344328209, - 2495155989, - 2577859137, - 2857814560, - 3127329373, - 3296722158, - 2773229577, - 3376009661, - 3450001968, - 920941800, - 3526837441, - 3858973601, - 1702168830, - 4088613871, - 1464587427, - 223310468, - 388034151, - 2346547796, - 1663234329, - 1750829822, - 1967643923, - 2881302403, - 2278706468, - 2326990117, - 2511346984, - 3088785099, - 2616085763, - 3027500544, - 3417583519, - 4178218543, - 1412908157, - 797934924, - 3533637837, - 1449907751, - 3362830643, - 1451831482, - 2637935122, - 3070114915, - 3023287679, - 551924251, - 1669930486, - 46736908, - 2870852215, - 1120149824, - 2923708820, - 3887377256, - 3464197236, - 4241374559, - 527665290, - 996663016, - 885020215, - 1763758554, - 3059119137, - 2555315060, - 2762094724, - 2530899578, - 2770161927, - 2262137600, - 3547456240, - 858902117, - 1140367371, - 1215030156, - 443490822, - 294390719, - 3032677281, - 1917451875, - 4184019303, - 3277199633, - 1271484400, - 1297294717, - 3560552546, - 171494987, - 195244192, - 3002890475, - 1811839150, - 265392489, - 1461398554, - 3205759417, - 333855951, - 529068443, - 660038281, - 557400685, - 663341511, - 930804377, - 1922045399, - 716890919, - 162167595, - 1654776395, - 1779143013, - 1123617794, - 2984325996, - 1162789888, - 1318479490, - 1235468610, - 3561562003, - 1486207619, - 1551372768, - 1850331254, - 3255947500, - 1037370721, - 1989327599, - 2137526937, - 835638766, - 2269130237, - 1962162282, - 3244209297, - 2330636993, - 3095831808, - 1396344138, - 2603020391, - 3434076295, - 3280064277, - 2656211099, - 3335250889, - 2550961007, - 3510242586, - 3536471583, - 3950980241, - 4033586023, - 117250846, - 3088282680, - 4041974454, - 4244540017, - 1167160774, - 899320334, - 1200870684, - 1752686878, - 1906988301, - 3804101227, - 2575525651, - 2919787747, - 3508792859, - 3548535223, - 3783756895, - 3797961332, - 4043078107, - 3115038057, - 2313593054, - 49456560, - 592180731, - 1051471757, - 1097775533, - 706238670, - 877895868, - 1173092699, - 1461897718, - 1767704813, - 1770165905, - 1923453688, - 2212501241, - 2305269460, - 2488410748, - 3782099915, - 2844616706, - 3383007207, - 3392887901, - 504514034, - 3765247327, - 1000070091, - 3727494858, - 3657635382, - 3839047923, - 3886529747, - 4069720347, - 4164704452, - 342197850, - 3540244297, - 2513230733, - 4117704995, - 3367298820, - 2680283743, - 3119663365, - 3697738938, - 545363837, - 163402553, - 5908395, - 129135650, - 2289183712, - 200922300, - 761731755, - 894529125, - 1086964761, - 1168927492, - 2100052708, - 2438466459, - 3390051757, - 2498042266, - 2557754096, - 2600961503, - 487719832, - 703543228, - 2726532092, - 4199470013, - 3142155593, - 2550501832, - 4076840151, - 200553094, - 380957745, - 572905105, - 462664429, - 1466804584, - 330249537, - 2605012269, - 491456522, - 4126287524, - 502863753, - 952536201, - 3510682541, - 1137442027, - 1665981878, - 1761469971, - 3085467405, - 2045285083, - 796985462, - 3433956341, - 2217966239, - 2183547611, - 2279273489, - 1916983087, - 2348676810, - 2403632109, - 2409539315, - 545986953, - 176166202, - 2477389837, - 2573160348, - 2796513469, - 3972309363, - 528662843, - 1038982109, - 1125913837, - 1318081294, - 1417425499, - }; - return descriptors_with_coding_scheme; -} diff --git a/3rdparty/spirv-tools/tools/fuzz/fuzz.cpp b/3rdparty/spirv-tools/tools/fuzz/fuzz.cpp new file mode 100644 index 000000000..2a31a2009 --- /dev/null +++ b/3rdparty/spirv-tools/tools/fuzz/fuzz.cpp @@ -0,0 +1,255 @@ +// 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 +#include +#include +#include +#include +#include + +#include "source/fuzz/fuzzer.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "source/opt/log.h" +#include "source/spirv_fuzzer_options.h" +#include "source/util/string_utils.h" +#include "tools/io.h" +#include "tools/util/cli_consumer.h" + +namespace { + +// Status and actions to perform after parsing command-line arguments. +enum class FuzzActions { CONTINUE, STOP }; + +struct FuzzStatus { + FuzzActions action; + int code; +}; + +void PrintUsage(const char* program) { + // NOTE: Please maintain flags in lexicographical order. + printf( + R"(%s - Fuzzes an equivalent SPIR-V binary based on a given binary. + +USAGE: %s [options] -o + +The SPIR-V binary is read from , which must have extension .spv. If + is also present, facts about the SPIR-V binary are read from this +file. + +The transformed SPIR-V binary is written to . Human-readable and +binary representations of the transformations that were applied to obtain this +binary are written to and , respectively. + +NOTE: The fuzzer is a work in progress. + +Options (in lexicographical order): + + -h, --help + Print this help. + --seed + Unsigned 32-bit integer seed to control random number + generation. + --version + Display fuzzer version information. + +)", + program, program); +} + +// Message consumer for this tool. Used to emit diagnostics during +// initialization and setup. Note that |source| and |position| are irrelevant +// here because we are still not processing a SPIR-V input file. +void FuzzDiagnostic(spv_message_level_t level, const char* /*source*/, + const spv_position_t& /*position*/, const char* message) { + if (level == SPV_MSG_ERROR) { + fprintf(stderr, "error: "); + } + 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, + spvtools::FuzzerOptions* fuzzer_options) { + uint32_t positional_arg_index = 0; + + for (int argi = 1; argi < argc; ++argi) { + const char* cur_arg = argv[argi]; + if ('-' == cur_arg[0]) { + if (0 == strcmp(cur_arg, "--version")) { + spvtools::Logf(FuzzDiagnostic, SPV_MSG_INFO, nullptr, {}, "%s\n", + spvSoftwareVersionDetailsString()); + return {FuzzActions::STOP, 0}; + } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { + PrintUsage(argv[0]); + return {FuzzActions::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 {FuzzActions::STOP, 1}; + } + } else if (0 == strncmp(cur_arg, "--seed=", sizeof("--seed=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + char* end = nullptr; + errno = 0; + const auto seed = + static_cast(strtol(split_flag.second.c_str(), &end, 10)); + assert(end != split_flag.second.c_str() && errno == 0); + fuzzer_options->set_random_seed(seed); + } 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. + PrintUsage(argv[0]); + return {FuzzActions::STOP, 0}; + } + } else if (positional_arg_index == 0) { + // Binary input file name + assert(in_binary_file->empty()); + *in_binary_file = std::string(cur_arg); + positional_arg_index++; + } else { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "Too many positional arguments specified"); + return {FuzzActions::STOP, 1}; + } + } + + if (in_binary_file->empty()) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "No input file specified"); + 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)) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "Output filename must have extension .spv"); + return {FuzzActions::STOP, 1}; + } + + return {FuzzActions::CONTINUE, 0}; +} + +} // namespace + +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; + + spv_target_env target_env = kDefaultEnvironment; + spvtools::FuzzerOptions fuzzer_options; + + FuzzStatus status = ParseFlags(argc, argv, &in_binary_file, &out_binary_file, + &fuzzer_options); + + if (status.action == FuzzActions::STOP) { + return status.code; + } + + std::vector binary_in; + if (!ReadFile(in_binary_file.c_str(), "rb", &binary_in)) { + return 1; + } + + 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()) + + ".json"; + std::ifstream facts_input(in_facts_file); + if (facts_input) { + std::string facts_json_string((std::istreambuf_iterator(facts_input)), + std::istreambuf_iterator()); + facts_input.close(); + if (google::protobuf::util::Status::OK != + google::protobuf::util::JsonStringToMessage(facts_json_string, + &initial_facts)) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error reading facts data"); + return 1; + } + } + + std::vector binary_out; + spvtools::fuzz::protobufs::TransformationSequence transformations_applied; + + spvtools::fuzz::Fuzzer fuzzer(target_env); + fuzzer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + auto fuzz_result_status = + fuzzer.Run(binary_in, initial_facts, &binary_out, + &transformations_applied, fuzzer_options); + if (fuzz_result_status != + spvtools::fuzz::Fuzzer::FuzzerResultStatus::kComplete) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error running fuzzer"); + return 1; + } + + if (!WriteFile(out_binary_file.c_str(), "wb", binary_out.data(), + binary_out.size())) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error writing out binary"); + 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; + } + + 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 + ".json"); + transformations_json_file << json_string; + transformations_json_file.close(); + + return 0; +} diff --git a/3rdparty/spirv-tools/tools/io.h b/3rdparty/spirv-tools/tools/io.h index aaf8fcdd2..97a31636b 100644 --- a/3rdparty/spirv-tools/tools/io.h +++ b/3rdparty/spirv-tools/tools/io.h @@ -37,6 +37,7 @@ bool ReadFile(const char* filename, const char* mode, std::vector* data) { if (ftell(fp) == -1L) { if (ferror(fp)) { fprintf(stderr, "error: error reading file '%s'\n", filename); + if (use_file) fclose(fp); return false; } } else { @@ -45,6 +46,7 @@ bool ReadFile(const char* filename, const char* mode, std::vector* data) { stderr, "error: file size should be a multiple of %zd; file '%s' corrupt\n", sizeof(T), filename); + if (use_file) fclose(fp); return false; } } @@ -69,6 +71,7 @@ bool WriteFile(const char* filename, const char* mode, const T* data, size_t written = fwrite(data, sizeof(T), count, fp); if (count != written) { fprintf(stderr, "error: could not write to file '%s'\n", filename); + if (!use_stdout) fclose(fp); return false; } if (!use_stdout) fclose(fp); diff --git a/3rdparty/spirv-tools/tools/opt/opt.cpp b/3rdparty/spirv-tools/tools/opt/opt.cpp index cc4954011..585952b62 100644 --- a/3rdparty/spirv-tools/tools/opt/opt.cpp +++ b/3rdparty/spirv-tools/tools/opt/opt.cpp @@ -140,6 +140,12 @@ Options (in lexicographical order):)", another. It will only propagate an array if the source is never written to, and the only store to the target is the copy.)"); printf(R"( + --decompose-initialized-variables + Decomposes initialized variable declarations into a declaration + followed by a store of the initial value. This is done to work + around known issues with some Vulkan drivers for initialize + variables.)"); + printf(R"( --eliminate-common-uniform Perform load/load elimination for duplicate uniform values. Converts any constant index access chain uniform loads into @@ -228,6 +234,11 @@ Options (in lexicographical order):)", option --relax-logical-pointer to the validator.)", GetLegalizationPasses().c_str()); printf(R"( + --legalize-vector-shuffle + Converts any usages of 0xFFFFFFFF for the literals in + OpVectorShuffle to a literal 0. This is done since 0xFFFFFFFF is + forbidden in WebGPU.)"); + printf(R"( --local-redundancy-elimination Looks for instructions in the same basic block that compute the same value, and deletes the redundant ones.)"); @@ -398,6 +409,13 @@ Options (in lexicographical order):)", Will simplify all instructions in the function as much as possible.)"); printf(R"( + --split-invalid-unreachable + Attempts to legalize for WebGPU cases where an unreachable + merge-block is also a continue-target by splitting it into two + seperate blocks. There exist legal, for Vulkan, instances of this + pattern that cannot be converted into legal WebGPU, so this + conversion may not succeed.)"); + printf(R"( --skip-validation Will not validate the SPIR-V before optimizing. If the SPIR-V is invalid, the optimizer may fail or generate incorrect code. diff --git a/3rdparty/spirv-tools/tools/stats/spirv_stats.cpp b/3rdparty/spirv-tools/tools/stats/spirv_stats.cpp deleted file mode 100644 index 609a6c972..000000000 --- a/3rdparty/spirv-tools/tools/stats/spirv_stats.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2017 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 "tools/stats/spirv_stats.h" - -#include - -#include -#include -#include - -#include "source/diagnostic.h" -#include "source/enum_string_mapping.h" -#include "source/extensions.h" -#include "source/id_descriptor.h" -#include "source/instruction.h" -#include "source/opcode.h" -#include "source/operand.h" -#include "source/val/instruction.h" -#include "source/val/validate.h" -#include "source/val/validation_state.h" -#include "spirv-tools/libspirv.h" - -namespace spvtools { -namespace stats { -namespace { - -// Helper class for stats aggregation. Receives as in/out parameter. -// Constructs ValidationState and updates it by running validator for each -// instruction. -class StatsAggregator { - public: - StatsAggregator(SpirvStats* in_out_stats, const val::ValidationState_t* state) - : stats_(in_out_stats), vstate_(state) {} - - // Processes the instructions to collect stats. - void aggregate() { - const auto& instructions = vstate_->ordered_instructions(); - - ++stats_->version_hist[vstate_->version()]; - ++stats_->generator_hist[vstate_->generator()]; - - for (size_t i = 0; i < instructions.size(); ++i) { - const auto& inst = instructions[i]; - - ProcessOpcode(&inst, i); - ProcessCapability(&inst); - ProcessExtension(&inst); - ProcessConstant(&inst); - } - } - - // Collects OpCapability statistics. - void ProcessCapability(const val::Instruction* inst) { - if (inst->opcode() != SpvOpCapability) return; - const uint32_t capability = inst->word(inst->operands()[0].offset); - ++stats_->capability_hist[capability]; - } - - // Collects OpExtension statistics. - void ProcessExtension(const val::Instruction* inst) { - if (inst->opcode() != SpvOpExtension) return; - const std::string extension = GetExtensionString(&inst->c_inst()); - ++stats_->extension_hist[extension]; - } - - // Collects OpCode statistics. - void ProcessOpcode(const val::Instruction* inst, size_t idx) { - const SpvOp opcode = inst->opcode(); - ++stats_->opcode_hist[opcode]; - - if (idx == 0) return; - - --idx; - - const auto& instructions = vstate_->ordered_instructions(); - - auto step_it = stats_->opcode_markov_hist.begin(); - for (; step_it != stats_->opcode_markov_hist.end(); --idx, ++step_it) { - auto& hist = (*step_it)[instructions[idx].opcode()]; - ++hist[opcode]; - - if (idx == 0) break; - } - } - - // Collects OpConstant statistics. - void ProcessConstant(const val::Instruction* inst) { - if (inst->opcode() != SpvOpConstant) return; - - const uint32_t type_id = inst->GetOperandAs(0); - const auto type_decl_it = vstate_->all_definitions().find(type_id); - assert(type_decl_it != vstate_->all_definitions().end()); - - const val::Instruction& type_decl_inst = *type_decl_it->second; - const SpvOp type_op = type_decl_inst.opcode(); - if (type_op == SpvOpTypeInt) { - const uint32_t bit_width = type_decl_inst.GetOperandAs(1); - const uint32_t is_signed = type_decl_inst.GetOperandAs(2); - assert(is_signed == 0 || is_signed == 1); - if (bit_width == 16) { - if (is_signed) - ++stats_->s16_constant_hist[inst->GetOperandAs(2)]; - else - ++stats_->u16_constant_hist[inst->GetOperandAs(2)]; - } else if (bit_width == 32) { - if (is_signed) - ++stats_->s32_constant_hist[inst->GetOperandAs(2)]; - else - ++stats_->u32_constant_hist[inst->GetOperandAs(2)]; - } else if (bit_width == 64) { - if (is_signed) - ++stats_->s64_constant_hist[inst->GetOperandAs(2)]; - else - ++stats_->u64_constant_hist[inst->GetOperandAs(2)]; - } else { - assert(false && "TypeInt bit width is not 16, 32 or 64"); - } - } else if (type_op == SpvOpTypeFloat) { - const uint32_t bit_width = type_decl_inst.GetOperandAs(1); - if (bit_width == 32) { - ++stats_->f32_constant_hist[inst->GetOperandAs(2)]; - } else if (bit_width == 64) { - ++stats_->f64_constant_hist[inst->GetOperandAs(2)]; - } else { - assert(bit_width == 16); - } - } - } - - private: - SpirvStats* stats_; - const val::ValidationState_t* vstate_; - IdDescriptorCollection id_descriptors_; -}; - -} // namespace - -spv_result_t AggregateStats(const spv_context context, const uint32_t* words, - const size_t num_words, spv_diagnostic* pDiagnostic, - SpirvStats* stats) { - std::unique_ptr vstate; - spv_validator_options_t options; - spv_result_t result = ValidateBinaryAndKeepValidationState( - context, &options, words, num_words, pDiagnostic, &vstate); - if (result != SPV_SUCCESS) return result; - - StatsAggregator stats_aggregator(stats, vstate.get()); - stats_aggregator.aggregate(); - return SPV_SUCCESS; -} - -} // namespace stats -} // namespace spvtools diff --git a/3rdparty/spirv-tools/tools/stats/spirv_stats.h b/3rdparty/spirv-tools/tools/stats/spirv_stats.h deleted file mode 100644 index 757695775..000000000 --- a/3rdparty/spirv-tools/tools/stats/spirv_stats.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TOOLS_STATS_SPIRV_STATS_H_ -#define TOOLS_STATS_SPIRV_STATS_H_ - -#include -#include -#include -#include -#include - -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace stats { - -struct SpirvStats { - // Version histogram, version_word -> count. - std::unordered_map version_hist; - - // Generator histogram, generator_word -> count. - std::unordered_map generator_hist; - - // Capability histogram, SpvCapabilityXXX -> count. - std::unordered_map capability_hist; - - // Extension histogram, extension_string -> count. - std::unordered_map extension_hist; - - // Opcode histogram, SpvOpXXX -> count. - std::unordered_map opcode_hist; - - // OpConstant u16 histogram, value -> count. - std::unordered_map u16_constant_hist; - - // OpConstant u32 histogram, value -> count. - std::unordered_map u32_constant_hist; - - // OpConstant u64 histogram, value -> count. - std::unordered_map u64_constant_hist; - - // OpConstant s16 histogram, value -> count. - std::unordered_map s16_constant_hist; - - // OpConstant s32 histogram, value -> count. - std::unordered_map s32_constant_hist; - - // OpConstant s64 histogram, value -> count. - std::unordered_map s64_constant_hist; - - // OpConstant f32 histogram, value -> count. - std::unordered_map f32_constant_hist; - - // OpConstant f64 histogram, value -> count. - std::unordered_map f64_constant_hist; - - // Used to collect statistics on opcodes triggering other opcodes. - // Container scheme: gap between instructions -> cue opcode -> later opcode - // -> count. - // For example opcode_markov_hist[2][OpFMul][OpFAdd] corresponds to - // the number of times an OpMul appears, followed by 2 other instructions, - // followed by OpFAdd. - // opcode_markov_hist[0][OpFMul][OpFAdd] corresponds to how many times - // OpFMul appears, directly followed by OpFAdd. - // The size of the outer std::vector also serves as an input parameter, - // determining how many steps will be collected. - // I.e. do opcode_markov_hist.resize(1) to collect data for one step only. - std::vector< - std::unordered_map>> - opcode_markov_hist; -}; - -// Aggregates existing |stats| with new stats extracted from |binary|. -spv_result_t AggregateStats(const spv_context context, const uint32_t* words, - const size_t num_words, spv_diagnostic* pDiagnostic, - SpirvStats* stats); - -} // namespace stats -} // namespace spvtools - -#endif // TOOLS_STATS_SPIRV_STATS_H_ diff --git a/3rdparty/spirv-tools/tools/stats/stats.cpp b/3rdparty/spirv-tools/tools/stats/stats.cpp deleted file mode 100644 index 30e3bccd6..000000000 --- a/3rdparty/spirv-tools/tools/stats/stats.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2017 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 -#include -#include -#include -#include -#include - -#include "spirv-tools/libspirv.h" -#include "tools/io.h" -#include "tools/stats/spirv_stats.h" -#include "tools/stats/stats_analyzer.h" - -namespace { - -void PrintUsage(char* argv0) { - printf( - R"(%s - Collect statistics from one or more SPIR-V binary file(s). - -USAGE: %s [options] [] - -TIP: In order to collect statistics from all .spv files under current dir use -find . -name "*.spv" -print0 | xargs -0 -s 2000000 %s - -Options: - -h, --help - Print this help. - - -v, --verbose - Print additional info to stderr. -)", - argv0, argv0, argv0); -} - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cout << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cout << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -} // namespace - -int main(int argc, char** argv) { - bool continue_processing = true; - int return_code = 0; - - bool expect_output_path = false; - bool verbose = false; - - std::vector paths; - const char* output_path = nullptr; - - for (int argi = 1; continue_processing && argi < argc; ++argi) { - const char* cur_arg = argv[argi]; - if ('-' == cur_arg[0]) { - if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { - PrintUsage(argv[0]); - continue_processing = false; - return_code = 0; - } else if (0 == strcmp(cur_arg, "--verbose") || - 0 == strcmp(cur_arg, "-v")) { - verbose = true; - } else if (0 == strcmp(cur_arg, "--output") || - 0 == strcmp(cur_arg, "-o")) { - expect_output_path = true; - } else { - PrintUsage(argv[0]); - continue_processing = false; - return_code = 1; - } - } else { - if (expect_output_path) { - output_path = cur_arg; - expect_output_path = false; - } else { - paths.push_back(cur_arg); - } - } - } - - // Exit if command line parsing was not successful. - if (!continue_processing) { - return return_code; - } - - std::cerr << "Processing " << paths.size() << " files..." << std::endl; - - spvtools::Context ctx(SPV_ENV_UNIVERSAL_1_1); - ctx.SetMessageConsumer(DiagnosticsMessageHandler); - - spvtools::stats::SpirvStats stats; - stats.opcode_markov_hist.resize(1); - - for (size_t index = 0; index < paths.size(); ++index) { - const size_t kMilestonePeriod = 1000; - if (verbose) { - if (index % kMilestonePeriod == kMilestonePeriod - 1) - std::cerr << "Processed " << index + 1 << " files..." << std::endl; - } - - const char* path = paths[index]; - std::vector contents; - if (!ReadFile(path, "rb", &contents)) return 1; - - if (SPV_SUCCESS != - spvtools::stats::AggregateStats(ctx.CContext(), contents.data(), - contents.size(), nullptr, &stats)) { - std::cerr << "error: Failed to aggregate stats for " << path << std::endl; - return 1; - } - } - - spvtools::stats::StatsAnalyzer analyzer(stats); - - std::ofstream fout; - if (output_path) { - fout.open(output_path); - if (!fout.is_open()) { - std::cerr << "error: Failed to open " << output_path << std::endl; - return 1; - } - } - - std::ostream& out = fout.is_open() ? fout : std::cout; - out << std::endl; - analyzer.WriteVersion(out); - analyzer.WriteGenerator(out); - - out << std::endl; - analyzer.WriteCapability(out); - - out << std::endl; - analyzer.WriteExtension(out); - - out << std::endl; - analyzer.WriteOpcode(out); - - out << std::endl; - analyzer.WriteOpcodeMarkov(out); - - out << std::endl; - analyzer.WriteConstantLiterals(out); - - return 0; -} diff --git a/3rdparty/spirv-tools/tools/stats/stats_analyzer.cpp b/3rdparty/spirv-tools/tools/stats/stats_analyzer.cpp deleted file mode 100644 index 6d4cabbf6..000000000 --- a/3rdparty/spirv-tools/tools/stats/stats_analyzer.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2017 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 "tools/stats/stats_analyzer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "source/comp/markv_model.h" -#include "source/enum_string_mapping.h" -#include "source/latest_version_spirv_header.h" -#include "source/opcode.h" -#include "source/operand.h" -#include "source/spirv_constant.h" - -namespace spvtools { -namespace stats { -namespace { - -// Signals that the value is not in the coding scheme and a fallback method -// needs to be used. -const uint64_t kMarkvNoneOfTheAbove = - comp::MarkvModel::GetMarkvNoneOfTheAbove(); - -std::string GetVersionString(uint32_t word) { - std::stringstream ss; - ss << "Version " << SPV_SPIRV_VERSION_MAJOR_PART(word) << "." - << SPV_SPIRV_VERSION_MINOR_PART(word); - return ss.str(); -} - -std::string GetGeneratorString(uint32_t word) { - return spvGeneratorStr(SPV_GENERATOR_TOOL_PART(word)); -} - -std::string GetOpcodeString(uint32_t word) { - return spvOpcodeString(static_cast(word)); -} - -std::string GetCapabilityString(uint32_t word) { - return CapabilityToString(static_cast(word)); -} - -template -std::string KeyIsLabel(T key) { - std::stringstream ss; - ss << key; - return ss.str(); -} - -template -std::unordered_map GetRecall( - const std::unordered_map& hist, uint64_t total) { - std::unordered_map freq; - for (const auto& pair : hist) { - const double frequency = - static_cast(pair.second) / static_cast(total); - freq.emplace(pair.first, frequency); - } - return freq; -} - -template -std::unordered_map GetPrevalence( - const std::unordered_map& hist) { - uint64_t total = 0; - for (const auto& pair : hist) { - total += pair.second; - } - - return GetRecall(hist, total); -} - -// Writes |freq| to |out| sorted by frequency in the following format: -// LABEL3 70% -// LABEL1 20% -// LABEL2 10% -// |label_from_key| is used to convert |Key| to label. -template -void WriteFreq(std::ostream& out, const std::unordered_map& freq, - std::string (*label_from_key)(Key)) { - std::vector> sorted_freq(freq.begin(), freq.end()); - std::sort(sorted_freq.begin(), sorted_freq.end(), - [](const std::pair& left, - const std::pair& right) { - return left.second > right.second; - }); - - for (const auto& pair : sorted_freq) { - if (pair.second < 0.001) break; - out << label_from_key(pair.first) << " " << pair.second * 100.0 << "%" - << std::endl; - } -} - -} // namespace - -StatsAnalyzer::StatsAnalyzer(const SpirvStats& stats) : stats_(stats) { - num_modules_ = 0; - for (const auto& pair : stats_.version_hist) { - num_modules_ += pair.second; - } - - version_freq_ = GetRecall(stats_.version_hist, num_modules_); - generator_freq_ = GetRecall(stats_.generator_hist, num_modules_); - capability_freq_ = GetRecall(stats_.capability_hist, num_modules_); - extension_freq_ = GetRecall(stats_.extension_hist, num_modules_); - opcode_freq_ = GetPrevalence(stats_.opcode_hist); -} - -void StatsAnalyzer::WriteVersion(std::ostream& out) { - WriteFreq(out, version_freq_, GetVersionString); -} - -void StatsAnalyzer::WriteGenerator(std::ostream& out) { - WriteFreq(out, generator_freq_, GetGeneratorString); -} - -void StatsAnalyzer::WriteCapability(std::ostream& out) { - WriteFreq(out, capability_freq_, GetCapabilityString); -} - -void StatsAnalyzer::WriteExtension(std::ostream& out) { - WriteFreq(out, extension_freq_, KeyIsLabel); -} - -void StatsAnalyzer::WriteOpcode(std::ostream& out) { - out << "Total unique opcodes used: " << opcode_freq_.size() << std::endl; - WriteFreq(out, opcode_freq_, GetOpcodeString); -} - -void StatsAnalyzer::WriteConstantLiterals(std::ostream& out) { - out << "Constant literals" << std::endl; - - out << "Float 32" << std::endl; - WriteFreq(out, GetPrevalence(stats_.f32_constant_hist), KeyIsLabel); - - out << std::endl << "Float 64" << std::endl; - WriteFreq(out, GetPrevalence(stats_.f64_constant_hist), KeyIsLabel); - - out << std::endl << "Unsigned int 16" << std::endl; - WriteFreq(out, GetPrevalence(stats_.u16_constant_hist), KeyIsLabel); - - out << std::endl << "Signed int 16" << std::endl; - WriteFreq(out, GetPrevalence(stats_.s16_constant_hist), KeyIsLabel); - - out << std::endl << "Unsigned int 32" << std::endl; - WriteFreq(out, GetPrevalence(stats_.u32_constant_hist), KeyIsLabel); - - out << std::endl << "Signed int 32" << std::endl; - WriteFreq(out, GetPrevalence(stats_.s32_constant_hist), KeyIsLabel); - - out << std::endl << "Unsigned int 64" << std::endl; - WriteFreq(out, GetPrevalence(stats_.u64_constant_hist), KeyIsLabel); - - out << std::endl << "Signed int 64" << std::endl; - WriteFreq(out, GetPrevalence(stats_.s64_constant_hist), KeyIsLabel); -} - -void StatsAnalyzer::WriteOpcodeMarkov(std::ostream& out) { - if (stats_.opcode_markov_hist.empty()) return; - - const std::unordered_map>& - cue_to_hist = stats_.opcode_markov_hist[0]; - - // Sort by prevalence of the opcodes in opcode_freq_ (descending). - std::vector>> - sorted_cue_to_hist(cue_to_hist.begin(), cue_to_hist.end()); - std::sort( - sorted_cue_to_hist.begin(), sorted_cue_to_hist.end(), - [this](const std::pair>& - left, - const std::pair>& - right) { - const double lf = opcode_freq_[left.first]; - const double rf = opcode_freq_[right.first]; - if (lf == rf) return right.first > left.first; - return lf > rf; - }); - - for (const auto& kv : sorted_cue_to_hist) { - const uint32_t cue = kv.first; - const double kFrequentEnoughToAnalyze = 0.0001; - if (opcode_freq_[cue] < kFrequentEnoughToAnalyze) continue; - - const std::unordered_map& hist = kv.second; - - uint32_t total = 0; - for (const auto& pair : hist) { - total += pair.second; - } - - std::vector> sorted_hist(hist.begin(), - hist.end()); - std::sort(sorted_hist.begin(), sorted_hist.end(), - [](const std::pair& left, - const std::pair& right) { - if (left.second == right.second) - return right.first > left.first; - return left.second > right.second; - }); - - for (const auto& pair : sorted_hist) { - const double prior = opcode_freq_[pair.first]; - const double posterior = - static_cast(pair.second) / static_cast(total); - out << GetOpcodeString(cue) << " -> " << GetOpcodeString(pair.first) - << " " << posterior * 100 << "% (base rate " << prior * 100 - << "%, pair occurrences " << pair.second << ")" << std::endl; - } - } -} - -} // namespace stats -} // namespace spvtools diff --git a/3rdparty/spirv-tools/tools/stats/stats_analyzer.h b/3rdparty/spirv-tools/tools/stats/stats_analyzer.h deleted file mode 100644 index f1c37bfaa..000000000 --- a/3rdparty/spirv-tools/tools/stats/stats_analyzer.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TOOLS_STATS_STATS_ANALYZER_H_ -#define TOOLS_STATS_STATS_ANALYZER_H_ - -#include -#include - -#include "tools/stats/spirv_stats.h" - -namespace spvtools { -namespace stats { - -class StatsAnalyzer { - public: - explicit StatsAnalyzer(const SpirvStats& stats); - - // Writes respective histograms to |out|. - void WriteVersion(std::ostream& out); - void WriteGenerator(std::ostream& out); - void WriteCapability(std::ostream& out); - void WriteExtension(std::ostream& out); - void WriteOpcode(std::ostream& out); - void WriteConstantLiterals(std::ostream& out); - - // Writes first order Markov analysis to |out|. - // stats_.opcode_markov_hist needs to contain raw data for at least one - // level. - void WriteOpcodeMarkov(std::ostream& out); - - private: - const SpirvStats& stats_; - - uint32_t num_modules_; - - std::unordered_map version_freq_; - std::unordered_map generator_freq_; - std::unordered_map capability_freq_; - std::unordered_map extension_freq_; - std::unordered_map opcode_freq_; -}; - -} // namespace stats -} // namespace spvtools - -#endif // TOOLS_STATS_STATS_ANALYZER_H_ diff --git a/3rdparty/spirv-tools/utils/check_code_format.sh b/3rdparty/spirv-tools/utils/check_code_format.sh index a6a58796a..799474022 100755 --- a/3rdparty/spirv-tools/utils/check_code_format.sh +++ b/3rdparty/spirv-tools/utils/check_code_format.sh @@ -18,14 +18,16 @@ # # This script assumes to be invoked at the project root directory. -FILES_TO_CHECK=$(git diff --name-only master | grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp)$") +BASE_BRANCH=${1:-master} + +FILES_TO_CHECK=$(git diff --name-only ${BASE_BRANCH} | grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp)$") if [ -z "${FILES_TO_CHECK}" ]; then echo "No source code to check for formatting." exit 0 fi -FORMAT_DIFF=$(git diff -U0 master -- ${FILES_TO_CHECK} | python ./utils/clang-format-diff.py -p1 -style=file) +FORMAT_DIFF=$(git diff -U0 ${BASE_BRANCH} -- ${FILES_TO_CHECK} | python ./utils/clang-format-diff.py -p1 -style=file) if [ -z "${FORMAT_DIFF}" ]; then echo "All source code in PR properly formatted." diff --git a/3rdparty/spirv-tools/utils/check_symbol_exports.py b/3rdparty/spirv-tools/utils/check_symbol_exports.py index d4c85794d..a8f3785a5 100755 --- a/3rdparty/spirv-tools/utils/check_symbol_exports.py +++ b/3rdparty/spirv-tools/utils/check_symbol_exports.py @@ -56,6 +56,13 @@ def check_library(library): # _ZN : something in a namespace # _Z[0-9]+spv[A-Z_] : C++ symbol starting with spv[A-Z_] symbol_ok_pattern = re.compile(r'^(spv[A-Z]|_ZN|_Z[0-9]+spv[A-Z_])') + + # In addition, the following pattern whitelists global functions that are added + # by the protobuf compiler: + # - AddDescriptors_spvtoolsfuzz_2eproto() + # - InitDefaults_spvtoolsfuzz_2eproto() + symbol_whitelist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov') + seen = set() result = 0 for line in command_output(['objdump', '-t', library], '.').split('\n'): @@ -65,7 +72,7 @@ def check_library(library): if symbol not in seen: seen.add(symbol) #print("look at '{}'".format(symbol)) - if not symbol_ok_pattern.match(symbol): + if not (symbol_whitelist_pattern.match(symbol) or symbol_ok_pattern.match(symbol)): print('{}: error: Unescaped exported symbol: {}'.format(PROG, symbol)) result = 1 return result diff --git a/scripts/shaderc.lua b/scripts/shaderc.lua index b0044453e..495d10213 100644 --- a/scripts/shaderc.lua +++ b/scripts/shaderc.lua @@ -47,8 +47,6 @@ project "spirv-opt" path.join(SPIRV_TOOLS, "source/ext_inst.h"), path.join(SPIRV_TOOLS, "source/extensions.cpp"), path.join(SPIRV_TOOLS, "source/extensions.h"), - path.join(SPIRV_TOOLS, "source/id_descriptor.cpp"), - path.join(SPIRV_TOOLS, "source/id_descriptor.h"), path.join(SPIRV_TOOLS, "source/instruction.h"), path.join(SPIRV_TOOLS, "source/latest_version_glsl_std_450_header.h"), path.join(SPIRV_TOOLS, "source/latest_version_opencl_std_header.h"), @@ -126,6 +124,7 @@ project "spirv-opt" path.join(SPIRV_TOOLS, "source/val/validate_logicals.cpp"), path.join(SPIRV_TOOLS, "source/val/validate_memory.cpp"), path.join(SPIRV_TOOLS, "source/val/validate_memory_semantics.cpp"), + path.join(SPIRV_TOOLS, "source/val/validate_misc.cpp"), path.join(SPIRV_TOOLS, "source/val/validate_mode_setting.cpp"), path.join(SPIRV_TOOLS, "source/val/validate_non_uniform.cpp"), path.join(SPIRV_TOOLS, "source/val/validate_primitives.cpp"),