From 9d29d2e32ca2c04c603ca3c39b13b86fff6ec4e5 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Tue, 16 Nov 2021 17:13:42 -0800 Subject: [PATCH] Update spirv-tools to v2021.4 (#4862) --- third_party/spirv-tools/.appveyor.yml | 90 - .../spirv-tools/.github/workflows/wasm.yml | 14 + third_party/spirv-tools/.gitignore | 2 - third_party/spirv-tools/Android.mk | 9 + third_party/spirv-tools/BUILD.bazel | 43 + third_party/spirv-tools/BUILD.gn | 501 +- third_party/spirv-tools/CHANGES | 41 +- third_party/spirv-tools/CMakeLists.txt | 27 +- third_party/spirv-tools/CONTRIBUTING.md | 7 - third_party/spirv-tools/DEPS | 8 +- third_party/spirv-tools/FILAMENT_README.md | 30 + third_party/spirv-tools/README.md | 167 +- third_party/spirv-tools/build_defs.bzl | 18 + third_party/spirv-tools/docker-compose.yml | 10 + third_party/spirv-tools/docs/downloads.md | 20 +- .../.github/workflows/presubmit.yml | 37 + .../external/spirv-headers/BUILD.bazel | 5 + .../external/spirv-headers/CMakeLists.txt | 8 +- .../spirv-headers/SPIRV-Headers.pc.in | 9 + .../spirv-headers/include/spirv/spir-v.xml | 31 +- .../unified1/NonSemanticClspvReflection.h | 3 +- .../unified1/NonSemanticShaderDebugInfo100.h | 171 + ...t.nonsemantic.clspvreflection.grammar.json | 9 +- ...semantic.shader.debuginfo.100.grammar.json | 713 +++ .../spirv/unified1/spirv.core.grammar.json | 284 +- .../include/spirv/unified1/spirv.cs | 23 +- .../include/spirv/unified1/spirv.h | 34 +- .../include/spirv/unified1/spirv.hpp | 34 +- .../include/spirv/unified1/spirv.hpp11 | 34 +- .../include/spirv/unified1/spirv.json | 25 +- .../include/spirv/unified1/spirv.lua | 23 +- .../include/spirv/unified1/spirv.py | 23 +- .../include/spirv/unified1/spv.d | 23 +- .../filament-specific-changes.patch | 51 +- .../include/spirv-tools/libspirv.h | 7 + .../include/spirv-tools/libspirv.hpp | 6 + .../include/spirv-tools/linter.hpp | 48 + .../include/spirv-tools/optimizer.hpp | 35 +- .../kokoro/linux-clang-ubsan/build.sh | 24 + .../kokoro/linux-clang-ubsan/continuous.cfg | 16 + .../kokoro/linux-clang-ubsan/presubmit.cfg | 16 + .../kokoro/scripts/linux/build-docker.sh | 15 +- .../spirv-tools/kokoro/scripts/macos/build.sh | 2 +- .../kokoro/scripts/windows/build.bat | 4 +- third_party/spirv-tools/source/CMakeLists.txt | 17 +- third_party/spirv-tools/source/binary.cpp | 3 +- .../spirv-tools/source/common_debug_info.h | 64 + third_party/spirv-tools/source/ext_inst.cpp | 9 + .../spirv-tools/source/fuzz/CMakeLists.txt | 4 + .../spirv-tools/source/fuzz/fuzzer.cpp | 15 +- third_party/spirv-tools/source/fuzz/fuzzer.h | 9 +- .../source/fuzz/fuzzer_context.cpp | 9 + .../spirv-tools/source/fuzz/fuzzer_context.h | 19 + .../spirv-tools/source/fuzz/fuzzer_pass.cpp | 27 +- .../spirv-tools/source/fuzz/fuzzer_pass.h | 7 +- .../fuzz/fuzzer_pass_add_access_chains.cpp | 5 +- .../fuzz/fuzzer_pass_add_access_chains.h | 3 +- ...zzer_pass_add_bit_instruction_synonyms.cpp | 5 +- ...fuzzer_pass_add_bit_instruction_synonyms.h | 3 +- .../fuzzer_pass_add_composite_extract.cpp | 5 +- .../fuzz/fuzzer_pass_add_composite_extract.h | 3 +- .../fuzzer_pass_add_composite_inserts.cpp | 5 +- .../fuzz/fuzzer_pass_add_composite_inserts.h | 3 +- .../fuzz/fuzzer_pass_add_composite_types.cpp | 5 +- .../fuzz/fuzzer_pass_add_composite_types.h | 3 +- .../fuzz/fuzzer_pass_add_copy_memory.cpp | 5 +- .../source/fuzz/fuzzer_pass_add_copy_memory.h | 3 +- .../fuzz/fuzzer_pass_add_dead_blocks.cpp | 5 +- .../source/fuzz/fuzzer_pass_add_dead_blocks.h | 3 +- .../fuzz/fuzzer_pass_add_dead_breaks.cpp | 5 +- .../source/fuzz/fuzzer_pass_add_dead_breaks.h | 3 +- .../fuzz/fuzzer_pass_add_dead_continues.cpp | 5 +- .../fuzz/fuzzer_pass_add_dead_continues.h | 9 +- .../fuzzer_pass_add_equation_instructions.cpp | 5 +- .../fuzzer_pass_add_equation_instructions.h | 3 +- .../fuzz/fuzzer_pass_add_function_calls.cpp | 5 +- .../fuzz/fuzzer_pass_add_function_calls.h | 9 +- .../fuzz/fuzzer_pass_add_global_variables.cpp | 9 +- .../fuzz/fuzzer_pass_add_global_variables.h | 3 +- ...ass_add_image_sample_unused_components.cpp | 5 +- ..._pass_add_image_sample_unused_components.h | 3 +- .../source/fuzz/fuzzer_pass_add_loads.cpp | 73 +- .../source/fuzz/fuzzer_pass_add_loads.h | 3 +- .../fuzz/fuzzer_pass_add_local_variables.cpp | 9 +- .../fuzz/fuzzer_pass_add_local_variables.h | 3 +- .../fuzz/fuzzer_pass_add_loop_preheaders.cpp | 5 +- .../fuzz/fuzzer_pass_add_loop_preheaders.h | 3 +- ..._loops_to_create_int_constant_synonyms.cpp | 5 +- ...dd_loops_to_create_int_constant_synonyms.h | 3 +- ...er_pass_add_no_contraction_decorations.cpp | 5 +- ...zzer_pass_add_no_contraction_decorations.h | 3 +- .../fuzz/fuzzer_pass_add_opphi_synonyms.cpp | 5 +- .../fuzz/fuzzer_pass_add_opphi_synonyms.h | 9 +- .../fuzz/fuzzer_pass_add_parameters.cpp | 5 +- .../source/fuzz/fuzzer_pass_add_parameters.h | 3 +- .../fuzzer_pass_add_relaxed_decorations.cpp | 5 +- .../fuzzer_pass_add_relaxed_decorations.h | 3 +- .../source/fuzz/fuzzer_pass_add_stores.cpp | 62 +- .../source/fuzz/fuzzer_pass_add_stores.h | 3 +- .../source/fuzz/fuzzer_pass_add_synonyms.cpp | 5 +- .../source/fuzz/fuzzer_pass_add_synonyms.h | 3 +- ...r_pass_add_vector_shuffle_instructions.cpp | 7 +- ...zer_pass_add_vector_shuffle_instructions.h | 3 +- .../fuzzer_pass_adjust_branch_weights.cpp | 5 +- .../fuzz/fuzzer_pass_adjust_branch_weights.h | 3 +- .../fuzzer_pass_adjust_function_controls.cpp | 5 +- .../fuzzer_pass_adjust_function_controls.h | 3 +- .../fuzz/fuzzer_pass_adjust_loop_controls.cpp | 5 +- .../fuzz/fuzzer_pass_adjust_loop_controls.h | 3 +- ...zzer_pass_adjust_memory_operands_masks.cpp | 5 +- ...fuzzer_pass_adjust_memory_operands_masks.h | 3 +- .../fuzzer_pass_adjust_selection_controls.cpp | 5 +- .../fuzzer_pass_adjust_selection_controls.h | 3 +- .../fuzz/fuzzer_pass_apply_id_synonyms.cpp | 7 +- .../fuzz/fuzzer_pass_apply_id_synonyms.h | 3 +- .../fuzz/fuzzer_pass_construct_composites.cpp | 7 +- .../fuzz/fuzzer_pass_construct_composites.h | 3 +- .../source/fuzz/fuzzer_pass_copy_objects.cpp | 5 +- .../source/fuzz/fuzzer_pass_copy_objects.h | 3 +- .../fuzz/fuzzer_pass_donate_modules.cpp | 7 +- .../source/fuzz/fuzzer_pass_donate_modules.h | 3 +- ...pass_duplicate_regions_with_selections.cpp | 5 +- ...r_pass_duplicate_regions_with_selections.h | 3 +- .../fuzzer_pass_expand_vector_reductions.cpp | 7 +- .../fuzzer_pass_expand_vector_reductions.h | 3 +- ...zzer_pass_flatten_conditional_branches.cpp | 5 +- ...fuzzer_pass_flatten_conditional_branches.h | 3 +- .../fuzz/fuzzer_pass_inline_functions.cpp | 5 +- .../fuzz/fuzzer_pass_inline_functions.h | 3 +- ...rchange_signedness_of_integer_operands.cpp | 5 +- ...terchange_signedness_of_integer_operands.h | 3 +- ...r_pass_interchange_zero_like_constants.cpp | 5 +- ...zer_pass_interchange_zero_like_constants.h | 3 +- ...uzzer_pass_invert_comparison_operators.cpp | 5 +- .../fuzzer_pass_invert_comparison_operators.h | 3 +- ...er_pass_make_vector_operations_dynamic.cpp | 5 +- ...zzer_pass_make_vector_operations_dynamic.h | 3 +- .../source/fuzz/fuzzer_pass_merge_blocks.cpp | 5 +- .../source/fuzz/fuzzer_pass_merge_blocks.h | 3 +- .../fuzzer_pass_merge_function_returns.cpp | 5 +- .../fuzz/fuzzer_pass_merge_function_returns.h | 3 +- .../fuzz/fuzzer_pass_mutate_pointers.cpp | 5 +- .../source/fuzz/fuzzer_pass_mutate_pointers.h | 3 +- .../fuzz/fuzzer_pass_obfuscate_constants.cpp | 5 +- .../fuzz/fuzzer_pass_obfuscate_constants.h | 3 +- .../fuzz/fuzzer_pass_outline_functions.cpp | 5 +- .../fuzz/fuzzer_pass_outline_functions.h | 9 +- .../fuzz/fuzzer_pass_permute_blocks.cpp | 5 +- .../source/fuzz/fuzzer_pass_permute_blocks.h | 3 +- ...uzzer_pass_permute_function_parameters.cpp | 5 +- .../fuzzer_pass_permute_function_parameters.h | 3 +- ...fuzzer_pass_permute_function_variables.cpp | 6 +- .../fuzzer_pass_permute_function_variables.h | 3 +- .../fuzz/fuzzer_pass_permute_instructions.cpp | 5 +- .../fuzz/fuzzer_pass_permute_instructions.h | 3 +- .../fuzz/fuzzer_pass_permute_phi_operands.cpp | 5 +- .../fuzz/fuzzer_pass_permute_phi_operands.h | 3 +- ...uzzer_pass_propagate_instructions_down.cpp | 5 +- .../fuzzer_pass_propagate_instructions_down.h | 3 +- .../fuzzer_pass_propagate_instructions_up.cpp | 5 +- .../fuzzer_pass_propagate_instructions_up.h | 3 +- ...fuzzer_pass_push_ids_through_variables.cpp | 7 +- .../fuzzer_pass_push_ids_through_variables.h | 3 +- ..._adds_subs_muls_with_carrying_extended.cpp | 5 +- ...ce_adds_subs_muls_with_carrying_extended.h | 3 +- ...e_branches_from_dead_blocks_with_exits.cpp | 5 +- ...ace_branches_from_dead_blocks_with_exits.h | 3 +- ...eplace_copy_memories_with_loads_stores.cpp | 5 +- ..._replace_copy_memories_with_loads_stores.h | 3 +- ...replace_copy_objects_with_stores_loads.cpp | 5 +- ...s_replace_copy_objects_with_stores_loads.h | 3 +- .../fuzzer_pass_replace_irrelevant_ids.cpp | 5 +- .../fuzz/fuzzer_pass_replace_irrelevant_ids.h | 3 +- ...ss_replace_linear_algebra_instructions.cpp | 5 +- ...pass_replace_linear_algebra_instructions.h | 3 +- ...eplace_loads_stores_with_copy_memories.cpp | 5 +- ..._replace_loads_stores_with_copy_memories.h | 3 +- ...place_opphi_ids_from_dead_predecessors.cpp | 5 +- ...replace_opphi_ids_from_dead_predecessors.h | 3 +- ...ce_opselects_with_conditional_branches.cpp | 5 +- ...lace_opselects_with_conditional_branches.h | 3 +- ...zer_pass_replace_parameter_with_global.cpp | 5 +- ...uzzer_pass_replace_parameter_with_global.h | 3 +- ...fuzzer_pass_replace_params_with_struct.cpp | 5 +- .../fuzzer_pass_replace_params_with_struct.h | 3 +- .../source/fuzz/fuzzer_pass_split_blocks.cpp | 5 +- .../source/fuzz/fuzzer_pass_split_blocks.h | 3 +- .../fuzzer_pass_swap_commutable_operands.cpp | 5 +- .../fuzzer_pass_swap_commutable_operands.h | 3 +- ..._pass_swap_conditional_branch_operands.cpp | 5 +- ...er_pass_swap_conditional_branch_operands.h | 3 +- .../fuzz/fuzzer_pass_swap_functions.cpp | 5 +- .../source/fuzz/fuzzer_pass_swap_functions.h | 3 +- ...r_pass_toggle_access_chain_instruction.cpp | 5 +- ...zer_pass_toggle_access_chain_instruction.h | 3 +- ...fuzzer_pass_wrap_regions_in_selections.cpp | 5 +- .../fuzzer_pass_wrap_regions_in_selections.h | 3 +- .../fuzz/fuzzer_pass_wrap_vector_synonym.cpp | 144 + .../fuzz/fuzzer_pass_wrap_vector_synonym.h | 38 + .../spirv-tools/source/fuzz/fuzzer_util.cpp | 208 +- .../spirv-tools/source/fuzz/fuzzer_util.h | 27 +- .../pass_management/repeated_pass_instances.h | 2 + .../repeated_pass_recommender_standard.cpp | 6 + .../fuzz/protobufs/spirvfuzz_protobufs.h | 5 +- .../source/fuzz/protobufs/spvtoolsfuzz.proto | 77 +- .../source/fuzz/transformation.cpp | 4 + .../fuzz/transformation_add_constant_null.cpp | 4 +- .../fuzz/transformation_add_global_undef.cpp | 9 +- .../fuzz/transformation_add_global_undef.h | 2 +- .../fuzz/transformation_add_synonym.cpp | 3 +- .../transformation_composite_construct.cpp | 2 +- .../fuzz/transformation_composite_extract.cpp | 2 +- .../fuzz/transformation_composite_insert.cpp | 8 +- ...mation_duplicate_region_with_selection.cpp | 4 +- ...transformation_expand_vector_reduction.cpp | 2 +- .../source/fuzz/transformation_load.cpp | 154 +- .../source/fuzz/transformation_load.h | 11 +- ...ransformation_push_id_through_variable.cpp | 2 +- ...transformation_replace_id_with_synonym.cpp | 60 +- .../transformation_replace_id_with_synonym.h | 15 - .../source/fuzz/transformation_store.cpp | 146 +- .../source/fuzz/transformation_store.h | 11 +- .../fuzz/transformation_vector_shuffle.cpp | 4 +- .../transformation_wrap_vector_synonym.cpp | 200 + .../fuzz/transformation_wrap_vector_synonym.h | 80 + .../spirv-tools/source/link/linker.cpp | 3 +- .../spirv-tools/source/lint/CMakeLists.txt | 61 + .../source/lint/divergence_analysis.cpp | 245 + .../source/lint/divergence_analysis.h | 163 + .../lint/lint_divergent_derivatives.cpp | 169 + .../spirv-tools/source/lint/linter.cpp | 60 + third_party/spirv-tools/source/lint/lints.h | 34 + third_party/spirv-tools/source/operand.cpp | 6 + .../spirv-tools/source/opt/CMakeLists.txt | 10 + .../opt/aggressive_dead_code_elim_pass.cpp | 796 +-- .../opt/aggressive_dead_code_elim_pass.h | 152 +- .../source/opt/block_merge_pass.cpp | 2 +- .../source/opt/block_merge_util.cpp | 15 +- .../spirv-tools/source/opt/ccp_pass.cpp | 4 + .../source/opt/combine_access_chains.cpp | 4 + .../source/opt/compact_ids_pass.cpp | 5 +- .../source/opt/const_folding_rules.cpp | 4 +- .../spirv-tools/source/opt/constants.cpp | 9 +- .../spirv-tools/source/opt/constants.h | 3 + .../source/opt/control_dependence.cpp | 156 + .../source/opt/control_dependence.h | 197 + .../source/opt/convert_to_half_pass.cpp | 36 +- .../source/opt/convert_to_half_pass.h | 2 +- .../opt/convert_to_sampled_image_pass.cpp | 437 ++ .../opt/convert_to_sampled_image_pass.h | 207 + .../source/opt/copy_prop_arrays.cpp | 29 +- .../spirv-tools/source/opt/dataflow.cpp | 91 + third_party/spirv-tools/source/opt/dataflow.h | 148 + .../source/opt/dead_branch_elim_pass.cpp | 5 + .../source/opt/dead_insert_elim_pass.cpp | 4 +- .../source/opt/debug_info_manager.cpp | 332 +- .../source/opt/debug_info_manager.h | 16 +- .../source/opt/decoration_manager.cpp | 8 + .../source/opt/decoration_manager.h | 4 + .../source/opt/def_use_manager.cpp | 21 +- .../spirv-tools/source/opt/desc_sroa.cpp | 224 +- .../spirv-tools/source/opt/desc_sroa.h | 47 +- .../spirv-tools/source/opt/desc_sroa_util.cpp | 117 + .../spirv-tools/source/opt/desc_sroa_util.h | 54 + .../opt/eliminate_dead_members_pass.cpp | 31 +- .../source/opt/feature_manager.cpp | 7 + .../spirv-tools/source/opt/feature_manager.h | 8 + .../spirv-tools/source/opt/folding_rules.cpp | 239 +- third_party/spirv-tools/source/opt/function.h | 3 + .../spirv-tools/source/opt/if_conversion.cpp | 1 + .../source/opt/inline_exhaustive_pass.cpp | 2 +- .../source/opt/inline_opaque_pass.cpp | 2 +- .../spirv-tools/source/opt/inline_pass.cpp | 27 +- .../source/opt/inst_buff_addr_check_pass.cpp | 60 +- .../source/opt/inst_buff_addr_check_pass.h | 12 +- .../spirv-tools/source/opt/instruction.cpp | 129 +- .../spirv-tools/source/opt/instruction.h | 49 +- .../spirv-tools/source/opt/ir_builder.h | 22 +- .../spirv-tools/source/opt/ir_context.cpp | 14 +- .../spirv-tools/source/opt/ir_context.h | 8 +- .../spirv-tools/source/opt/ir_loader.cpp | 70 +- third_party/spirv-tools/source/opt/iterator.h | 2 +- .../opt/local_access_chain_convert_pass.cpp | 20 +- .../opt/local_single_block_elim_pass.cpp | 24 +- .../opt/local_single_store_elim_pass.cpp | 30 +- .../spirv-tools/source/opt/loop_unroller.cpp | 10 +- .../spirv-tools/source/opt/mem_pass.cpp | 9 +- .../source/opt/merge_return_pass.cpp | 21 +- .../source/opt/merge_return_pass.h | 4 +- third_party/spirv-tools/source/opt/module.cpp | 61 +- third_party/spirv-tools/source/opt/module.h | 8 +- .../spirv-tools/source/opt/optimizer.cpp | 69 +- third_party/spirv-tools/source/opt/pass.cpp | 4 +- third_party/spirv-tools/source/opt/passes.h | 2 + .../source/opt/private_to_local_pass.cpp | 6 +- .../source/opt/reduce_load_size.cpp | 7 +- .../spirv-tools/source/opt/reduce_load_size.h | 8 + .../source/opt/redundancy_elimination.cpp | 4 + third_party/spirv-tools/source/opt/reflect.h | 5 +- .../source/opt/relax_float_ops_pass.cpp | 2 +- ...lace_desc_array_access_using_var_index.cpp | 423 ++ ...eplace_desc_array_access_using_var_index.h | 204 + .../source/opt/replace_invalid_opc.cpp | 18 +- .../source/opt/scalar_replacement_pass.cpp | 32 +- .../source/opt/scalar_replacement_pass.h | 3 + .../set_spec_constant_default_value_pass.cpp | 33 +- .../source/opt/simplification_pass.cpp | 4 + .../source/opt/ssa_rewrite_pass.cpp | 3 + .../source/opt/value_number_table.cpp | 2 +- .../spirv-tools/source/opt/vector_dce.cpp | 36 +- .../spirv-tools/source/opt/vector_dce.h | 7 +- .../spirv-tools/source/spirv_constant.h | 1 + .../spirv-tools/source/spirv_target_env.cpp | 63 +- .../spirv-tools/source/spirv_target_env.h | 3 + .../source/spirv_validator_options.cpp | 5 + .../source/spirv_validator_options.h | 2 + .../spirv-tools/source/text_handler.cpp | 3 +- .../spirv-tools/source/util/hex_float.h | 16 +- .../spirv-tools/source/val/construct.cpp | 3 +- .../spirv-tools/source/val/function.cpp | 3 + .../source/val/validate_adjacency.cpp | 5 +- .../source/val/validate_annotation.cpp | 262 +- .../source/val/validate_atomics.cpp | 2 +- .../source/val/validate_builtins.cpp | 19 +- .../spirv-tools/source/val/validate_cfg.cpp | 18 +- .../source/val/validate_decorations.cpp | 72 +- .../source/val/validate_derivatives.cpp | 12 +- .../source/val/validate_extensions.cpp | 1084 ++-- .../spirv-tools/source/val/validate_image.cpp | 32 +- .../source/val/validate_instruction.cpp | 7 +- .../source/val/validate_interfaces.cpp | 63 +- .../source/val/validate_layout.cpp | 79 +- .../source/val/validate_memory.cpp | 6 + .../source/val/validate_mode_setting.cpp | 19 +- .../spirv-tools/source/val/validate_type.cpp | 2 +- .../source/val/validation_state.cpp | 134 +- .../spirv-tools/source/val/validation_state.h | 37 +- third_party/spirv-tools/source/wasm/README.md | 43 + third_party/spirv-tools/source/wasm/build.sh | 78 + .../spirv-tools/source/wasm/package.json | 17 + .../spirv-tools/source/wasm/spirv-tools.cpp | 93 + .../spirv-tools/source/wasm/spirv-tools.d.ts | 56 + third_party/spirv-tools/test/CMakeLists.txt | 2 + .../spirv-tools/test/binary_to_text_test.cpp | 2 +- .../spirv-tools/test/fuzz/CMakeLists.txt | 1 + .../fuzzer_pass_add_opphi_synonyms_test.cpp | 2 +- .../fuzzer_pass_construct_composites_test.cpp | 4 +- .../fuzz/fuzzer_pass_donate_modules_test.cpp | 40 +- .../fuzzer_pass_outline_functions_test.cpp | 8 +- .../test/fuzz/fuzzer_pass_test.cpp | 2 +- .../test/fuzz/fuzzer_replayer_test.cpp | 26 +- .../test/fuzz/fuzzer_shrinker_test.cpp | 2 +- .../spirv-tools/test/fuzz/fuzzerutil_test.cpp | 267 +- .../spirv-tools/test/fuzz/shrinker_test.cpp | 4 +- .../fuzz/transformation_access_chain_test.cpp | 13 +- .../transformation_add_copy_memory_test.cpp | 10 +- .../fuzz/transformation_add_synonym_test.cpp | 10 +- .../test/fuzz/transformation_load_test.cpp | 383 +- .../transformation_mutate_pointer_test.cpp | 8 +- ...ormation_push_id_through_variable_test.cpp | 10 +- ...formation_replace_id_with_synonym_test.cpp | 245 +- .../test/fuzz/transformation_store_test.cpp | 307 +- ...ransformation_wrap_vector_synonym_test.cpp | 1553 +++++ third_party/spirv-tools/test/fuzzers/BUILD.gn | 1 + .../spirv-tools/test/fuzzers/CMakeLists.txt | 56 + .../fuzzers/corpora/spv/graphicsfuzz_000.spv | Bin 0 -> 7968 bytes .../fuzzers/corpora/spv/graphicsfuzz_001.spv | Bin 0 -> 2452 bytes .../fuzzers/corpora/spv/graphicsfuzz_002.spv | Bin 0 -> 2060 bytes .../fuzzers/corpora/spv/graphicsfuzz_003.spv | Bin 0 -> 13336 bytes .../fuzzers/corpora/spv/graphicsfuzz_004.spv | Bin 0 -> 12368 bytes .../fuzzers/corpora/spv/graphicsfuzz_005.spv | Bin 0 -> 2416 bytes .../fuzzers/corpora/spv/graphicsfuzz_006.spv | Bin 0 -> 2728 bytes .../fuzzers/corpora/spv/graphicsfuzz_007.spv | Bin 0 -> 2668 bytes .../fuzzers/corpora/spv/graphicsfuzz_008.spv | Bin 0 -> 22972 bytes .../fuzzers/corpora/spv/graphicsfuzz_009.spv | Bin 0 -> 3728 bytes .../fuzzers/corpora/spv/graphicsfuzz_010.spv | Bin 0 -> 3280 bytes .../fuzzers/corpora/spv/graphicsfuzz_011.spv | Bin 0 -> 5440 bytes .../fuzzers/corpora/spv/graphicsfuzz_012.spv | Bin 0 -> 3692 bytes .../fuzzers/corpora/spv/graphicsfuzz_013.spv | Bin 0 -> 2860 bytes .../fuzzers/corpora/spv/graphicsfuzz_014.spv | Bin 0 -> 1772 bytes .../fuzzers/corpora/spv/graphicsfuzz_015.spv | Bin 0 -> 7488 bytes .../fuzzers/corpora/spv/graphicsfuzz_016.spv | Bin 0 -> 4044 bytes .../fuzzers/corpora/spv/graphicsfuzz_017.spv | Bin 0 -> 14360 bytes .../fuzzers/corpora/spv/graphicsfuzz_018.spv | Bin 0 -> 16524 bytes .../fuzzers/corpora/spv/graphicsfuzz_019.spv | Bin 0 -> 10552 bytes .../fuzzers/corpora/spv/graphicsfuzz_020.spv | Bin 0 -> 9800 bytes .../fuzzers/corpora/spv/graphicsfuzz_021.spv | Bin 0 -> 1936 bytes .../fuzzers/corpora/spv/graphicsfuzz_022.spv | Bin 0 -> 9436 bytes .../fuzzers/corpora/spv/graphicsfuzz_023.spv | Bin 0 -> 1940 bytes .../fuzzers/corpora/spv/graphicsfuzz_024.spv | Bin 0 -> 9256 bytes .../fuzzers/corpora/spv/graphicsfuzz_025.spv | Bin 0 -> 7960 bytes .../fuzzers/corpora/spv/graphicsfuzz_026.spv | Bin 0 -> 9680 bytes .../fuzzers/corpora/spv/graphicsfuzz_027.spv | Bin 0 -> 9432 bytes .../fuzzers/corpora/spv/graphicsfuzz_028.spv | Bin 0 -> 4092 bytes .../fuzzers/corpora/spv/graphicsfuzz_029.spv | Bin 0 -> 2404 bytes .../fuzzers/corpora/spv/graphicsfuzz_030.spv | Bin 0 -> 2568 bytes .../fuzzers/corpora/spv/graphicsfuzz_031.spv | Bin 0 -> 6084 bytes .../fuzzers/corpora/spv/graphicsfuzz_032.spv | Bin 0 -> 11380 bytes .../fuzzers/corpora/spv/graphicsfuzz_033.spv | Bin 0 -> 7180 bytes .../fuzzers/corpora/spv/graphicsfuzz_034.spv | Bin 0 -> 1356 bytes .../fuzzers/corpora/spv/graphicsfuzz_035.spv | Bin 0 -> 648 bytes .../fuzzers/corpora/spv/graphicsfuzz_036.spv | Bin 0 -> 2872 bytes .../fuzzers/corpora/spv/graphicsfuzz_037.spv | Bin 0 -> 6256 bytes .../fuzzers/corpora/spv/graphicsfuzz_038.spv | Bin 0 -> 3648 bytes .../fuzzers/corpora/spv/graphicsfuzz_039.spv | Bin 0 -> 3428 bytes .../fuzzers/corpora/spv/graphicsfuzz_040.spv | Bin 0 -> 3284 bytes .../fuzzers/corpora/spv/graphicsfuzz_041.spv | Bin 0 -> 3360 bytes .../fuzzers/corpora/spv/graphicsfuzz_042.spv | Bin 0 -> 6456 bytes .../fuzzers/corpora/spv/graphicsfuzz_043.spv | Bin 0 -> 2084 bytes .../fuzzers/corpora/spv/graphicsfuzz_044.spv | Bin 0 -> 2596 bytes .../fuzzers/corpora/spv/graphicsfuzz_045.spv | Bin 0 -> 4680 bytes .../fuzzers/corpora/spv/graphicsfuzz_046.spv | Bin 0 -> 5816 bytes .../fuzzers/corpora/spv/graphicsfuzz_047.spv | Bin 0 -> 3216 bytes .../fuzzers/corpora/spv/graphicsfuzz_048.spv | Bin 0 -> 4644 bytes .../fuzzers/corpora/spv/graphicsfuzz_049.spv | Bin 0 -> 7436 bytes .../fuzzers/corpora/spv/graphicsfuzz_050.spv | Bin 0 -> 4156 bytes .../fuzzers/corpora/spv/graphicsfuzz_051.spv | Bin 0 -> 3200 bytes .../fuzzers/corpora/spv/graphicsfuzz_052.spv | Bin 0 -> 5572 bytes .../fuzzers/corpora/spv/graphicsfuzz_053.spv | Bin 0 -> 3936 bytes .../fuzzers/corpora/spv/graphicsfuzz_054.spv | Bin 0 -> 3024 bytes .../fuzzers/corpora/spv/graphicsfuzz_055.spv | Bin 0 -> 1220 bytes .../fuzzers/corpora/spv/graphicsfuzz_056.spv | Bin 0 -> 7660 bytes .../fuzzers/corpora/spv/graphicsfuzz_057.spv | Bin 0 -> 9044 bytes .../fuzzers/corpora/spv/graphicsfuzz_058.spv | Bin 0 -> 3172 bytes .../fuzzers/corpora/spv/graphicsfuzz_059.spv | Bin 0 -> 5940 bytes .../fuzzers/corpora/spv/graphicsfuzz_060.spv | Bin 0 -> 12388 bytes .../fuzzers/corpora/spv/graphicsfuzz_061.spv | Bin 0 -> 9564 bytes .../fuzzers/corpora/spv/graphicsfuzz_062.spv | Bin 0 -> 1824 bytes .../fuzzers/corpora/spv/graphicsfuzz_063.spv | Bin 0 -> 13152 bytes .../fuzzers/corpora/spv/graphicsfuzz_064.spv | Bin 0 -> 6284 bytes .../fuzzers/corpora/spv/graphicsfuzz_065.spv | Bin 0 -> 7184 bytes .../fuzzers/corpora/spv/graphicsfuzz_066.spv | Bin 0 -> 3796 bytes .../fuzzers/corpora/spv/graphicsfuzz_067.spv | Bin 0 -> 3716 bytes .../fuzzers/corpora/spv/graphicsfuzz_068.spv | Bin 0 -> 1956 bytes .../fuzzers/corpora/spv/graphicsfuzz_069.spv | Bin 0 -> 3740 bytes .../fuzzers/corpora/spv/graphicsfuzz_070.spv | Bin 0 -> 6024 bytes .../fuzzers/corpora/spv/graphicsfuzz_071.spv | Bin 0 -> 964 bytes .../fuzzers/corpora/spv/graphicsfuzz_072.spv | Bin 0 -> 20916 bytes .../fuzzers/corpora/spv/graphicsfuzz_073.spv | Bin 0 -> 10108 bytes .../fuzzers/corpora/spv/graphicsfuzz_074.spv | Bin 0 -> 5476 bytes .../fuzzers/corpora/spv/graphicsfuzz_075.spv | Bin 0 -> 1264 bytes .../fuzzers/corpora/spv/graphicsfuzz_076.spv | Bin 0 -> 3772 bytes .../fuzzers/corpora/spv/graphicsfuzz_077.spv | Bin 0 -> 4276 bytes .../fuzzers/corpora/spv/graphicsfuzz_078.spv | Bin 0 -> 7136 bytes .../fuzzers/corpora/spv/graphicsfuzz_079.spv | Bin 0 -> 5548 bytes .../fuzzers/corpora/spv/graphicsfuzz_080.spv | Bin 0 -> 5548 bytes .../fuzzers/corpora/spv/graphicsfuzz_081.spv | Bin 0 -> 3216 bytes .../fuzzers/corpora/spv/graphicsfuzz_082.spv | Bin 0 -> 16372 bytes .../fuzzers/corpora/spv/graphicsfuzz_083.spv | Bin 0 -> 4328 bytes .../fuzzers/corpora/spv/graphicsfuzz_084.spv | Bin 0 -> 4180 bytes .../fuzzers/corpora/spv/graphicsfuzz_085.spv | Bin 0 -> 2132 bytes .../fuzzers/corpora/spv/graphicsfuzz_086.spv | Bin 0 -> 2476 bytes .../test/fuzzers/random_generator.cpp | 135 + .../test/fuzzers/random_generator.h | 68 + .../test/fuzzers/spvtools_as_fuzzer.cpp | 23 +- .../fuzzers/spvtools_binary_parser_fuzzer.cpp | 16 +- .../test/fuzzers/spvtools_dis_fuzzer.cpp | 18 +- .../test/fuzzers/spvtools_fuzz_fuzzer.cpp | 80 + .../spvtools_opt_legalization_fuzzer.cpp | 8 +- .../spvtools_opt_performance_fuzzer.cpp | 8 +- .../test/fuzzers/spvtools_opt_size_fuzzer.cpp | 8 +- .../test/fuzzers/spvtools_val_fuzzer.cpp | 8 +- .../spirv-tools/test/hex_float_test.cpp | 70 + .../spirv-tools/test/lint/CMakeLists.txt | 18 + .../test/lint/divergence_analysis_test.cpp | 700 +++ .../test/operand_capabilities_test.cpp | 13 - .../spirv-tools/test/opt/CMakeLists.txt | 4 + .../opt/aggressive_dead_code_elim_test.cpp | 458 +- .../spirv-tools/test/opt/block_merge_test.cpp | 163 + third_party/spirv-tools/test/opt/ccp_test.cpp | 26 + .../test/opt/combine_access_chains_test.cpp | 26 + .../test/opt/control_dependence.cpp | 306 + .../test/opt/convert_relaxed_to_half_test.cpp | 173 + .../opt/convert_to_sampled_image_test.cpp | 353 ++ .../test/opt/copy_prop_array_test.cpp | 25 + third_party/spirv-tools/test/opt/dataflow.cpp | 225 + .../test/opt/dead_branch_elim_test.cpp | 65 + .../test/opt/dead_insert_elim_test.cpp | 66 + .../test/opt/debug_info_manager_test.cpp | 116 + .../spirv-tools/test/opt/desc_sroa_test.cpp | 63 + .../test/opt/eliminate_dead_member_test.cpp | 62 +- .../spirv-tools/test/opt/fold_test.cpp | 325 +- .../test/opt/inline_opaque_test.cpp | 109 + .../spirv-tools/test/opt/inline_test.cpp | 400 +- .../test/opt/inst_buff_addr_check_test.cpp | 206 + .../spirv-tools/test/opt/ir_loader_test.cpp | 16 + .../test/opt/local_single_block_elim.cpp | 50 + .../test/opt/local_single_store_elim_test.cpp | 85 + .../test/opt/local_ssa_elim_test.cpp | 160 + .../loop_optimizations/unroll_assumptions.cpp | 31 + .../opt/loop_optimizations/unroll_simple.cpp | 179 + .../test/opt/pass_merge_return_test.cpp | 33 + .../test/opt/reduce_load_size_test.cpp | 89 +- .../test/opt/redundancy_elimination_test.cpp | 28 +- .../test/opt/relax_float_ops_test.cpp | 80 + ...desc_array_access_using_var_index_test.cpp | 411 ++ .../test/opt/scalar_replacement_test.cpp | 40 +- .../opt/set_spec_const_default_value_test.cpp | 92 + .../test/opt/simplification_test.cpp | 25 + .../test/opt/upgrade_memory_model_test.cpp | 2 +- .../spirv-tools/test/opt/vector_dce_test.cpp | 66 + .../spirv-tools/test/text_to_binary_test.cpp | 6 - .../spirv-tools/test/val/CMakeLists.txt | 2 + .../test/val/val_annotation_test.cpp | 951 +++ .../test/val/val_arithmetics_test.cpp | 51 + .../spirv-tools/test/val/val_atomics_test.cpp | 33 + .../test/val/val_builtins_test.cpp | 127 +- .../test/val/val_capability_test.cpp | 466 +- .../spirv-tools/test/val/val_cfg_test.cpp | 180 + .../test/val/val_composites_test.cpp | 23 +- .../test/val/val_decoration_test.cpp | 249 +- .../test/val/val_derivatives_test.cpp | 25 + .../test/val/val_ext_inst_debug_test.cpp | 5313 +++++++++++++++++ .../test/val/val_ext_inst_test.cpp | 2841 +-------- .../spirv-tools/test/val/val_id_test.cpp | 14 +- .../spirv-tools/test/val/val_image_test.cpp | 50 +- .../test/val/val_interfaces_test.cpp | 94 +- .../spirv-tools/test/val/val_layout_test.cpp | 2 - .../spirv-tools/test/val/val_memory_test.cpp | 123 +- .../spirv-tools/test/val/val_modes_test.cpp | 53 +- third_party/spirv-tools/test/wasm/test.js | 64 + third_party/spirv-tools/tools/CMakeLists.txt | 3 +- third_party/spirv-tools/tools/cfg/cfg.cpp | 10 +- third_party/spirv-tools/tools/fuzz/fuzz.cpp | 24 +- third_party/spirv-tools/tools/io.h | 4 +- third_party/spirv-tools/tools/lint/lint.cpp | 75 + third_party/spirv-tools/tools/opt/opt.cpp | 21 +- third_party/spirv-tools/tools/val/val.cpp | 4 + third_party/spirv-tools/utils/roll_deps.sh | 8 +- 529 files changed, 26363 insertions(+), 5855 deletions(-) delete mode 100644 third_party/spirv-tools/.appveyor.yml create mode 100644 third_party/spirv-tools/.github/workflows/wasm.yml create mode 100644 third_party/spirv-tools/FILAMENT_README.md create mode 100644 third_party/spirv-tools/docker-compose.yml create mode 100644 third_party/spirv-tools/external/spirv-headers/.github/workflows/presubmit.yml create mode 100644 third_party/spirv-tools/external/spirv-headers/SPIRV-Headers.pc.in create mode 100644 third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticShaderDebugInfo100.h create mode 100644 third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json create mode 100644 third_party/spirv-tools/include/spirv-tools/linter.hpp create mode 100755 third_party/spirv-tools/kokoro/linux-clang-ubsan/build.sh create mode 100644 third_party/spirv-tools/kokoro/linux-clang-ubsan/continuous.cfg create mode 100644 third_party/spirv-tools/kokoro/linux-clang-ubsan/presubmit.cfg create mode 100644 third_party/spirv-tools/source/common_debug_info.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.h create mode 100644 third_party/spirv-tools/source/lint/CMakeLists.txt create mode 100644 third_party/spirv-tools/source/lint/divergence_analysis.cpp create mode 100644 third_party/spirv-tools/source/lint/divergence_analysis.h create mode 100644 third_party/spirv-tools/source/lint/lint_divergent_derivatives.cpp create mode 100644 third_party/spirv-tools/source/lint/linter.cpp create mode 100644 third_party/spirv-tools/source/lint/lints.h create mode 100644 third_party/spirv-tools/source/opt/control_dependence.cpp create mode 100644 third_party/spirv-tools/source/opt/control_dependence.h create mode 100644 third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.h create mode 100644 third_party/spirv-tools/source/opt/dataflow.cpp create mode 100644 third_party/spirv-tools/source/opt/dataflow.h create mode 100644 third_party/spirv-tools/source/opt/desc_sroa_util.cpp create mode 100644 third_party/spirv-tools/source/opt/desc_sroa_util.h create mode 100644 third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.cpp create mode 100644 third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h create mode 100644 third_party/spirv-tools/source/wasm/README.md create mode 100755 third_party/spirv-tools/source/wasm/build.sh create mode 100644 third_party/spirv-tools/source/wasm/package.json create mode 100644 third_party/spirv-tools/source/wasm/spirv-tools.cpp create mode 100644 third_party/spirv-tools/source/wasm/spirv-tools.d.ts create mode 100644 third_party/spirv-tools/test/fuzz/transformation_wrap_vector_synonym_test.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/CMakeLists.txt create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_000.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_001.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_002.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_003.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_004.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_005.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_006.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_007.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_008.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_009.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_010.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_011.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_012.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_013.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_014.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_015.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_016.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_017.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_018.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_019.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_020.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_021.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_022.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_023.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_024.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_025.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_026.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_027.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_028.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_029.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_030.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_031.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_032.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_033.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_034.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_035.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_036.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_037.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_038.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_039.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_040.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_041.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_042.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_043.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_044.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_045.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_046.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_047.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_048.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_049.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_050.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_051.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_052.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_053.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_054.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_055.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_056.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_057.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_058.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_059.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_060.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_061.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_062.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_063.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_064.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_065.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_066.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_067.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_068.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_069.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_070.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_071.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_072.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_073.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_074.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_075.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_076.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_077.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_078.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_079.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_080.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_081.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_082.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_083.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_084.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_085.spv create mode 100644 third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_086.spv create mode 100644 third_party/spirv-tools/test/fuzzers/random_generator.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/random_generator.h create mode 100644 third_party/spirv-tools/test/fuzzers/spvtools_fuzz_fuzzer.cpp create mode 100644 third_party/spirv-tools/test/lint/CMakeLists.txt create mode 100644 third_party/spirv-tools/test/lint/divergence_analysis_test.cpp create mode 100644 third_party/spirv-tools/test/opt/control_dependence.cpp create mode 100644 third_party/spirv-tools/test/opt/convert_to_sampled_image_test.cpp create mode 100644 third_party/spirv-tools/test/opt/dataflow.cpp create mode 100644 third_party/spirv-tools/test/opt/replace_desc_array_access_using_var_index_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_annotation_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_ext_inst_debug_test.cpp create mode 100644 third_party/spirv-tools/test/wasm/test.js create mode 100644 third_party/spirv-tools/tools/lint/lint.cpp diff --git a/third_party/spirv-tools/.appveyor.yml b/third_party/spirv-tools/.appveyor.yml deleted file mode 100644 index 0a4cca05dc..0000000000 --- a/third_party/spirv-tools/.appveyor.yml +++ /dev/null @@ -1,90 +0,0 @@ -# Windows Build Configuration for AppVeyor -# http://www.appveyor.com/docs/appveyor-yml - -# version format -version: "{build}" - -# The most recent compiler gives the most interesting new results. -# Put it first so we get its feedback first. -os: - - Visual Studio 2017 - #- Visual Studio 2013 - -platform: - - x64 - -configuration: - - Debug - #- Release - -branches: - only: - - master - -# Travis advances the master-tot tag to current top of the tree after -# each push into the master branch, because it relies on that tag to -# upload build artifacts to the master-tot release. This will cause -# double testing for each push on Appveyor: one for the push, one for -# the tag advance. Disable testing tags. -skip_tags: true - -clone_depth: 1 - -matrix: - fast_finish: true # Show final status immediately if a test fails. - #exclude: - # - os: Visual Studio 2013 - # configuration: Debug - -# scripts that run after cloning repository -install: - # Install ninja - - set NINJA_URL="https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-win.zip" - - appveyor DownloadFile %NINJA_URL% -FileName ninja.zip - - 7z x ninja.zip -oC:\ninja > nul - - set PATH=C:\ninja;C:\Python36;%PATH% - -before_build: - - git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers.git external/spirv-headers - - git clone https://github.com/google/googletest.git external/googletest - - cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. - - git clone --depth=1 https://github.com/google/effcee.git external/effcee - - git clone --depth=1 https://github.com/google/re2.git external/re2 - # Set path and environment variables for the current Visual Studio version - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" (call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64) - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64) - -build: - parallel: true # enable MSBuild parallel builds - verbosity: minimal - -build_script: - - mkdir build && cd build - - 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 310 - -after_test: - # Zip build artifacts for uploading and deploying - - cd install - - 7z a SPIRV-Tools-master-windows-"%PLATFORM%"-"%CONFIGURATION%".zip *\* - -artifacts: - - path: build\install\*.zip - name: artifacts-zip - -deploy: - - provider: GitHub - auth_token: - secure: TMfcScKzzFIm1YgeV/PwCRXFDCw8Xm0wY2Vb2FU6WKlbzb5eUITTpr6I5vHPnAxS - release: master-tot - description: "Continuous build of the latest master branch by Appveyor and Travis CI" - artifact: artifacts-zip - draft: false - prerelease: false - force_update: true - on: - branch: master - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 diff --git a/third_party/spirv-tools/.github/workflows/wasm.yml b/third_party/spirv-tools/.github/workflows/wasm.yml new file mode 100644 index 0000000000..d9a9c5cb7c --- /dev/null +++ b/third_party/spirv-tools/.github/workflows/wasm.yml @@ -0,0 +1,14 @@ +name: Wasm Build + +on: [ push, pull_request ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Build web + run: docker-compose up + - name: Run tests + run: node test/wasm/test.js diff --git a/third_party/spirv-tools/.gitignore b/third_party/spirv-tools/.gitignore index b2af56e92b..22fb106d62 100644 --- a/third_party/spirv-tools/.gitignore +++ b/third_party/spirv-tools/.gitignore @@ -5,8 +5,6 @@ compile_commands.json /build/ /buildtools/ /external/googletest -/external/SPIRV-Headers -/external/spirv-headers /external/effcee /external/re2 /external/protobuf diff --git a/third_party/spirv-tools/Android.mk b/third_party/spirv-tools/Android.mk index 1bc844d400..bc748e535b 100644 --- a/third_party/spirv-tools/Android.mk +++ b/third_party/spirv-tools/Android.mk @@ -88,8 +88,11 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/composite.cpp \ source/opt/const_folding_rules.cpp \ source/opt/constants.cpp \ + source/opt/control_dependence.cpp \ + source/opt/convert_to_sampled_image_pass.cpp \ source/opt/convert_to_half_pass.cpp \ source/opt/copy_prop_arrays.cpp \ + source/opt/dataflow.cpp \ source/opt/dead_branch_elim_pass.cpp \ source/opt/dead_insert_elim_pass.cpp \ source/opt/dead_variable_elimination.cpp \ @@ -97,6 +100,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/debug_info_manager.cpp \ source/opt/def_use_manager.cpp \ source/opt/desc_sroa.cpp \ + source/opt/desc_sroa_util.cpp \ source/opt/dominator_analysis.cpp \ source/opt/dominator_tree.cpp \ source/opt/eliminate_dead_constant_pass.cpp \ @@ -154,6 +158,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/relax_float_ops_pass.cpp \ source/opt/remove_duplicates_pass.cpp \ source/opt/remove_unused_interface_variables_pass.cpp \ + source/opt/replace_desc_array_access_using_var_index.cpp \ source/opt/replace_invalid_opc.cpp \ source/opt/scalar_analysis.cpp \ source/opt/scalar_analysis_simplification.cpp \ @@ -181,6 +186,7 @@ SPV_GLSL_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.glsl.st SPV_OPENCL_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.opencl.std.100.grammar.json SPV_DEBUGINFO_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.debuginfo.grammar.json SPV_CLDEBUGINFO100_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.opencl.debuginfo.100.grammar.json +SPV_VKDEBUGINFO100_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json define gen_spvtools_grammar_tables $(call generate-file-dir,$(1)/core.insts-unified1.inc) @@ -212,6 +218,7 @@ $(LOCAL_PATH)/source/ext_inst.cpp: \ $(1)/opencl.std.insts.inc \ $(1)/debuginfo.insts.inc \ $(1)/opencl.debuginfo.100.insts.inc \ + $(1)/nonsemantic.shader.debuginfo.100.insts.inc \ $(1)/spv-amd-gcn-shader.insts.inc \ $(1)/spv-amd-shader-ballot.insts.inc \ $(1)/spv-amd-shader-explicit-vertex-parameter.insts.inc \ @@ -241,6 +248,7 @@ endef # We generate language-specific headers for DebugInfo and OpenCL.DebugInfo.100 $(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),DebugInfo,$(SPV_DEBUGINFO_GRAMMAR))) $(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),OpenCLDebugInfo100,$(SPV_CLDEBUGINFO100_GRAMMAR))) +$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),NonSemanticShaderDebugInfo100,$(SPV_VKDEBUGINFO100_GRAMMAR))) define gen_spvtools_vendor_tables @@ -258,6 +266,7 @@ endef # Vendor and debug extended instruction sets, with grammars from SPIRV-Tools source tree. $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),debuginfo,"")) $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),opencl.debuginfo.100,"CLDEBUG100_")) +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),nonsemantic.shader.debuginfo.100,"SHDEBUG100_")) $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-gcn-shader,"")) $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-ballot,"")) $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-explicit-vertex-parameter,"")) diff --git a/third_party/spirv-tools/BUILD.bazel b/third_party/spirv-tools/BUILD.bazel index 52290cfb34..b2031dede2 100644 --- a/third_party/spirv-tools/BUILD.bazel +++ b/third_party/spirv-tools/BUILD.bazel @@ -3,6 +3,7 @@ load( "COMMON_COPTS", "DEBUGINFO_GRAMMAR_JSON_FILE", "CLDEBUGINFO100_GRAMMAR_JSON_FILE", + "SHDEBUGINFO100_GRAMMAR_JSON_FILE", "TEST_COPTS", "base_test", "generate_core_tables", @@ -12,6 +13,7 @@ load( "generate_opencl_tables", "generate_vendor_tables", "link_test", + "lint_test", "opt_test", "reduce_test", "util_test", @@ -59,12 +61,16 @@ generate_vendor_tables("debuginfo") generate_vendor_tables("opencl.debuginfo.100", "CLDEBUG100_") +generate_vendor_tables("nonsemantic.shader.debuginfo.100", "SHDEBUG100_") + generate_vendor_tables("nonsemantic.clspvreflection") generate_extinst_lang_headers("DebugInfo", DEBUGINFO_GRAMMAR_JSON_FILE) generate_extinst_lang_headers("OpenCLDebugInfo100", CLDEBUGINFO100_GRAMMAR_JSON_FILE) +generate_extinst_lang_headers("NonSemanticShaderDebugInfo100", SHDEBUGINFO100_GRAMMAR_JSON_FILE) + py_binary( name = "generate_registry_tables", srcs = ["utils/generate_registry_tables.py"], @@ -101,12 +107,14 @@ cc_library( ":gen_enum_string_mapping", ":gen_extinst_lang_headers_DebugInfo", ":gen_extinst_lang_headers_OpenCLDebugInfo100", + ":gen_extinst_lang_headers_NonSemanticShaderDebugInfo100", ":gen_glsl_tables_unified1", ":gen_opencl_tables_unified1", ":gen_registry_tables", ":gen_vendor_tables_debuginfo", ":gen_vendor_tables_nonsemantic_clspvreflection", ":gen_vendor_tables_opencl_debuginfo_100", + ":gen_vendor_tables_nonsemantic_shader_debuginfo_100", ":gen_vendor_tables_spv_amd_gcn_shader", ":gen_vendor_tables_spv_amd_shader_ballot", ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter", @@ -225,6 +233,19 @@ cc_library( ], ) +cc_library( + name = "spirv_tools_lint", + srcs = glob(["source/lint/*.cpp", "source/lint/*.h"]), + hdrs = ["include/spirv-tools/linter.hpp"], + copts = COMMON_COPTS, + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_opt", + ], +) + cc_library( name = "tools_util", srcs = glob(["tools/util/*.cpp"]), @@ -322,6 +343,21 @@ cc_binary( ], ) +cc_binary( + name = "spirv-lint", + srcs = [ + "tools/io.h", + "tools/lint/lint.cpp", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_lint", + ":tools_util", + ], +) + cc_binary( name = "spirv-cfg", srcs = [ @@ -465,6 +501,13 @@ base_test( ["test/link/*.cpp"], )] +[lint_test( + name = f[10:-4], # strip test/lint/, .cpp + srcs = [f], +) for f in glob( + ["test/lint/*.cpp"], +)] + [opt_test( name = f[9:-4], # strip test/opt/, .cpp srcs = [f], diff --git a/third_party/spirv-tools/BUILD.gn b/third_party/spirv-tools/BUILD.gn index 996905a2d7..309d51373b 100644 --- a/third_party/spirv-tools/BUILD.gn +++ b/third_party/spirv-tools/BUILD.gn @@ -16,6 +16,7 @@ import("//build_overrides/build.gni") import("//build_overrides/spirv_tools.gni") if (build_with_chromium) { import("//testing/test.gni") + import("//third_party/protobuf/proto_library.gni") } spirv_headers = spirv_tools_spirv_headers_dir @@ -275,6 +276,10 @@ spvtools_language_header("cldebuginfo100") { name = "OpenCLDebugInfo100" grammar_file = "${spirv_headers}/include/spirv/unified1/extinst.opencl.debuginfo.100.grammar.json" } +spvtools_language_header("vkdebuginfo100") { + name = "NonSemanticShaderDebugInfo100" + grammar_file = "${spirv_headers}/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json" +} spvtools_vendor_tables = [ [ @@ -305,6 +310,10 @@ spvtools_vendor_tables = [ "nonsemantic.clspvreflection", "...nil...", ], + [ + "nonsemantic.shader.debuginfo.100", + "SHDEBUG100_", + ], ] foreach(table_def, spvtools_vendor_tables) { @@ -318,20 +327,28 @@ config("spvtools_public_config") { include_dirs = [ "include" ] } +config("spvtools_include_gen_dirs") { + include_dirs = [ "$target_gen_dir" ] +} + config("spvtools_internal_config") { include_dirs = [ ".", - "$target_gen_dir", "${spirv_headers}/include", ] - configs = [ ":spvtools_public_config" ] + configs = [ + ":spvtools_public_config", + ":spvtools_include_gen_dirs", + ] cflags = [] if (is_clang) { cflags += [ "-Wno-implicit-fallthrough", "-Wno-newline-eof", + "-Wno-unreachable-code-break", + "-Wno-unreachable-code-return", ] } else if (!is_win) { # Work around a false-positive on a Skia GCC 10 builder. @@ -351,6 +368,14 @@ source_set("spvtools_headers") { public_configs = [ ":spvtools_public_config" ] } +group("spvtools_language_headers") { + public_deps = [ + ":spvtools_language_header_cldebuginfo100", + ":spvtools_language_header_debuginfo", + ":spvtools_language_header_vkdebuginfo100", + ] +} + static_library("spvtools") { deps = [ ":spvtools_core_tables_unified1", @@ -358,6 +383,7 @@ static_library("spvtools") { ":spvtools_glsl_tables_glsl1-0", ":spvtools_language_header_cldebuginfo100", ":spvtools_language_header_debuginfo", + ":spvtools_language_header_vkdebuginfo100", ":spvtools_opencl_tables_opencl1-0", ] foreach(table_def, spvtools_vendor_tables) { @@ -371,6 +397,7 @@ static_library("spvtools") { "source/binary.cpp", "source/binary.h", "source/cfa.h", + "source/common_debug_info.h", "source/diagnostic.cpp", "source/diagnostic.h", "source/disassemble.cpp", @@ -402,8 +429,12 @@ static_library("spvtools") { "source/spirv_definition.h", "source/spirv_endian.cpp", "source/spirv_endian.h", + "source/spirv_fuzzer_options.cpp", + "source/spirv_fuzzer_options.h", "source/spirv_optimizer_options.cpp", "source/spirv_optimizer_options.h", + "source/spirv_reducer_options.cpp", + "source/spirv_reducer_options.h", "source/spirv_target_env.cpp", "source/spirv_target_env.h", "source/spirv_validator_options.cpp", @@ -499,6 +530,7 @@ static_library("spvtools_val") { ":spvtools", ":spvtools_language_header_cldebuginfo100", ":spvtools_language_header_debuginfo", + ":spvtools_language_header_vkdebuginfo100", ] public_deps = [ ":spvtools_headers" ] @@ -541,10 +573,16 @@ static_library("spvtools_opt") { "source/opt/const_folding_rules.h", "source/opt/constants.cpp", "source/opt/constants.h", + "source/opt/control_dependence.cpp", + "source/opt/control_dependence.h", "source/opt/convert_to_half_pass.cpp", "source/opt/convert_to_half_pass.h", + "source/opt/convert_to_sampled_image_pass.cpp", + "source/opt/convert_to_sampled_image_pass.h", "source/opt/copy_prop_arrays.cpp", "source/opt/copy_prop_arrays.h", + "source/opt/dataflow.cpp", + "source/opt/dataflow.h", "source/opt/dead_branch_elim_pass.cpp", "source/opt/dead_branch_elim_pass.h", "source/opt/dead_insert_elim_pass.cpp", @@ -559,6 +597,8 @@ static_library("spvtools_opt") { "source/opt/def_use_manager.h", "source/opt/desc_sroa.cpp", "source/opt/desc_sroa.h", + "source/opt/desc_sroa_util.cpp", + "source/opt/desc_sroa_util.h", "source/opt/dominator_analysis.cpp", "source/opt/dominator_analysis.h", "source/opt/dominator_tree.cpp", @@ -678,6 +718,8 @@ static_library("spvtools_opt") { "source/opt/remove_duplicates_pass.h", "source/opt/remove_unused_interface_variables_pass.cpp", "source/opt/remove_unused_interface_variables_pass.h", + "source/opt/replace_desc_array_access_using_var_index.cpp", + "source/opt/replace_desc_array_access_using_var_index.h", "source/opt/replace_invalid_opc.cpp", "source/opt/replace_invalid_opc.h", "source/opt/scalar_analysis.cpp", @@ -721,11 +763,14 @@ static_library("spvtools_opt") { deps = [ ":spvtools", - ":spvtools_language_header_cldebuginfo100", ":spvtools_language_header_debuginfo", ":spvtools_vendor_tables_spv-amd-shader-ballot", ] - public_deps = [ ":spvtools_headers" ] + public_deps = [ + ":spvtools_headers", + ":spvtools_language_header_cldebuginfo100", + ":spvtools_language_header_vkdebuginfo100", + ] if (build_with_chromium) { configs -= [ "//build/config/compiler:chromium_code" ] @@ -811,8 +856,6 @@ static_library("spvtools_reduce") { "source/reduce/structured_loop_to_selection_reduction_opportunity.h", "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp", "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h", - "source/spirv_reducer_options.cpp", - "source/spirv_reducer_options.h", ] deps = [ ":spvtools", @@ -826,6 +869,423 @@ static_library("spvtools_reduce") { configs += [ ":spvtools_internal_config" ] } +if (build_with_chromium) { + # The spirv-fuzz library is only built when in a Chromium checkout + # due to its dependency on protobuf. + + proto_library("spvtools_fuzz_proto") { + sources = [ "source/fuzz/protobufs/spvtoolsfuzz.proto" ] + generate_python = false + use_protobuf_full = true + } + + static_library("spvtools_fuzz") { + sources = [ + "source/fuzz/added_function_reducer.cpp", + "source/fuzz/added_function_reducer.h", + "source/fuzz/available_instructions.cpp", + "source/fuzz/available_instructions.h", + "source/fuzz/call_graph.cpp", + "source/fuzz/call_graph.h", + "source/fuzz/comparator_deep_blocks_first.h", + "source/fuzz/counter_overflow_id_source.cpp", + "source/fuzz/counter_overflow_id_source.h", + "source/fuzz/data_descriptor.cpp", + "source/fuzz/data_descriptor.h", + "source/fuzz/equivalence_relation.h", + "source/fuzz/fact_manager/constant_uniform_facts.cpp", + "source/fuzz/fact_manager/constant_uniform_facts.h", + "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp", + "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h", + "source/fuzz/fact_manager/dead_block_facts.cpp", + "source/fuzz/fact_manager/dead_block_facts.h", + "source/fuzz/fact_manager/fact_manager.cpp", + "source/fuzz/fact_manager/fact_manager.h", + "source/fuzz/fact_manager/irrelevant_value_facts.cpp", + "source/fuzz/fact_manager/irrelevant_value_facts.h", + "source/fuzz/fact_manager/livesafe_function_facts.cpp", + "source/fuzz/fact_manager/livesafe_function_facts.h", + "source/fuzz/force_render_red.cpp", + "source/fuzz/force_render_red.h", + "source/fuzz/fuzzer.cpp", + "source/fuzz/fuzzer.h", + "source/fuzz/fuzzer_context.cpp", + "source/fuzz/fuzzer_context.h", + "source/fuzz/fuzzer_pass.cpp", + "source/fuzz/fuzzer_pass.h", + "source/fuzz/fuzzer_pass_add_access_chains.cpp", + "source/fuzz/fuzzer_pass_add_access_chains.h", + "source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp", + "source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h", + "source/fuzz/fuzzer_pass_add_composite_extract.cpp", + "source/fuzz/fuzzer_pass_add_composite_extract.h", + "source/fuzz/fuzzer_pass_add_composite_inserts.cpp", + "source/fuzz/fuzzer_pass_add_composite_inserts.h", + "source/fuzz/fuzzer_pass_add_composite_types.cpp", + "source/fuzz/fuzzer_pass_add_composite_types.h", + "source/fuzz/fuzzer_pass_add_copy_memory.cpp", + "source/fuzz/fuzzer_pass_add_copy_memory.h", + "source/fuzz/fuzzer_pass_add_dead_blocks.cpp", + "source/fuzz/fuzzer_pass_add_dead_blocks.h", + "source/fuzz/fuzzer_pass_add_dead_breaks.cpp", + "source/fuzz/fuzzer_pass_add_dead_breaks.h", + "source/fuzz/fuzzer_pass_add_dead_continues.cpp", + "source/fuzz/fuzzer_pass_add_dead_continues.h", + "source/fuzz/fuzzer_pass_add_equation_instructions.cpp", + "source/fuzz/fuzzer_pass_add_equation_instructions.h", + "source/fuzz/fuzzer_pass_add_function_calls.cpp", + "source/fuzz/fuzzer_pass_add_function_calls.h", + "source/fuzz/fuzzer_pass_add_global_variables.cpp", + "source/fuzz/fuzzer_pass_add_global_variables.h", + "source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp", + "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h", + "source/fuzz/fuzzer_pass_add_loads.cpp", + "source/fuzz/fuzzer_pass_add_loads.h", + "source/fuzz/fuzzer_pass_add_local_variables.cpp", + "source/fuzz/fuzzer_pass_add_local_variables.h", + "source/fuzz/fuzzer_pass_add_loop_preheaders.cpp", + "source/fuzz/fuzzer_pass_add_loop_preheaders.h", + "source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp", + "source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h", + "source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp", + "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h", + "source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp", + "source/fuzz/fuzzer_pass_add_opphi_synonyms.h", + "source/fuzz/fuzzer_pass_add_parameters.cpp", + "source/fuzz/fuzzer_pass_add_parameters.h", + "source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp", + "source/fuzz/fuzzer_pass_add_relaxed_decorations.h", + "source/fuzz/fuzzer_pass_add_stores.cpp", + "source/fuzz/fuzzer_pass_add_stores.h", + "source/fuzz/fuzzer_pass_add_synonyms.cpp", + "source/fuzz/fuzzer_pass_add_synonyms.h", + "source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp", + "source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h", + "source/fuzz/fuzzer_pass_adjust_branch_weights.cpp", + "source/fuzz/fuzzer_pass_adjust_branch_weights.h", + "source/fuzz/fuzzer_pass_adjust_function_controls.cpp", + "source/fuzz/fuzzer_pass_adjust_function_controls.h", + "source/fuzz/fuzzer_pass_adjust_loop_controls.cpp", + "source/fuzz/fuzzer_pass_adjust_loop_controls.h", + "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp", + "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h", + "source/fuzz/fuzzer_pass_adjust_selection_controls.cpp", + "source/fuzz/fuzzer_pass_adjust_selection_controls.h", + "source/fuzz/fuzzer_pass_apply_id_synonyms.cpp", + "source/fuzz/fuzzer_pass_apply_id_synonyms.h", + "source/fuzz/fuzzer_pass_construct_composites.cpp", + "source/fuzz/fuzzer_pass_construct_composites.h", + "source/fuzz/fuzzer_pass_copy_objects.cpp", + "source/fuzz/fuzzer_pass_copy_objects.h", + "source/fuzz/fuzzer_pass_donate_modules.cpp", + "source/fuzz/fuzzer_pass_donate_modules.h", + "source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp", + "source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h", + "source/fuzz/fuzzer_pass_expand_vector_reductions.cpp", + "source/fuzz/fuzzer_pass_expand_vector_reductions.h", + "source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp", + "source/fuzz/fuzzer_pass_flatten_conditional_branches.h", + "source/fuzz/fuzzer_pass_inline_functions.cpp", + "source/fuzz/fuzzer_pass_inline_functions.h", + "source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp", + "source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h", + "source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp", + "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h", + "source/fuzz/fuzzer_pass_invert_comparison_operators.cpp", + "source/fuzz/fuzzer_pass_invert_comparison_operators.h", + "source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp", + "source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h", + "source/fuzz/fuzzer_pass_merge_blocks.cpp", + "source/fuzz/fuzzer_pass_merge_blocks.h", + "source/fuzz/fuzzer_pass_merge_function_returns.cpp", + "source/fuzz/fuzzer_pass_merge_function_returns.h", + "source/fuzz/fuzzer_pass_mutate_pointers.cpp", + "source/fuzz/fuzzer_pass_mutate_pointers.h", + "source/fuzz/fuzzer_pass_obfuscate_constants.cpp", + "source/fuzz/fuzzer_pass_obfuscate_constants.h", + "source/fuzz/fuzzer_pass_outline_functions.cpp", + "source/fuzz/fuzzer_pass_outline_functions.h", + "source/fuzz/fuzzer_pass_permute_blocks.cpp", + "source/fuzz/fuzzer_pass_permute_blocks.h", + "source/fuzz/fuzzer_pass_permute_function_parameters.cpp", + "source/fuzz/fuzzer_pass_permute_function_parameters.h", + "source/fuzz/fuzzer_pass_permute_function_variables.cpp", + "source/fuzz/fuzzer_pass_permute_function_variables.h", + "source/fuzz/fuzzer_pass_permute_instructions.cpp", + "source/fuzz/fuzzer_pass_permute_instructions.h", + "source/fuzz/fuzzer_pass_permute_phi_operands.cpp", + "source/fuzz/fuzzer_pass_permute_phi_operands.h", + "source/fuzz/fuzzer_pass_propagate_instructions_down.cpp", + "source/fuzz/fuzzer_pass_propagate_instructions_down.h", + "source/fuzz/fuzzer_pass_propagate_instructions_up.cpp", + "source/fuzz/fuzzer_pass_propagate_instructions_up.h", + "source/fuzz/fuzzer_pass_push_ids_through_variables.cpp", + "source/fuzz/fuzzer_pass_push_ids_through_variables.h", + "source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp", + "source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h", + "source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp", + "source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h", + "source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp", + "source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h", + "source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp", + "source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h", + "source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp", + "source/fuzz/fuzzer_pass_replace_irrelevant_ids.h", + "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp", + "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h", + "source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp", + "source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h", + "source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp", + "source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h", + "source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp", + "source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h", + "source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp", + "source/fuzz/fuzzer_pass_replace_parameter_with_global.h", + "source/fuzz/fuzzer_pass_replace_params_with_struct.cpp", + "source/fuzz/fuzzer_pass_replace_params_with_struct.h", + "source/fuzz/fuzzer_pass_split_blocks.cpp", + "source/fuzz/fuzzer_pass_split_blocks.h", + "source/fuzz/fuzzer_pass_swap_commutable_operands.cpp", + "source/fuzz/fuzzer_pass_swap_commutable_operands.h", + "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp", + "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h", + "source/fuzz/fuzzer_pass_swap_functions.cpp", + "source/fuzz/fuzzer_pass_swap_functions.h", + "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp", + "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h", + "source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp", + "source/fuzz/fuzzer_pass_wrap_regions_in_selections.h", + "source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp", + "source/fuzz/fuzzer_pass_wrap_vector_synonym.h", + "source/fuzz/fuzzer_util.cpp", + "source/fuzz/fuzzer_util.h", + "source/fuzz/id_use_descriptor.cpp", + "source/fuzz/id_use_descriptor.h", + "source/fuzz/instruction_descriptor.cpp", + "source/fuzz/instruction_descriptor.h", + "source/fuzz/instruction_message.cpp", + "source/fuzz/instruction_message.h", + "source/fuzz/overflow_id_source.cpp", + "source/fuzz/overflow_id_source.h", + "source/fuzz/pass_management/repeated_pass_instances.h", + "source/fuzz/pass_management/repeated_pass_manager.cpp", + "source/fuzz/pass_management/repeated_pass_manager.h", + "source/fuzz/pass_management/repeated_pass_manager_looped_with_recommendations.cpp", + "source/fuzz/pass_management/repeated_pass_manager_looped_with_recommendations.h", + "source/fuzz/pass_management/repeated_pass_manager_random_with_recommendations.cpp", + "source/fuzz/pass_management/repeated_pass_manager_random_with_recommendations.h", + "source/fuzz/pass_management/repeated_pass_manager_simple.cpp", + "source/fuzz/pass_management/repeated_pass_manager_simple.h", + "source/fuzz/pass_management/repeated_pass_recommender.cpp", + "source/fuzz/pass_management/repeated_pass_recommender.h", + "source/fuzz/pass_management/repeated_pass_recommender_standard.cpp", + "source/fuzz/pass_management/repeated_pass_recommender_standard.h", + "source/fuzz/protobufs/spirvfuzz_protobufs.h", + "source/fuzz/pseudo_random_generator.cpp", + "source/fuzz/pseudo_random_generator.h", + "source/fuzz/random_generator.cpp", + "source/fuzz/random_generator.h", + "source/fuzz/replayer.cpp", + "source/fuzz/replayer.h", + "source/fuzz/shrinker.cpp", + "source/fuzz/shrinker.h", + "source/fuzz/transformation.cpp", + "source/fuzz/transformation.h", + "source/fuzz/transformation_access_chain.cpp", + "source/fuzz/transformation_access_chain.h", + "source/fuzz/transformation_add_bit_instruction_synonym.cpp", + "source/fuzz/transformation_add_bit_instruction_synonym.h", + "source/fuzz/transformation_add_constant_boolean.cpp", + "source/fuzz/transformation_add_constant_boolean.h", + "source/fuzz/transformation_add_constant_composite.cpp", + "source/fuzz/transformation_add_constant_composite.h", + "source/fuzz/transformation_add_constant_null.cpp", + "source/fuzz/transformation_add_constant_null.h", + "source/fuzz/transformation_add_constant_scalar.cpp", + "source/fuzz/transformation_add_constant_scalar.h", + "source/fuzz/transformation_add_copy_memory.cpp", + "source/fuzz/transformation_add_copy_memory.h", + "source/fuzz/transformation_add_dead_block.cpp", + "source/fuzz/transformation_add_dead_block.h", + "source/fuzz/transformation_add_dead_break.cpp", + "source/fuzz/transformation_add_dead_break.h", + "source/fuzz/transformation_add_dead_continue.cpp", + "source/fuzz/transformation_add_dead_continue.h", + "source/fuzz/transformation_add_early_terminator_wrapper.cpp", + "source/fuzz/transformation_add_early_terminator_wrapper.h", + "source/fuzz/transformation_add_function.cpp", + "source/fuzz/transformation_add_function.h", + "source/fuzz/transformation_add_global_undef.cpp", + "source/fuzz/transformation_add_global_undef.h", + "source/fuzz/transformation_add_global_variable.cpp", + "source/fuzz/transformation_add_global_variable.h", + "source/fuzz/transformation_add_image_sample_unused_components.cpp", + "source/fuzz/transformation_add_image_sample_unused_components.h", + "source/fuzz/transformation_add_local_variable.cpp", + "source/fuzz/transformation_add_local_variable.h", + "source/fuzz/transformation_add_loop_preheader.cpp", + "source/fuzz/transformation_add_loop_preheader.h", + "source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp", + "source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h", + "source/fuzz/transformation_add_no_contraction_decoration.cpp", + "source/fuzz/transformation_add_no_contraction_decoration.h", + "source/fuzz/transformation_add_opphi_synonym.cpp", + "source/fuzz/transformation_add_opphi_synonym.h", + "source/fuzz/transformation_add_parameter.cpp", + "source/fuzz/transformation_add_parameter.h", + "source/fuzz/transformation_add_relaxed_decoration.cpp", + "source/fuzz/transformation_add_relaxed_decoration.h", + "source/fuzz/transformation_add_spec_constant_op.cpp", + "source/fuzz/transformation_add_spec_constant_op.h", + "source/fuzz/transformation_add_synonym.cpp", + "source/fuzz/transformation_add_synonym.h", + "source/fuzz/transformation_add_type_array.cpp", + "source/fuzz/transformation_add_type_array.h", + "source/fuzz/transformation_add_type_boolean.cpp", + "source/fuzz/transformation_add_type_boolean.h", + "source/fuzz/transformation_add_type_float.cpp", + "source/fuzz/transformation_add_type_float.h", + "source/fuzz/transformation_add_type_function.cpp", + "source/fuzz/transformation_add_type_function.h", + "source/fuzz/transformation_add_type_int.cpp", + "source/fuzz/transformation_add_type_int.h", + "source/fuzz/transformation_add_type_matrix.cpp", + "source/fuzz/transformation_add_type_matrix.h", + "source/fuzz/transformation_add_type_pointer.cpp", + "source/fuzz/transformation_add_type_pointer.h", + "source/fuzz/transformation_add_type_struct.cpp", + "source/fuzz/transformation_add_type_struct.h", + "source/fuzz/transformation_add_type_vector.cpp", + "source/fuzz/transformation_add_type_vector.h", + "source/fuzz/transformation_adjust_branch_weights.cpp", + "source/fuzz/transformation_adjust_branch_weights.h", + "source/fuzz/transformation_composite_construct.cpp", + "source/fuzz/transformation_composite_construct.h", + "source/fuzz/transformation_composite_extract.cpp", + "source/fuzz/transformation_composite_extract.h", + "source/fuzz/transformation_composite_insert.cpp", + "source/fuzz/transformation_composite_insert.h", + "source/fuzz/transformation_compute_data_synonym_fact_closure.cpp", + "source/fuzz/transformation_compute_data_synonym_fact_closure.h", + "source/fuzz/transformation_context.cpp", + "source/fuzz/transformation_context.h", + "source/fuzz/transformation_duplicate_region_with_selection.cpp", + "source/fuzz/transformation_duplicate_region_with_selection.h", + "source/fuzz/transformation_equation_instruction.cpp", + "source/fuzz/transformation_equation_instruction.h", + "source/fuzz/transformation_expand_vector_reduction.cpp", + "source/fuzz/transformation_expand_vector_reduction.h", + "source/fuzz/transformation_flatten_conditional_branch.cpp", + "source/fuzz/transformation_flatten_conditional_branch.h", + "source/fuzz/transformation_function_call.cpp", + "source/fuzz/transformation_function_call.h", + "source/fuzz/transformation_inline_function.cpp", + "source/fuzz/transformation_inline_function.h", + "source/fuzz/transformation_invert_comparison_operator.cpp", + "source/fuzz/transformation_invert_comparison_operator.h", + "source/fuzz/transformation_load.cpp", + "source/fuzz/transformation_load.h", + "source/fuzz/transformation_make_vector_operation_dynamic.cpp", + "source/fuzz/transformation_make_vector_operation_dynamic.h", + "source/fuzz/transformation_merge_blocks.cpp", + "source/fuzz/transformation_merge_blocks.h", + "source/fuzz/transformation_merge_function_returns.cpp", + "source/fuzz/transformation_merge_function_returns.h", + "source/fuzz/transformation_move_block_down.cpp", + "source/fuzz/transformation_move_block_down.h", + "source/fuzz/transformation_move_instruction_down.cpp", + "source/fuzz/transformation_move_instruction_down.h", + "source/fuzz/transformation_mutate_pointer.cpp", + "source/fuzz/transformation_mutate_pointer.h", + "source/fuzz/transformation_outline_function.cpp", + "source/fuzz/transformation_outline_function.h", + "source/fuzz/transformation_permute_function_parameters.cpp", + "source/fuzz/transformation_permute_function_parameters.h", + "source/fuzz/transformation_permute_phi_operands.cpp", + "source/fuzz/transformation_permute_phi_operands.h", + "source/fuzz/transformation_propagate_instruction_down.cpp", + "source/fuzz/transformation_propagate_instruction_down.h", + "source/fuzz/transformation_propagate_instruction_up.cpp", + "source/fuzz/transformation_propagate_instruction_up.h", + "source/fuzz/transformation_push_id_through_variable.cpp", + "source/fuzz/transformation_push_id_through_variable.h", + "source/fuzz/transformation_record_synonymous_constants.cpp", + "source/fuzz/transformation_record_synonymous_constants.h", + "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp", + "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h", + "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp", + "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h", + "source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp", + "source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h", + "source/fuzz/transformation_replace_constant_with_uniform.cpp", + "source/fuzz/transformation_replace_constant_with_uniform.h", + "source/fuzz/transformation_replace_copy_memory_with_load_store.cpp", + "source/fuzz/transformation_replace_copy_memory_with_load_store.h", + "source/fuzz/transformation_replace_copy_object_with_store_load.cpp", + "source/fuzz/transformation_replace_copy_object_with_store_load.h", + "source/fuzz/transformation_replace_id_with_synonym.cpp", + "source/fuzz/transformation_replace_id_with_synonym.h", + "source/fuzz/transformation_replace_irrelevant_id.cpp", + "source/fuzz/transformation_replace_irrelevant_id.h", + "source/fuzz/transformation_replace_linear_algebra_instruction.cpp", + "source/fuzz/transformation_replace_linear_algebra_instruction.h", + "source/fuzz/transformation_replace_load_store_with_copy_memory.cpp", + "source/fuzz/transformation_replace_load_store_with_copy_memory.h", + "source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp", + "source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.h", + "source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp", + "source/fuzz/transformation_replace_opselect_with_conditional_branch.h", + "source/fuzz/transformation_replace_parameter_with_global.cpp", + "source/fuzz/transformation_replace_parameter_with_global.h", + "source/fuzz/transformation_replace_params_with_struct.cpp", + "source/fuzz/transformation_replace_params_with_struct.h", + "source/fuzz/transformation_set_function_control.cpp", + "source/fuzz/transformation_set_function_control.h", + "source/fuzz/transformation_set_loop_control.cpp", + "source/fuzz/transformation_set_loop_control.h", + "source/fuzz/transformation_set_memory_operands_mask.cpp", + "source/fuzz/transformation_set_memory_operands_mask.h", + "source/fuzz/transformation_set_selection_control.cpp", + "source/fuzz/transformation_set_selection_control.h", + "source/fuzz/transformation_split_block.cpp", + "source/fuzz/transformation_split_block.h", + "source/fuzz/transformation_store.cpp", + "source/fuzz/transformation_store.h", + "source/fuzz/transformation_swap_commutable_operands.cpp", + "source/fuzz/transformation_swap_commutable_operands.h", + "source/fuzz/transformation_swap_conditional_branch_operands.cpp", + "source/fuzz/transformation_swap_conditional_branch_operands.h", + "source/fuzz/transformation_swap_function_variables.cpp", + "source/fuzz/transformation_swap_function_variables.h", + "source/fuzz/transformation_swap_two_functions.cpp", + "source/fuzz/transformation_swap_two_functions.h", + "source/fuzz/transformation_toggle_access_chain_instruction.cpp", + "source/fuzz/transformation_toggle_access_chain_instruction.h", + "source/fuzz/transformation_vector_shuffle.cpp", + "source/fuzz/transformation_vector_shuffle.h", + "source/fuzz/transformation_wrap_early_terminator_in_function.cpp", + "source/fuzz/transformation_wrap_early_terminator_in_function.h", + "source/fuzz/transformation_wrap_region_in_selection.cpp", + "source/fuzz/transformation_wrap_region_in_selection.h", + "source/fuzz/transformation_wrap_vector_synonym.cpp", + "source/fuzz/transformation_wrap_vector_synonym.h", + "source/fuzz/uniform_buffer_element_descriptor.cpp", + "source/fuzz/uniform_buffer_element_descriptor.h", + ] + deps = [ + ":spvtools", + ":spvtools_fuzz_proto", + ":spvtools_opt", + ":spvtools_reduce", + "//third_party/protobuf:protobuf_full", + ] + public_deps = [ ":spvtools_headers" ] + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ ":spvtools_internal_config" ] + } +} + group("SPIRV-Tools") { public_deps = [ ":spvtools", @@ -905,6 +1365,7 @@ if (build_with_chromium) { ":spvtools", ":spvtools_language_header_cldebuginfo100", ":spvtools_language_header_debuginfo", + ":spvtools_language_header_vkdebuginfo100", ":spvtools_val", "//testing/gmock", "//testing/gtest", @@ -1012,8 +1473,31 @@ executable("spirv-link") { configs += [ ":spvtools_internal_config" ] } +if (!is_ios && !spirv_is_winuwp && build_with_chromium) { + # iOS and UWP do not allow std::system calls which spirv-fuzz + # requires. Additionally, spirv-fuzz is only built when in a + # Chromium checkout due to its dependency on protobuf. + + executable("spirv-fuzz") { + sources = [ "tools/fuzz/fuzz.cpp" ] + deps = [ + ":spvtools", + ":spvtools_fuzz", + ":spvtools_opt", + ":spvtools_reduce", + ":spvtools_software_version", + ":spvtools_util_cli_consumer", + ":spvtools_val", + "//third_party/protobuf:protobuf_full", + ] + configs += [ ":spvtools_internal_config" ] + } +} + if (!is_ios && !spirv_is_winuwp) { - # iOS and UWP do not allow std::system calls which spirv-reduce requires + # iOS and UWP do not allow std::system calls which spirv-reduce + # requires. + executable("spirv-reduce") { sources = [ "tools/reduce/reduce.cpp" ] deps = [ @@ -1037,6 +1521,9 @@ group("all_spirv_tools") { ":spirv-opt", ":spirv-val", ] + if (!is_ios && !spirv_is_winuwp && build_with_chromium) { + deps += [ ":spirv-fuzz" ] + } if (!is_ios && !spirv_is_winuwp) { deps += [ ":spirv-reduce" ] } diff --git a/third_party/spirv-tools/CHANGES b/third_party/spirv-tools/CHANGES index 467655ccfe..ee232b6075 100644 --- a/third_party/spirv-tools/CHANGES +++ b/third_party/spirv-tools/CHANGES @@ -1,7 +1,44 @@ Revision history for SPIRV-Tools -v2021.3-dev 2021-06-22 - - Start v2021.3-dev +v2021.4 2021-11-11 + - General + - Add a WebAssembly build (#3752) + - Make cxx exceptions controllable (#4591) + - Validator + - Improve decoration validation (#4490) + - Optimizer + - Add spirv-opt pass to replace descriptor accesses based on variable indices (#4574) + - Do not fold snegate feeding sdiv (#4600) + - Handle overflowing id in merge return (#4606) + - Fuzzer + - Add libFuzzer target for spirv-fuzz (#4434) + - Linter + +v2021.3 2021-08-24 + - General + - Initial support for SPV_KHR_integer_dot_product (#4327) + - Add non-semantic vulkan extended instruction set (#4362) + - Add common enum for debug info instructions from either opencl or vulkan (#4377) + - Validator + - Add validation for SPV_EXT_shader_atomic_float16_add (#4325) + - Disallow loading a runtime-sized array (#4473) + - spirv-val: Validate vulkan debug info similarly to opencl debug info (#4466) + - Optimizer + - spirv-opt: support SPV_EXT_shader_image_int64 (#4379) + - spirv-opt: Add dataflow analysis framework (#4402) + - Add control dependence analysis to opt (#4380) + - Add spirv-opt convert-to-sampled-image pass (#4340) + - spirv-opt: Add handling of vulkan debug info to DebugInfoManager (#4423) + - Fuzz + - spirv-fuzz: support AtomicLoad (#4330) + - spirv-fuzz: Support AtomicStore (#4440) + - spirv-fuzz: TransformationWrapVectorSynonym that rewrites scalar operations using vectors (#4376) + - spirv-fuzz: Add minimal SPIR-V example to test shaders (#4415) + - spirv-fuzz: support building using gn (#4365) + - Linter + - Add new target for spirv-lint (#4446) + - spirv-lint: add basic CLI argument handling (#4478) + - Add divergence analysis to linter (#4465) v2021.2 2021-06-18 - General diff --git a/third_party/spirv-tools/CMakeLists.txt b/third_party/spirv-tools/CMakeLists.txt index 5530f8c4f3..3991bf6605 100755 --- a/third_party/spirv-tools/CMakeLists.txt +++ b/third_party/spirv-tools/CMakeLists.txt @@ -44,6 +44,7 @@ include(GNUInstallDirs) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_CXX_STANDARD 11) +option(ENABLE_RTTI "Enables RTTI" OFF) option(SPIRV_ALLOW_TIMERS "Allow timers via clock_gettime on supported platforms" ON) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") @@ -96,6 +97,10 @@ endif(SPIRV_BUILD_COMPRESSION) option(SPIRV_BUILD_FUZZER "Build spirv-fuzz" OFF) +set(SPIRV_LIB_FUZZING_ENGINE_LINK_OPTIONS "" CACHE STRING "Used by OSS-Fuzz to control, via link options, which fuzzing engine should be used") + +option(SPIRV_BUILD_LIBFUZZER_TARGETS "Build libFuzzer targets" OFF) + # Filament specific changes # option(SPIRV_WERROR "Enable error on warning" ON) set(SPIRV_WERROR OFF) @@ -175,6 +180,7 @@ endif() # Note this target provides no API stability guarantees. # # Ideally, all of these will go away - see https://github.com/KhronosGroup/SPIRV-Tools/issues/3909. +option(ENABLE_EXCEPTIONS_ON_MSVC "Build SPIRV-TOOLS with c++ exceptions enabled in MSVC" ON) option(SPIRV_TOOLS_BUILD_STATIC "Build ${SPIRV_TOOLS}-static target. ${SPIRV_TOOLS} will alias to ${SPIRV_TOOLS}-static or ${SPIRV_TOOLS}-shared based on BUILD_SHARED_LIBS" ON) if(SPIRV_TOOLS_BUILD_STATIC) set(SPIRV_TOOLS_FULL_VISIBILITY ${SPIRV_TOOLS}-static) @@ -194,11 +200,14 @@ function(spvtools_default_compile_options TARGET) target_compile_options(${TARGET} PRIVATE ${SPIRV_WARNINGS}) if (${COMPILER_IS_LIKE_GNU}) - target_compile_options(${TARGET} PRIVATE - -std=c++11 -fno-exceptions -fno-rtti) + target_compile_options(${TARGET} PRIVATE -std=c++11 -fno-exceptions) target_compile_options(${TARGET} PRIVATE -Wall -Wextra -Wno-long-long -Wshadow -Wundef -Wconversion -Wno-sign-conversion) + + if(NOT ENABLE_RTTI) + add_compile_options(-fno-rtti) + endif() # For good call stacks in profiles, keep the frame pointers. if(NOT "${SPIRV_PERF}" STREQUAL "") target_compile_options(${TARGET} PRIVATE -fno-omit-frame-pointer) @@ -223,7 +232,9 @@ function(spvtools_default_compile_options TARGET) if (MSVC) # Specify /EHs for exception handling. This makes using SPIRV-Tools as # dependencies in other projects easier. - target_compile_options(${TARGET} PRIVATE /EHs) + if(ENABLE_EXCEPTIONS_ON_MSVC) + target_compile_options(${TARGET} PRIVATE /EHs) + endif() endif() # For MinGW cross compile, statically link to the C++ runtime. @@ -248,11 +259,13 @@ if(NOT COMMAND find_host_program) endif() # Tests require Python3 +# Filament specific changes if(CMAKE_VERSION VERSION_LESS "3.12" OR ${CMAKE_SYSTEM_NAME} MATCHES "Windows") find_host_package(PythonInterp 3 REQUIRED) else() find_package(Python3 COMPONENTS Interpreter) endif() +# End Filament specific changes # Check for symbol exports on Linux. # At the moment, this check will fail on the OSX build machines for the Android NDK. @@ -296,10 +309,10 @@ endif() # Defaults to OFF if the user didn't set it. # Filament specific changes -option(SPIRV_SKIP_EXECUTABLES - "Skip building the executable and tests along with the library" + option(SPIRV_SKIP_EXECUTABLES + "Skip building the executable and tests along with the library" ${SPIRV_SKIP_EXECUTABLES_OPTION}) -option(SPIRV_SKIP_TESTS + option(SPIRV_SKIP_TESTS "Skip building tests along with the library" ${SPIRV_SKIP_TESTS_OPTION}) # End Filament specific changes if ("${SPIRV_SKIP_EXECUTABLES}") @@ -310,7 +323,7 @@ endif() # Turn off if they take too long. option(SPIRV_CHECK_CONTEXT "In a debug build, check if the IR context is in a valid state." ON) if (${SPIRV_CHECK_CONTEXT}) - add_definitions(-DSPIRV_CHECK_CONTEXT) + add_compile_options($<$:-DSPIRV_CHECK_CONTEXT>) endif() # Precompiled header macro. Parameters are source file list and filename for pch cpp file. diff --git a/third_party/spirv-tools/CONTRIBUTING.md b/third_party/spirv-tools/CONTRIBUTING.md index b46ae31ec4..1eb8b689e8 100644 --- a/third_party/spirv-tools/CONTRIBUTING.md +++ b/third_party/spirv-tools/CONTRIBUTING.md @@ -98,13 +98,6 @@ should pay particular attention to: scenarios? The respective SPIR-V dialects are slightly different. * Changes are made to a container while iterating through it. You have to be careful that iterators are not invalidated or that elements are not skipped. -* C++11 and VS2013. We generally assume that we have a C++11 compliant - compiler. However, on Windows, we still support Visual Studio 2013, which is - not fully C++11 compliant. See - [here](https://msdn.microsoft.com/en-us/library/hh567368.aspx). In - particular, note that it does not provide default move-constructors or - move-assignments for classes. In general, r-value references do not work the - way you might assume they do. * For SPIR-V transforms: The module is changed, but the analyses are not updated. For example, a new instruction is added, but the def-use manager is not updated. Later on, it is possible that the def-use manager will be used, diff --git a/third_party/spirv-tools/DEPS b/third_party/spirv-tools/DEPS index 718927d040..2aaf11f926 100644 --- a/third_party/spirv-tools/DEPS +++ b/third_party/spirv-tools/DEPS @@ -3,10 +3,10 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'effcee_revision': '2ec8f8738118cc483b67c04a759fee53496c5659', - 'googletest_revision': 'b7d472f1225c5a64943821d8483fecb469d3f382', - 're2_revision': 'f8e389f3acdc2517562924239e2a188037393683', - 'spirv_headers_revision': 'ddf3230c14c71e81fc0eae9b781cc4bcc2d1f0f5', + 'effcee_revision': 'ddf5e2bb92957dc8a12c5392f8495333d6844133', + 'googletest_revision': 'bf0701daa9f5b30e5882e2f8f9a5280bcba87e77', + 're2_revision': '4244cd1cb492fa1d10986ec67f862964c073f844', + 'spirv_headers_revision': '814e728b30ddd0f4509233099a3ad96fd4318c07', } deps = { diff --git a/third_party/spirv-tools/FILAMENT_README.md b/third_party/spirv-tools/FILAMENT_README.md new file mode 100644 index 0000000000..23bb8a02bf --- /dev/null +++ b/third_party/spirv-tools/FILAMENT_README.md @@ -0,0 +1,30 @@ +When updating spirv-tools to a new version, make sure to preserve all the changes marked with +the following in `CMakeLists.txt` and `source/CMakeLists.txt`: + +`# Filament specific changes` + +You can easily apply these changes by running the following command at Filament's root: + +``` +git apply third_party/spirv-tools/filament-specific-changes.patch +``` + +The following procedure can be used to update spirv-tools. Note that there is a secondary repository +that needs to be downloaded (spirv-headers). + +``` +curl -L https://github.com/KhronosGroup/spirv-tools/archive/master.zip > master.zip +unzip master.zip +rsync -r SPIRV-Tools-master/ spirv-tools/ --delete +rm -rf SPIRV-Tools-master master.zip +curl -L https://github.com/KhronosGroup/spirv-headers/archive/master.zip > master.zip +unzip master.zip +mv SPIRV-Headers-master/ spirv-tools/external/spirv-headers +rm master.zip + +git add spirv-tools +``` + +Edit the .gitignore so it doesn't prevent `spirv-headers` from being committed. + +Finally, remember to bring back the Filament-specific changes in CMakeLists. diff --git a/third_party/spirv-tools/README.md b/third_party/spirv-tools/README.md index 3637305bae..14db1e7045 100644 --- a/third_party/spirv-tools/README.md +++ b/third_party/spirv-tools/README.md @@ -21,7 +21,6 @@ headers, and XML registry. ## Downloads -[![Build status](https://ci.appveyor.com/api/projects/status/gpue87cesrx3pi0d/branch/master?svg=true)](https://ci.appveyor.com/project/Khronoswebmaster/spirv-tools/branch/master) Linux[![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html) MacOS[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html) Windows[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_release.html) @@ -45,6 +44,20 @@ following versions are ordered from oldest to newest: Use the `--version` option on each command line tool to see the software version. An API call reports the software version as a C-style string. +## Releases + +Some versions of SPIRV-Tools are tagged as stable releases (see +[tags](https://github.com/KhronosGroup/SPIRV-Tools/tags) on github). +These versions undergo extra testing. +Releases are not directly related to releases (or versions) of +[SPIRV-Headers][spirv-headers]. +Releases of SPIRV-Tools are tested against the version of SPIRV-Headers listed +in the [DEPS](DEPS) file. +The release generally uses the most recent compatible version of SPIRV-Headers +available at the time of release. +No version of SPIRV-Headers other than the one listed in the DEPS file is +guaranteed to work with the SPIRV-Tools release. + ## Supported features ### Assembler, binary parser, and disassembler @@ -242,6 +255,34 @@ Contributions via merge request are welcome. Changes should: We intend to maintain a linear history on the GitHub `master` branch. +### Getting the source + +Example of getting sources, assuming SPIRV-Tools is configured as a standalone project: + + git clone https://github.com/KhronosGroup/SPIRV-Tools.git spirv-tools + cd spirv-tools + + # Check out sources for dependencies, at versions known to work together, + # as listed in the DEPS file. + python3 utils/git-sync-deps + +For some kinds of development, you may need the latest sources from the third-party projects: + + git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-tools/external/spirv-headers + git clone https://github.com/google/googletest.git spirv-tools/external/googletest + git clone https://github.com/google/effcee.git spirv-tools/external/effcee + git clone https://github.com/google/re2.git spirv-tools/external/re2 + +#### Dependency on Effcee + +Some tests depend on the [Effcee][effcee] library for stateful matching. +Effcee itself depends on [RE2][re2]. + +* If SPIRV-Tools is configured as part of a larger project that already uses + Effcee, then that project should include Effcee before SPIRV-Tools. +* Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee` + and RE2 sources to appear in `external/re2`. + ### Source code organization * `example`: demo code of using SPIRV-Tools APIs @@ -260,14 +301,6 @@ We intend to maintain a linear history on the GitHub `master` branch. * `test/`: Tests, using the [googletest][googletest] framework * `tools/`: Command line executables -Example of getting sources, assuming SPIRV-Tools is configured as a standalone project: - - git clone https://github.com/KhronosGroup/SPIRV-Tools.git spirv-tools - git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-tools/external/spirv-headers - git clone https://github.com/google/googletest.git spirv-tools/external/googletest - git clone https://github.com/google/effcee.git spirv-tools/external/effcee - git clone https://github.com/google/re2.git spirv-tools/external/re2 - ### Tests The project contains a number of tests, used to drive development @@ -281,46 +314,12 @@ tests: `googletest` source into the `/external/googletest` directory before configuring and building the project. -*Note*: You must use a version of googletest that includes -[a fix][googletest-pull-612] for [googletest issue 610][googletest-issue-610]. -The fix is included on the googletest master branch any time after 2015-11-10. -In particular, googletest must be newer than version 1.7.0. - -### Dependency on Effcee - -Some tests depend on the [Effcee][effcee] library for stateful matching. -Effcee itself depends on [RE2][re2]. - -* If SPIRV-Tools is configured as part of a larger project that already uses - Effcee, then that project should include Effcee before SPIRV-Tools. -* Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee` - and RE2 sources to appear in `external/re2`. - - ## Build -Instead of building manually, you can also download the binaries for your -platform directly from the [master-tot release][master-tot-release] on GitHub. -Those binaries are automatically uploaded by the buildbots after successful -testing and they always reflect the current top of the tree of the master -branch. +*Note*: Prebuilt binaries are available from the [downloads](docs/downloads.md) page. -In order to build the code, you first need to sync the external repositories -that it depends on. Assume that `` is the root directory of the -checked out code: - -```sh -cd -git clone https://github.com/KhronosGroup/SPIRV-Headers.git external/spirv-headers -git clone https://github.com/google/effcee.git external/effcee -git clone https://github.com/google/re2.git external/re2 -git clone https://github.com/google/googletest.git external/googletest # optional - -``` - -*Note*: -The script `utils/git-sync-deps` can be used to checkout and/or update the -contents of the repos under `external/` instead of manually maintaining them. +First [get the sources](#getting-the-source). +Then build using CMake, Bazel, Android ndk-build, or the Emscripten SDK. ### Build using CMake You can build the project using [CMake][cmake]: @@ -348,7 +347,7 @@ option, like so: ```sh # In (the SPIRV-Tools repo root): -git clone --depth=1 --branch v3.13.0 https://github.com/protocolbuffers/protobuf external/protobuf +git clone --depth=1 --branch v3.13.0.1 https://github.com/protocolbuffers/protobuf external/protobuf # In your build directory: cmake [-G ] -DSPIRV_BUILD_FUZZER=ON @@ -365,6 +364,30 @@ You can also use [Bazel](https://bazel.build/) to build the project. cd bazel build :all ``` +### Build a node.js package using Emscripten + +The SPIRV-Tools core library can be built to a WebAssembly [node.js](https://nodejs.org) +module. The resulting `SpirvTools` WebAssembly module only exports methods to +assemble and disassemble SPIR-V modules. + +First, make sure you have the [Emscripten SDK](https://emscripten.org). +Then: + +```sh +cd +./source/wasm/build.sh +``` + +The resulting node package, with JavaScript and TypeScript bindings, is +written to `/out/web`. + +Note: This builds the package locally. It does *not* publish it to [npm](https://npmjs.org). + +To test the result: + +```sh +node ./test/wasm/test.js +``` ### Tools you'll need @@ -378,15 +401,17 @@ suite. - [Bazel](https://bazel.build/) (optional): if building the source with Bazel, you need to install Bazel Version 0.29.1 on your machine. Other versions may also work, but are not verified. +- [Emscripten SDK](https://emscripten.org) (optional): if building the + WebAssembly module. SPIRV-Tools is regularly tested with the following compilers: On Linux -- GCC version 4.8.5 -- Clang version 3.8 +- GCC version 9.3 +- Clang version 10.0 On MacOS -- AppleClang 10.0 +- AppleClang 11.0 On Windows - Visual Studio 2015 @@ -421,7 +446,7 @@ via setting `SPIRV_TOOLS_EXTRA_DEFINITIONS`. For example, by setting it to `/D_ITERATOR_DEBUG_LEVEL=0` on Windows, you can disable checked iterators and iterator debugging. -### Android +### Android ndk-build SPIR-V Tools supports building static libraries `libSPIRV-Tools.a` and `libSPIRV-Tools-opt.a` for Android: @@ -442,11 +467,12 @@ $ANDROID_NDK/ndk-build -C ../android_test \ ``` ### Updating DEPS -Occasionally the entries in DEPS will need to be updated. This is done on demand -when there is a request to do this, often due to downstream breakages. There is -a script `utils/roll_deps.sh` provided, which will generate a patch with the -updated DEPS values. This will still need to be tested in your checkout to -confirm that there are no integration issues that need to be resolved. + +Occasionally the entries in [DEPS](DEPS) will need to be updated. This is done on +demand when there is a request to do this, often due to downstream breakages. +To update `DEPS`, run `utils/roll_deps.sh` and confirm that tests pass. +The script requires Chromium's +[`depot_tools`](https://chromium.googlesource.com/chromium/tools/depot_tools). ## Library @@ -643,8 +669,32 @@ This is experimental. ### Tests -Tests are only built when googletest is found. Use `ctest` to run all the -tests. +Tests are only built when googletest is found. + +#### Running test with CMake + +Use `ctest -j ` to run all the tests. To run tests using all threads: +```shell +ctest -j$(nproc) +``` + +To run a single test target, use `ctest [-j ] -R `. For example, +you can run all `opt` tests with: +```shell +ctest -R 'spirv-tools-test_opt' +``` + +#### Running test with Bazel + +Use `bazel test :all` to run all tests. This will run tests in parallel by default. + +To run a single test target, specify `:my_test_target` instead of `:all`. Test target +names get printed when you run `bazel test :all`. For example, you can run +`opt_def_use_test` with: +```shell +bazel test :opt_def_use_test +``` + ## Future Work @@ -705,4 +755,3 @@ limitations under the License. [CMake]: https://cmake.org/ [cpp-style-guide]: https://google.github.io/styleguide/cppguide.html [clang-sanitizers]: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation -[master-tot-release]: https://github.com/KhronosGroup/SPIRV-Tools/releases/tag/master-tot diff --git a/third_party/spirv-tools/build_defs.bzl b/third_party/spirv-tools/build_defs.bzl index 30af3bd605..b2cd41b9a2 100644 --- a/third_party/spirv-tools/build_defs.bzl +++ b/third_party/spirv-tools/build_defs.bzl @@ -41,6 +41,7 @@ TEST_COPTS = COMMON_COPTS + select({ DEBUGINFO_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_debuginfo_grammar_unified1" CLDEBUGINFO100_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_opencl_debuginfo_100_grammar_unified1" +SHDEBUGINFO100_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_nonsemantic_shader_debuginfo_100_grammar_unified1" def generate_core_tables(version = None): if not version: @@ -201,6 +202,23 @@ def base_test(name, srcs, deps = []): ] + deps, ) +def lint_test(name, srcs, deps = []): + if name[-5:] != "_test": + name = name + "_test" + native.cc_test( + name = "lint_" + name, + srcs = srcs, + compatible_with = [], + copts = TEST_COPTS, + size = "large", + deps = [ + ":spirv_tools_lint", + "@com_google_googletest//:gtest_main", + "@com_google_googletest//:gtest", + "@com_google_effcee//:effcee", + ] + deps, + ) + def link_test(name, srcs, deps = []): if name[-5:] != "_test": name = name + "_test" diff --git a/third_party/spirv-tools/docker-compose.yml b/third_party/spirv-tools/docker-compose.yml new file mode 100644 index 0000000000..fb6d114ffb --- /dev/null +++ b/third_party/spirv-tools/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3" +services: + build: + image: emscripten/emsdk:2.0.2 + environment: + GITHUB_RUN_NUMBER: ${GITHUB_RUN_NUMBER:-} + working_dir: /app + command: ./source/wasm/build.sh + volumes: + - ./:/app diff --git a/third_party/spirv-tools/docs/downloads.md b/third_party/spirv-tools/docs/downloads.md index 9c7d85671d..168937a705 100644 --- a/third_party/spirv-tools/docs/downloads.md +++ b/third_party/spirv-tools/docs/downloads.md @@ -1,14 +1,28 @@ # Downloads -Download the latest builds. -## Release +## Latest builds + +Download the latest builds of the [master](https://github.com/KhronosGroup/SPIRV-Tools/tree/master) branch. + +### Release build | Windows | Linux | MacOS | | --- | --- | --- | | [MSVC 2017](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_release.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html) | | | [gcc](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_gcc_release.html) | | -## Debug +### Debug build | Windows | Linux | MacOS | | --- | --- | --- | | [MSVC 2017](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_debug.html) | | | [gcc](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_gcc_debug.html) | | + + +## Vulkan SDK + +SPIRV-Tools is published as part of the [LunarG Vulkan SDK](https://www.lunarg.com/vulkan-sdk/). +The Vulkan SDK is updated approximately every six weeks. + +## Android NDK + +SPIRV-Tools host executables, and library sources are published as +part of the [Android NDK](https://developer.android.com/ndk/downloads). diff --git a/third_party/spirv-tools/external/spirv-headers/.github/workflows/presubmit.yml b/third_party/spirv-tools/external/spirv-headers/.github/workflows/presubmit.yml new file mode 100644 index 0000000000..d9c25faef5 --- /dev/null +++ b/third_party/spirv-tools/external/spirv-headers/.github/workflows/presubmit.yml @@ -0,0 +1,37 @@ +name: Presubmit +on: [push, pull_request] + +jobs: + build: + name: Build ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - uses: actions/checkout@v2 + - name: Install Ubuntu packages + if: matrix.os == 'ubuntu-latest' + run: sudo apt install -y dos2unix + - name: Install macOS packages + if: matrix.os == 'macos-latest' + run: brew install dos2unix + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_INSTALL_PREFIX=install .. + cmake --build . --target install + - name: Build spec tools + run: | + cd tools/buildHeaders + mkdir build + cd build + cmake .. + cmake --build . --target install + - name: Build headers + run: | + cd tools/buildHeaders + ./bin/makeHeaders + - name: Check generated headers + run: git diff --exit-code diff --git a/third_party/spirv-tools/external/spirv-headers/BUILD.bazel b/third_party/spirv-tools/external/spirv-headers/BUILD.bazel index 9cb46bfc8f..c898ade80a 100644 --- a/third_party/spirv-tools/external/spirv-headers/BUILD.bazel +++ b/third_party/spirv-tools/external/spirv-headers/BUILD.bazel @@ -91,6 +91,11 @@ filegroup( srcs = ["include/spirv/unified1/extinst.opencl.debuginfo.100.grammar.json"], ) +filegroup( + name = "spirv_ext_inst_nonsemantic_shader_debuginfo_100_grammar_unified1", + srcs = ["include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json"], +) + filegroup( name = "spirv_ext_inst_spv_amd_gcn_shader_grammar_unified1", srcs = ["include/spirv/unified1/extinst.spv-amd-gcn-shader.grammar.json"], diff --git a/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt b/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt index ef2e566067..5c746ff60c 100644 --- a/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt +++ b/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt @@ -29,7 +29,7 @@ # https://www.khronos.org/registry/spir-v/ # cmake_minimum_required(VERSION 3.0) -project(SPIRV-Headers VERSION 1.5.1) +project(SPIRV-Headers VERSION 1.5.5) # There are two ways to use this project. # @@ -124,4 +124,10 @@ if (SPIRV_HEADERS_ENABLE_INSTALL) NAMESPACE "${namespace}" DESTINATION "${config_install_dir}" ) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers.pc.in ${CMAKE_BINARY_DIR}/SPIRV-Headers.pc @ONLY) + install( + FILES "${CMAKE_BINARY_DIR}/SPIRV-Headers.pc" + DESTINATION ${CMAKE_INSTALL_DATADIR}/pkgconfig + ) endif() diff --git a/third_party/spirv-tools/external/spirv-headers/SPIRV-Headers.pc.in b/third_party/spirv-tools/external/spirv-headers/SPIRV-Headers.pc.in new file mode 100644 index 0000000000..345f5f8040 --- /dev/null +++ b/third_party/spirv-tools/external/spirv-headers/SPIRV-Headers.pc.in @@ -0,0 +1,9 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: SPIRV-Headers +Description: Header files from the SPIR-V registry +Version: @CMAKE_PROJECT_VERSION@ +Requires: +Libs: +Cflags: -I${includedir} diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml b/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml index 75cba89a74..34453f83a9 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml @@ -69,7 +69,7 @@ - + @@ -81,7 +81,8 @@ - + + @@ -133,13 +134,14 @@ + - + @@ -161,13 +163,14 @@ + - + @@ -251,4 +254,24 @@ + + + + + + + + + diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticClspvReflection.h b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticClspvReflection.h index fa7061d845..380dc21b80 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticClspvReflection.h +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticClspvReflection.h @@ -33,7 +33,7 @@ extern "C" { #endif enum { - NonSemanticClspvReflectionRevision = 1, + NonSemanticClspvReflectionRevision = 2, NonSemanticClspvReflectionRevision_BitWidthPadding = 0x7fffffff }; @@ -62,6 +62,7 @@ enum NonSemanticClspvReflectionInstructions { NonSemanticClspvReflectionConstantDataUniform = 22, NonSemanticClspvReflectionLiteralSampler = 23, NonSemanticClspvReflectionPropertyRequiredWorkgroupSize = 24, + NonSemanticClspvReflectionSpecConstantSubgroupMaxSize = 25, NonSemanticClspvReflectionInstructionsMax = 0x7fffffff }; diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticShaderDebugInfo100.h b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticShaderDebugInfo100.h new file mode 100644 index 0000000000..c52f32f809 --- /dev/null +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticShaderDebugInfo100.h @@ -0,0 +1,171 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and/or associated documentation files (the "Materials"), +// to deal in the Materials without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Materials, and to permit persons to whom the +// Materials are furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Materials. +// +// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// +// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +// IN THE MATERIALS. + +#ifndef SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ +#define SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + NonSemanticShaderDebugInfo100Version = 100, + NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff +}; +enum { + NonSemanticShaderDebugInfo100Revision = 6, + NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100Instructions { + NonSemanticShaderDebugInfo100DebugInfoNone = 0, + NonSemanticShaderDebugInfo100DebugCompilationUnit = 1, + NonSemanticShaderDebugInfo100DebugTypeBasic = 2, + NonSemanticShaderDebugInfo100DebugTypePointer = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifier = 4, + NonSemanticShaderDebugInfo100DebugTypeArray = 5, + NonSemanticShaderDebugInfo100DebugTypeVector = 6, + NonSemanticShaderDebugInfo100DebugTypedef = 7, + NonSemanticShaderDebugInfo100DebugTypeFunction = 8, + NonSemanticShaderDebugInfo100DebugTypeEnum = 9, + NonSemanticShaderDebugInfo100DebugTypeComposite = 10, + NonSemanticShaderDebugInfo100DebugTypeMember = 11, + NonSemanticShaderDebugInfo100DebugTypeInheritance = 12, + NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13, + NonSemanticShaderDebugInfo100DebugTypeTemplate = 14, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15, + NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17, + NonSemanticShaderDebugInfo100DebugGlobalVariable = 18, + NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19, + NonSemanticShaderDebugInfo100DebugFunction = 20, + NonSemanticShaderDebugInfo100DebugLexicalBlock = 21, + NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22, + NonSemanticShaderDebugInfo100DebugScope = 23, + NonSemanticShaderDebugInfo100DebugNoScope = 24, + NonSemanticShaderDebugInfo100DebugInlinedAt = 25, + NonSemanticShaderDebugInfo100DebugLocalVariable = 26, + NonSemanticShaderDebugInfo100DebugInlinedVariable = 27, + NonSemanticShaderDebugInfo100DebugDeclare = 28, + NonSemanticShaderDebugInfo100DebugValue = 29, + NonSemanticShaderDebugInfo100DebugOperation = 30, + NonSemanticShaderDebugInfo100DebugExpression = 31, + NonSemanticShaderDebugInfo100DebugMacroDef = 32, + NonSemanticShaderDebugInfo100DebugMacroUndef = 33, + NonSemanticShaderDebugInfo100DebugImportedEntity = 34, + NonSemanticShaderDebugInfo100DebugSource = 35, + NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101, + NonSemanticShaderDebugInfo100DebugSourceContinued = 102, + NonSemanticShaderDebugInfo100DebugLine = 103, + NonSemanticShaderDebugInfo100DebugNoLine = 104, + NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105, + NonSemanticShaderDebugInfo100DebugStoragePath = 106, + NonSemanticShaderDebugInfo100DebugEntryPoint = 107, + NonSemanticShaderDebugInfo100DebugTypeMatrix = 108, + NonSemanticShaderDebugInfo100InstructionsMax = 0x7fffffff +}; + + +enum NonSemanticShaderDebugInfo100DebugInfoFlags { + NonSemanticShaderDebugInfo100None = 0x0000, + NonSemanticShaderDebugInfo100FlagIsProtected = 0x01, + NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02, + NonSemanticShaderDebugInfo100FlagIsPublic = 0x03, + NonSemanticShaderDebugInfo100FlagIsLocal = 0x04, + NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08, + NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10, + NonSemanticShaderDebugInfo100FlagArtificial = 0x20, + NonSemanticShaderDebugInfo100FlagExplicit = 0x40, + NonSemanticShaderDebugInfo100FlagPrototyped = 0x80, + NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100, + NonSemanticShaderDebugInfo100FlagStaticMember = 0x200, + NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400, + NonSemanticShaderDebugInfo100FlagLValueReference = 0x800, + NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000, + NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000, + NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000, + NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000, + NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000, + NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000, + NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100BuildIdentifierFlags { + NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01, + NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding { + NonSemanticShaderDebugInfo100Unspecified = 0, + NonSemanticShaderDebugInfo100Address = 1, + NonSemanticShaderDebugInfo100Boolean = 2, + NonSemanticShaderDebugInfo100Float = 3, + NonSemanticShaderDebugInfo100Signed = 4, + NonSemanticShaderDebugInfo100SignedChar = 5, + NonSemanticShaderDebugInfo100Unsigned = 6, + NonSemanticShaderDebugInfo100UnsignedChar = 7, + NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugCompositeType { + NonSemanticShaderDebugInfo100Class = 0, + NonSemanticShaderDebugInfo100Structure = 1, + NonSemanticShaderDebugInfo100Union = 2, + NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugTypeQualifier { + NonSemanticShaderDebugInfo100ConstType = 0, + NonSemanticShaderDebugInfo100VolatileType = 1, + NonSemanticShaderDebugInfo100RestrictType = 2, + NonSemanticShaderDebugInfo100AtomicType = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugOperation { + NonSemanticShaderDebugInfo100Deref = 0, + NonSemanticShaderDebugInfo100Plus = 1, + NonSemanticShaderDebugInfo100Minus = 2, + NonSemanticShaderDebugInfo100PlusUconst = 3, + NonSemanticShaderDebugInfo100BitPiece = 4, + NonSemanticShaderDebugInfo100Swap = 5, + NonSemanticShaderDebugInfo100Xderef = 6, + NonSemanticShaderDebugInfo100StackValue = 7, + NonSemanticShaderDebugInfo100Constu = 8, + NonSemanticShaderDebugInfo100Fragment = 9, + NonSemanticShaderDebugInfo100DebugOperationMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugImportedEntity { + NonSemanticShaderDebugInfo100ImportedModule = 0, + NonSemanticShaderDebugInfo100ImportedDeclaration = 1, + NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7fffffff +}; + + +#ifdef __cplusplus +} +#endif + +#endif // SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.clspvreflection.grammar.json b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.clspvreflection.grammar.json index 15e56990a1..3d153e58f0 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.clspvreflection.grammar.json +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.clspvreflection.grammar.json @@ -1,5 +1,5 @@ { - "revision" : 1, + "revision" : 2, "instructions" : [ { "opname" : "Kernel", @@ -232,6 +232,13 @@ { "kind" : "IdRef", "name" : "Y" }, { "kind" : "IdRef", "name" : "Z" } ] + }, + { + "opname" : "SpecConstantSubgroupMaxSize", + "opcode" : 25, + "operands" : [ + { "kind" : "IdRef", "name" : "Size" } + ] } ] } diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json new file mode 100644 index 0000000000..f3621b0b4f --- /dev/null +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json @@ -0,0 +1,713 @@ +{ + "copyright" : [ + "Copyright (c) 2018 The Khronos Group Inc.", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and/or associated documentation files (the \"Materials\"),", + "to deal in the Materials without restriction, including without limitation", + "the rights to use, copy, modify, merge, publish, distribute, sublicense,", + "and/or sell copies of the Materials, and to permit persons to whom the", + "Materials are furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in", + "all copies or substantial portions of the Materials.", + "", + "MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS", + "STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND", + "HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ ", + "", + "THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS", + "OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL", + "THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING", + "FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS", + "IN THE MATERIALS." + ], + "version" : 100, + "revision" : 6, + "instructions" : [ + { + "opname" : "DebugInfoNone", + "opcode" : 0 + }, + { + "opname" : "DebugCompilationUnit", + "opcode" : 1, + "operands" : [ + { "kind" : "IdRef", "name" : "'Version'" }, + { "kind" : "IdRef", "name" : "'DWARF Version'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Language'" } + ] + }, + { + "opname" : "DebugTypeBasic", + "opcode" : 2, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "IdRef", "name" : "'Encoding'" }, + { "kind" : "IdRef", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugTypePointer", + "opcode" : 3, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "IdRef", "name" : "'Storage Class'" }, + { "kind" : "IdRef", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugTypeQualifier", + "opcode" : 4, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "IdRef", "name" : "'Type Qualifier'" } + ] + }, + { + "opname" : "DebugTypeArray", + "opcode" : 5, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "IdRef", "name" : "'Component Counts'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeVector", + "opcode" : 6, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "IdRef", "name" : "'Component Count'" } + ] + }, + { + "opname" : "DebugTypedef", + "opcode" : 7, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugTypeFunction", + "opcode" : 8, + "operands" : [ + { "kind" : "IdRef", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Return Type'" }, + { "kind" : "IdRef", "name" : "'Parameter Types'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeEnum", + "opcode" : 9, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Underlying Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "IdRef", "name" : "'Flags'" }, + { "kind" : "PairIdRefIdRef", "name" : "'Value, Name, Value, Name, ...'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeComposite", + "opcode" : 10, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Tag'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "IdRef", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Members'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeMember", + "opcode" : 11, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Offset'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "IdRef", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Value'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugTypeInheritance", + "opcode" : 12, + "operands" : [ + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Offset'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "IdRef", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugTypePtrToMember", + "opcode" : 13, + "operands" : [ + { "kind" : "IdRef", "name" : "'Member Type'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugTypeTemplate", + "opcode" : 14, + "operands" : [ + { "kind" : "IdRef", "name" : "'Target'" }, + { "kind" : "IdRef", "name" : "'Parameters'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeTemplateParameter", + "opcode" : 15, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Actual Type'" }, + { "kind" : "IdRef", "name" : "'Value'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" } + ] + }, + { + "opname" : "DebugTypeTemplateTemplateParameter", + "opcode" : 16, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Template Name'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" } + ] + }, + { + "opname" : "DebugTypeTemplateParameterPack", + "opcode" : 17, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Template Parameters'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugGlobalVariable", + "opcode" : 18, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "IdRef", "name" : "'Variable'" }, + { "kind" : "IdRef", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Static Member Declaration'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugFunctionDeclaration", + "opcode" : 19, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "IdRef", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugFunction", + "opcode" : 20, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "IdRef", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Scope Line'" }, + { "kind" : "IdRef", "name" : "'Declaration'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugLexicalBlock", + "opcode" : 21, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Name'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugLexicalBlockDiscriminator", + "opcode" : 22, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Discriminator'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugScope", + "opcode" : 23, + "operands" : [ + { "kind" : "IdRef", "name" : "'Scope'" }, + { "kind" : "IdRef", "name" : "'Inlined At'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugNoScope", + "opcode" : 24 + }, + { + "opname" : "DebugInlinedAt", + "opcode" : 25, + "operands" : [ + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Scope'" }, + { "kind" : "IdRef", "name" : "'Inlined'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugLocalVariable", + "opcode" : 26, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Arg Number'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugInlinedVariable", + "opcode" : 27, + "operands" : [ + { "kind" : "IdRef", "name" : "'Variable'" }, + { "kind" : "IdRef", "name" : "'Inlined'" } + ] + }, + { + "opname" : "DebugDeclare", + "opcode" : 28, + "operands" : [ + { "kind" : "IdRef", "name" : "'Local Variable'" }, + { "kind" : "IdRef", "name" : "'Variable'" }, + { "kind" : "IdRef", "name" : "'Expression'" }, + { "kind" : "IdRef", "name" : "'Indexes'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugValue", + "opcode" : 29, + "operands" : [ + { "kind" : "IdRef", "name" : "'Local Variable'" }, + { "kind" : "IdRef", "name" : "'Value'" }, + { "kind" : "IdRef", "name" : "'Expression'" }, + { "kind" : "IdRef", "name" : "'Indexes'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugOperation", + "opcode" : 30, + "operands" : [ + { "kind" : "IdRef", "name" : "'OpCode'" }, + { "kind" : "IdRef", "name" : "'Operands ...'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugExpression", + "opcode" : 31, + "operands" : [ + { "kind" : "IdRef", "name" : "'Operands ...'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugMacroDef", + "opcode" : 32, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Value'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugMacroUndef", + "opcode" : 33, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Macro'" } + ] + }, + { + "opname" : "DebugImportedEntity", + "opcode" : 34, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Tag'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Entity'" }, + { "kind" : "IdRef", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugSource", + "opcode" : 35, + "operands" : [ + { "kind" : "IdRef", "name" : "'File'" }, + { "kind" : "IdRef", "name" : "'Text'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugFunctionDefinition", + "opcode" : 101, + "operands" : [ + { "kind" : "IdRef", "name" : "'Function'" }, + { "kind" : "IdRef", "name" : "'Definition'" } + ] + }, + { + "opname" : "DebugSourceContinued", + "opcode" : 102, + "operands" : [ + { "kind" : "IdRef", "name" : "'Text'" } + ] + }, + { + "opname" : "DebugLine", + "opcode" : 103, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Line Start'" }, + { "kind" : "IdRef", "name" : "'Line End'" }, + { "kind" : "IdRef", "name" : "'Column Start'" }, + { "kind" : "IdRef", "name" : "'Column End'" } + ] + }, + { + "opname" : "DebugNoLine", + "opcode" : 104 + }, + { + "opname" : "DebugBuildIdentifier", + "opcode" : 105, + "operands" : [ + { "kind" : "IdRef", "name" : "'Identifier'" }, + { "kind" : "IdRef", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugStoragePath", + "opcode" : 106, + "operands" : [ + { "kind" : "IdRef", "name" : "'Path'" } + ] + }, + { + "opname" : "DebugEntryPoint", + "opcode" : 107, + "operands" : [ + { "kind" : "IdRef", "name" : "'Entry Point'" }, + { "kind" : "IdRef", "name" : "'Compilation Unit'" }, + { "kind" : "IdRef", "name" : "'Compiler Signature'" }, + { "kind" : "IdRef", "name" : "'Command-line Arguments'" } + ] + }, + { + "opname" : "DebugTypeMatrix", + "opcode" : 108, + "operands" : [ + { "kind" : "IdRef", "name" : "'Vector Type'" }, + { "kind" : "IdRef", "name" : "'Vector Count'" }, + { "kind" : "IdRef", "name" : "'Column Major'" } + ] + } + ], + "operand_kinds" : [ + { + "category" : "BitEnum", + "kind" : "DebugInfoFlags", + "enumerants" : [ + { + "enumerant" : "None", + "value" : "0x0000" + }, + { + "enumerant" : "FlagIsProtected", + "value" : "0x01" + }, + { + "enumerant" : "FlagIsPrivate", + "value" : "0x02" + }, + { + "enumerant" : "FlagIsPublic", + "value" : "0x03" + }, + { + "enumerant" : "FlagIsLocal", + "value" : "0x04" + }, + { + "enumerant" : "FlagIsDefinition", + "value" : "0x08" + }, + { + "enumerant" : "FlagFwdDecl", + "value" : "0x10" + }, + { + "enumerant" : "FlagArtificial", + "value" : "0x20" + }, + { + "enumerant" : "FlagExplicit", + "value" : "0x40" + }, + { + "enumerant" : "FlagPrototyped", + "value" : "0x80" + }, + { + "enumerant" : "FlagObjectPointer", + "value" : "0x100" + }, + { + "enumerant" : "FlagStaticMember", + "value" : "0x200" + }, + { + "enumerant" : "FlagIndirectVariable", + "value" : "0x400" + }, + { + "enumerant" : "FlagLValueReference", + "value" : "0x800" + }, + { + "enumerant" : "FlagRValueReference", + "value" : "0x1000" + }, + { + "enumerant" : "FlagIsOptimized", + "value" : "0x2000" + }, + { + "enumerant" : "FlagIsEnumClass", + "value" : "0x4000" + }, + { + "enumerant" : "FlagTypePassByValue", + "value" : "0x8000" + }, + { + "enumerant" : "FlagTypePassByReference", + "value" : "0x10000" + }, + { + "enumerant" : "FlagUnknownPhysicalLayout", + "value" : "0x20000" + } + ] + }, + { + "category" : "BitEnum", + "kind" : "BuildIdentifierFlags", + "enumerants" : [ + { + "enumerant" : "IdentifierPossibleDuplicates", + "value" : "0x01" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugBaseTypeAttributeEncoding", + "enumerants" : [ + { + "enumerant" : "Unspecified", + "value" : "0" + }, + { + "enumerant" : "Address", + "value" : "1" + }, + { + "enumerant" : "Boolean", + "value" : "2" + }, + { + "enumerant" : "Float", + "value" : "3" + }, + { + "enumerant" : "Signed", + "value" : "4" + }, + { + "enumerant" : "SignedChar", + "value" : "5" + }, + { + "enumerant" : "Unsigned", + "value" : "6" + }, + { + "enumerant" : "UnsignedChar", + "value" : "7" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugCompositeType", + "enumerants" : [ + { + "enumerant" : "Class", + "value" : "0" + }, + { + "enumerant" : "Structure", + "value" : "1" + }, + { + "enumerant" : "Union", + "value" : "2" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugTypeQualifier", + "enumerants" : [ + { + "enumerant" : "ConstType", + "value" : "0" + }, + { + "enumerant" : "VolatileType", + "value" : "1" + }, + { + "enumerant" : "RestrictType", + "value" : "2" + }, + { + "enumerant" : "AtomicType", + "value" : "3" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugOperation", + "enumerants" : [ + { + "enumerant" : "Deref", + "value" : "0" + }, + { + "enumerant" : "Plus", + "value" : "1" + }, + { + "enumerant" : "Minus", + "value" : "2" + }, + { + "enumerant" : "PlusUconst", + "value" : "3", + "parameters" : [ + { "kind" : "IdRef" } + ] + }, + { + "enumerant" : "BitPiece", + "value" : "4", + "parameters" : [ + { "kind" : "IdRef" }, + { "kind" : "IdRef" } + ] + }, + { + "enumerant" : "Swap", + "value" : "5" + }, + { + "enumerant" : "Xderef", + "value" : "6" + }, + { + "enumerant" : "StackValue", + "value" : "7" + }, + { + "enumerant" : "Constu", + "value" : "8", + "parameters" : [ + { "kind" : "IdRef" } + ] + }, + { + "enumerant" : "Fragment", + "value" : "9", + "parameters" : [ + { "kind" : "IdRef" }, + { "kind" : "IdRef" } + ] + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugImportedEntity", + "enumerants" : [ + { + "enumerant" : "ImportedModule", + "value" : "0" + }, + { + "enumerant" : "ImportedDeclaration", + "value" : "1" + } + ] + } + ] +} diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json index 2852c09bc0..05784973d0 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json @@ -4753,6 +4753,52 @@ "extensions" : [ "SPV_NV_ray_tracing" ], "version" : "None" }, + { + "opname" : "OpTraceMotionNV", + "class" : "Reserved", + "opcode" : 5338, + "operands" : [ + + { "kind" : "IdRef", "name" : "'Accel'" }, + { "kind" : "IdRef", "name" : "'Ray Flags'" }, + { "kind" : "IdRef", "name" : "'Cull Mask'" }, + { "kind" : "IdRef", "name" : "'SBT Offset'" }, + { "kind" : "IdRef", "name" : "'SBT Stride'" }, + { "kind" : "IdRef", "name" : "'Miss Index'" }, + { "kind" : "IdRef", "name" : "'Ray Origin'" }, + { "kind" : "IdRef", "name" : "'Ray Tmin'" }, + { "kind" : "IdRef", "name" : "'Ray Direction'" }, + { "kind" : "IdRef", "name" : "'Ray Tmax'" }, + { "kind" : "IdRef", "name" : "'Time'" }, + { "kind" : "IdRef", "name" : "'PayloadId'" } + ], + "capabilities" : [ "RayTracingMotionBlurNV" ], + "extensions" : [ "SPV_NV_ray_tracing_motion_blur" ], + "version" : "None" + }, + { + "opname" : "OpTraceRayMotionNV", + "class" : "Reserved", + "opcode" : 5339, + "operands" : [ + + { "kind" : "IdRef", "name" : "'Accel'" }, + { "kind" : "IdRef", "name" : "'Ray Flags'" }, + { "kind" : "IdRef", "name" : "'Cull Mask'" }, + { "kind" : "IdRef", "name" : "'SBT Offset'" }, + { "kind" : "IdRef", "name" : "'SBT Stride'" }, + { "kind" : "IdRef", "name" : "'Miss Index'" }, + { "kind" : "IdRef", "name" : "'Ray Origin'" }, + { "kind" : "IdRef", "name" : "'Ray Tmin'" }, + { "kind" : "IdRef", "name" : "'Ray Direction'" }, + { "kind" : "IdRef", "name" : "'Ray Tmax'" }, + { "kind" : "IdRef", "name" : "'Time'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "RayTracingMotionBlurNV" ], + "extensions" : [ "SPV_NV_ray_tracing_motion_blur" ], + "version" : "None" + }, { "opname" : "OpTypeAccelerationStructureNV", "class" : "Reserved", @@ -4898,6 +4944,88 @@ "extensions" : [ "SPV_EXT_demote_to_helper_invocation" ], "version" : "None" }, + { + "opname" : "OpConvertUToImageNV", + "class" : "Reserved", + "opcode" : 5391, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "opname" : "OpConvertUToSamplerNV", + "class" : "Reserved", + "opcode" : 5392, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "opname" : "OpConvertImageToUNV", + "class" : "Reserved", + "opcode" : 5393, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "opname" : "OpConvertSamplerToUNV", + "class" : "Reserved", + "opcode" : 5394, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "opname" : "OpConvertUToSampledImageNV", + "class" : "Reserved", + "opcode" : 5395, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "opname" : "OpConvertSampledImageToUNV", + "class" : "Reserved", + "opcode" : 5396, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "opname" : "OpSamplerImageAddressingModeNV", + "class" : "Reserved", + "opcode" : 5397, + "operands" : [ + { "kind" : "LiteralInteger", "name" : "'Bit Width'" } + ], + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, { "opname" : "OpSubgroupShuffleINTEL", "class" : "Group", @@ -5210,7 +5338,7 @@ "version" : "None" }, { - "opname" : "OpConstFunctionPointerINTEL", + "opname" : "OpConstantFunctionPointerINTEL", "class" : "@exclude", "opcode" : 5600, "operands" : [ @@ -7630,24 +7758,6 @@ "capabilities" : [ "ArbitraryPrecisionFloatingPointINTEL" ], "version" : "None" }, - { - "opname" : "OpArbitraryFloatPowNINTEL", - "class" : "@exclude", - "opcode" : 5882, - "operands" : [ - { "kind" : "IdResultType" }, - { "kind" : "IdResult" }, - { "kind" : "IdRef", "name" : "'A'" }, - { "kind" : "LiteralInteger", "name" : "'M1'" }, - { "kind" : "IdRef", "name" : "'B'" }, - { "kind" : "LiteralInteger", "name" : "'Mout'" }, - { "kind" : "LiteralInteger", "name" : "'EnableSubnormals'" }, - { "kind" : "LiteralInteger", "name" : "'RoundingMode'" }, - { "kind" : "LiteralInteger", "name" : "'RoundingAccuracy'" } - ], - "capabilities" : [ "ArbitraryPrecisionFloatingPointINTEL" ], - "version" : "None" - }, { "opname" : "OpLoopControlINTEL", "class" : "Reserved", @@ -8447,6 +8557,13 @@ "enumerant" : "ZeroExtend", "value" : "0x2000", "version" : "1.4" + }, + { + "enumerant" : "Offsets", + "value" : "0x10000", + "parameters" : [ + { "kind" : "IdRef" } + ] } ] }, @@ -8460,40 +8577,35 @@ }, { "enumerant" : "NotNaN", - "value" : "0x0001", - "capabilities" : [ "Kernel" ] + "value" : "0x0001" }, { "enumerant" : "NotInf", - "value" : "0x0002", - "capabilities" : [ "Kernel" ] + "value" : "0x0002" }, { "enumerant" : "NSZ", - "value" : "0x0004", - "capabilities" : [ "Kernel" ] + "value" : "0x0004" }, { "enumerant" : "AllowRecip", - "value" : "0x0008", - "capabilities" : [ "Kernel" ] + "value" : "0x0008" }, { "enumerant" : "Fast", - "value" : "0x0010", - "capabilities" : [ "Kernel" ] + "value" : "0x0010" }, { "enumerant" : "AllowContractFastINTEL", "value" : "0x10000", "capabilities" : [ "FPFastMathModeINTEL" ], - "version" : "None" + "version" : "None" }, { "enumerant" : "AllowReassocINTEL", "value" : "0x20000", "capabilities" : [ "FPFastMathModeINTEL" ], - "version" : "None" + "version" : "None" } ] }, @@ -8689,6 +8801,12 @@ { "enumerant" : "Const", "value" : "0x0008" + }, + { + "enumerant" : "OptNoneINTEL", + "value" : "0x10000", + "capabilities" : [ "OptNoneINTEL" ], + "version" : "None" } ] }, @@ -9445,7 +9563,9 @@ "value" : 39, "capabilities" : [ "Kernel" ], "parameters" : [ - { "kind" : "IdRef", "name" : "'Local Size Hint'" } + { "kind" : "IdRef", "name" : "'x size hint'" }, + { "kind" : "IdRef", "name" : "'y size hint'" }, + { "kind" : "IdRef", "name" : "'z size hint'" } ], "version" : "1.2" }, @@ -10433,35 +10553,51 @@ "enumerants" : [ { "enumerant" : "TRN", - "value" : 0 + "value" : 0, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "TRN_ZERO", - "value" : 1 + "value" : 1, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "RND", - "value" : 2 + "value" : 2, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "RND_ZERO", - "value" : 3 + "value" : 3, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "RND_INF", - "value" : 4 + "value" : 4, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "RND_MIN_INF", - "value" : 5 + "value" : 5, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "RND_CONV", - "value" : 6 + "value" : 6, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "RND_CONV_ODD", - "value" : 7 + "value" : 7, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" } ] }, @@ -10489,19 +10625,27 @@ "enumerants" : [ { "enumerant" : "WRAP", - "value" : 0 + "value" : 0, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "SAT", - "value" : 1 + "value" : 1, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "SAT_ZERO", - "value" : 2 + "value" : 2, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" }, { "enumerant" : "SAT_SYM", - "value" : 3 + "value" : 3, + "capabilities" : [ "ArbitraryPrecisionFixedPointINTEL"], + "version" : "None" } ] }, @@ -11018,6 +11162,30 @@ "extensions" : [ "SPV_EXT_physical_storage_buffer" ], "version" : "1.5" }, + { + "enumerant" : "BindlessSamplerNV", + "value" : 5398, + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "enumerant" : "BindlessImageNV", + "value" : 5399, + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "enumerant" : "BoundSamplerNV", + "value" : 5400, + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, + { + "enumerant" : "BoundImageNV", + "value" : 5401, + "capabilities" : [ "BindlessTextureNV" ], + "version" : "None" + }, { "enumerant" : "SIMTCallINTEL", "value" : 5599, @@ -12022,6 +12190,13 @@ "extensions" : [ "SPV_NV_ray_tracing" , "SPV_KHR_ray_tracing" ], "version" : "None" }, + { + "enumerant" : "CurrentRayTimeNV", + "value" : 5334, + "capabilities" : [ "RayTracingMotionBlurNV" ], + "extensions" : [ "SPV_NV_ray_tracing_motion_blur" ], + "version" : "None" + }, { "enumerant" : "IncomingRayFlagsNV", "value" : 5351, @@ -13054,6 +13229,13 @@ "extensions" : [ "SPV_NV_ray_tracing" ], "version" : "None" }, + { + "enumerant" : "RayTracingMotionBlurNV", + "value" : 5341, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_NV_ray_tracing_motion_blur" ], + "version" : "None" + }, { "enumerant" : "VulkanMemoryModel", "value" : 5345, @@ -13145,6 +13327,12 @@ "extensions" : [ "SPV_EXT_demote_to_helper_invocation" ], "version" : "None" }, + { + "enumerant" : "BindlessTextureNV", + "value" : 5390, + "extensions" : [ "SPV_NV_bindless_texture" ], + "version" : "None" + }, { "enumerant" : "SubgroupShuffleINTEL", "value" : 5568, @@ -13427,6 +13615,12 @@ "extensions" : [ "SPV_INTEL_long_constant_composite" ], "version" : "None" }, + { + "enumerant" : "OptNoneINTEL", + "value" : 6094, + "extensions" : [ "SPV_INTEL_optnone" ], + "version" : "None" + }, { "enumerant" : "AtomicFloat16AddEXT", "value" : 6095, @@ -13509,7 +13703,7 @@ { "enumerant" : "PackedVectorFormat4x8BitKHR", "value" : 0, - "capabilities" : [ "DotProductInput4x8BitPackedKHR" ], + "extensions" : [ "SPV_KHR_integer_dot_product" ], "version" : "None" } ] diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.cs b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.cs index 859f0e7c48..fd007ee5b7 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.cs +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.cs @@ -349,6 +349,7 @@ namespace Spv VolatileTexelKHR = 11, SignExtend = 12, ZeroExtend = 13, + Offsets = 16, } public enum ImageOperandsMask @@ -372,6 +373,7 @@ namespace Spv VolatileTexelKHR = 0x00000800, SignExtend = 0x00001000, ZeroExtend = 0x00002000, + Offsets = 0x00010000, } public enum FPFastMathModeShift @@ -497,6 +499,10 @@ namespace Spv RestrictPointerEXT = 5355, AliasedPointer = 5356, AliasedPointerEXT = 5356, + BindlessSamplerNV = 5398, + BindlessImageNV = 5399, + BoundSamplerNV = 5400, + BoundImageNV = 5401, SIMTCallINTEL = 5599, ReferencedIndirectlyINTEL = 5602, ClobberINTEL = 5607, @@ -651,6 +657,7 @@ namespace Spv HitTNV = 5332, HitKindKHR = 5333, HitKindNV = 5333, + CurrentRayTimeNV = 5334, IncomingRayFlagsKHR = 5351, IncomingRayFlagsNV = 5351, RayGeometryIndexKHR = 5352, @@ -722,6 +729,7 @@ namespace Spv DontInline = 1, Pure = 2, Const = 3, + OptNoneINTEL = 16, } public enum FunctionControlMask @@ -731,6 +739,7 @@ namespace Spv DontInline = 0x00000002, Pure = 0x00000004, Const = 0x00000008, + OptNoneINTEL = 0x00010000, } public enum MemorySemanticsShift @@ -993,6 +1002,7 @@ namespace Spv StorageTexelBufferArrayNonUniformIndexing = 5312, StorageTexelBufferArrayNonUniformIndexingEXT = 5312, RayTracingNV = 5340, + RayTracingMotionBlurNV = 5341, VulkanMemoryModel = 5345, VulkanMemoryModelKHR = 5345, VulkanMemoryModelDeviceScope = 5346, @@ -1007,6 +1017,7 @@ namespace Spv ShaderSMBuiltinsNV = 5373, FragmentShaderPixelInterlockEXT = 5378, DemoteToHelperInvocationEXT = 5379, + BindlessTextureNV = 5390, SubgroupShuffleINTEL = 5568, SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, @@ -1053,6 +1064,7 @@ namespace Spv AtomicFloat32AddEXT = 6033, AtomicFloat64AddEXT = 6034, LongConstantCompositeINTEL = 6089, + OptNoneINTEL = 6094, AtomicFloat16AddEXT = 6095, DebugInfoModuleINTEL = 6114, } @@ -1549,6 +1561,8 @@ namespace Spv OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, OpTypeAccelerationStructureKHR = 5341, OpTypeAccelerationStructureNV = 5341, OpExecuteCallableNV = 5344, @@ -1561,6 +1575,13 @@ namespace Spv OpEndInvocationInterlockEXT = 5365, OpDemoteToHelperInvocationEXT = 5380, OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1585,7 +1606,7 @@ namespace Spv OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, - OpConstFunctionPointerINTEL = 5600, + OpConstantFunctionPointerINTEL = 5600, OpFunctionPointerCallINTEL = 5601, OpAsmTargetINTEL = 5609, OpAsmINTEL = 5610, diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h index 34f90d3183..32e5b73efb 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h @@ -357,6 +357,7 @@ typedef enum SpvImageOperandsShift_ { SpvImageOperandsVolatileTexelKHRShift = 11, SpvImageOperandsSignExtendShift = 12, SpvImageOperandsZeroExtendShift = 13, + SpvImageOperandsOffsetsShift = 16, SpvImageOperandsMax = 0x7fffffff, } SpvImageOperandsShift; @@ -380,6 +381,7 @@ typedef enum SpvImageOperandsMask_ { SpvImageOperandsVolatileTexelKHRMask = 0x00000800, SpvImageOperandsSignExtendMask = 0x00001000, SpvImageOperandsZeroExtendMask = 0x00002000, + SpvImageOperandsOffsetsMask = 0x00010000, } SpvImageOperandsMask; typedef enum SpvFPFastMathModeShift_ { @@ -503,6 +505,10 @@ typedef enum SpvDecoration_ { SpvDecorationRestrictPointerEXT = 5355, SpvDecorationAliasedPointer = 5356, SpvDecorationAliasedPointerEXT = 5356, + SpvDecorationBindlessSamplerNV = 5398, + SpvDecorationBindlessImageNV = 5399, + SpvDecorationBoundSamplerNV = 5400, + SpvDecorationBoundImageNV = 5401, SpvDecorationSIMTCallINTEL = 5599, SpvDecorationReferencedIndirectlyINTEL = 5602, SpvDecorationClobberINTEL = 5607, @@ -657,6 +663,7 @@ typedef enum SpvBuiltIn_ { SpvBuiltInHitTNV = 5332, SpvBuiltInHitKindKHR = 5333, SpvBuiltInHitKindNV = 5333, + SpvBuiltInCurrentRayTimeNV = 5334, SpvBuiltInIncomingRayFlagsKHR = 5351, SpvBuiltInIncomingRayFlagsNV = 5351, SpvBuiltInRayGeometryIndexKHR = 5352, @@ -726,6 +733,7 @@ typedef enum SpvFunctionControlShift_ { SpvFunctionControlDontInlineShift = 1, SpvFunctionControlPureShift = 2, SpvFunctionControlConstShift = 3, + SpvFunctionControlOptNoneINTELShift = 16, SpvFunctionControlMax = 0x7fffffff, } SpvFunctionControlShift; @@ -735,6 +743,7 @@ typedef enum SpvFunctionControlMask_ { SpvFunctionControlDontInlineMask = 0x00000002, SpvFunctionControlPureMask = 0x00000004, SpvFunctionControlConstMask = 0x00000008, + SpvFunctionControlOptNoneINTELMask = 0x00010000, } SpvFunctionControlMask; typedef enum SpvMemorySemanticsShift_ { @@ -993,6 +1002,7 @@ typedef enum SpvCapability_ { SpvCapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, SpvCapabilityRayTracingNV = 5340, + SpvCapabilityRayTracingMotionBlurNV = 5341, SpvCapabilityVulkanMemoryModel = 5345, SpvCapabilityVulkanMemoryModelKHR = 5345, SpvCapabilityVulkanMemoryModelDeviceScope = 5346, @@ -1007,6 +1017,7 @@ typedef enum SpvCapability_ { SpvCapabilityShaderSMBuiltinsNV = 5373, SpvCapabilityFragmentShaderPixelInterlockEXT = 5378, SpvCapabilityDemoteToHelperInvocationEXT = 5379, + SpvCapabilityBindlessTextureNV = 5390, SpvCapabilitySubgroupShuffleINTEL = 5568, SpvCapabilitySubgroupBufferBlockIOINTEL = 5569, SpvCapabilitySubgroupImageBlockIOINTEL = 5570, @@ -1053,6 +1064,7 @@ typedef enum SpvCapability_ { SpvCapabilityAtomicFloat32AddEXT = 6033, SpvCapabilityAtomicFloat64AddEXT = 6034, SpvCapabilityLongConstantCompositeINTEL = 6089, + SpvCapabilityOptNoneINTEL = 6094, SpvCapabilityAtomicFloat16AddEXT = 6095, SpvCapabilityDebugInfoModuleINTEL = 6114, SpvCapabilityMax = 0x7fffffff, @@ -1547,6 +1559,8 @@ typedef enum SpvOp_ { SpvOpIgnoreIntersectionNV = 5335, SpvOpTerminateRayNV = 5336, SpvOpTraceNV = 5337, + SpvOpTraceMotionNV = 5338, + SpvOpTraceRayMotionNV = 5339, SpvOpTypeAccelerationStructureKHR = 5341, SpvOpTypeAccelerationStructureNV = 5341, SpvOpExecuteCallableNV = 5344, @@ -1559,6 +1573,13 @@ typedef enum SpvOp_ { SpvOpEndInvocationInterlockEXT = 5365, SpvOpDemoteToHelperInvocationEXT = 5380, SpvOpIsHelperInvocationEXT = 5381, + SpvOpConvertUToImageNV = 5391, + SpvOpConvertUToSamplerNV = 5392, + SpvOpConvertImageToUNV = 5393, + SpvOpConvertSamplerToUNV = 5394, + SpvOpConvertUToSampledImageNV = 5395, + SpvOpConvertSampledImageToUNV = 5396, + SpvOpSamplerImageAddressingModeNV = 5397, SpvOpSubgroupShuffleINTEL = 5571, SpvOpSubgroupShuffleDownINTEL = 5572, SpvOpSubgroupShuffleUpINTEL = 5573, @@ -1583,7 +1604,7 @@ typedef enum SpvOp_ { SpvOpUSubSatINTEL = 5596, SpvOpIMul32x16INTEL = 5597, SpvOpUMul32x16INTEL = 5598, - SpvOpConstFunctionPointerINTEL = 5600, + SpvOpConstantFunctionPointerINTEL = 5600, SpvOpFunctionPointerCallINTEL = 5601, SpvOpAsmTargetINTEL = 5609, SpvOpAsmINTEL = 5610, @@ -2192,6 +2213,8 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy case SpvOpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; case SpvOpTerminateRayNV: *hasResult = false; *hasResultType = false; break; case SpvOpTraceNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTraceMotionNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; case SpvOpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; case SpvOpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; case SpvOpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; @@ -2203,6 +2226,13 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy case SpvOpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; case SpvOpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; case SpvOpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertUToImageNV: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertUToSamplerNV: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertImageToUNV: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertSamplerToUNV: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertUToSampledImageNV: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertSampledImageToUNV: *hasResult = true; *hasResultType = true; break; + case SpvOpSamplerImageAddressingModeNV: *hasResult = false; *hasResultType = false; break; case SpvOpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; @@ -2227,7 +2257,7 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy case SpvOpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; case SpvOpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpConstFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpAsmTargetINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpAsmINTEL: *hasResult = true; *hasResultType = true; break; diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp index a0b35b3f15..d66576d9b1 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp @@ -353,6 +353,7 @@ enum ImageOperandsShift { ImageOperandsVolatileTexelKHRShift = 11, ImageOperandsSignExtendShift = 12, ImageOperandsZeroExtendShift = 13, + ImageOperandsOffsetsShift = 16, ImageOperandsMax = 0x7fffffff, }; @@ -376,6 +377,7 @@ enum ImageOperandsMask { ImageOperandsVolatileTexelKHRMask = 0x00000800, ImageOperandsSignExtendMask = 0x00001000, ImageOperandsZeroExtendMask = 0x00002000, + ImageOperandsOffsetsMask = 0x00010000, }; enum FPFastMathModeShift { @@ -499,6 +501,10 @@ enum Decoration { DecorationRestrictPointerEXT = 5355, DecorationAliasedPointer = 5356, DecorationAliasedPointerEXT = 5356, + DecorationBindlessSamplerNV = 5398, + DecorationBindlessImageNV = 5399, + DecorationBoundSamplerNV = 5400, + DecorationBoundImageNV = 5401, DecorationSIMTCallINTEL = 5599, DecorationReferencedIndirectlyINTEL = 5602, DecorationClobberINTEL = 5607, @@ -653,6 +659,7 @@ enum BuiltIn { BuiltInHitTNV = 5332, BuiltInHitKindKHR = 5333, BuiltInHitKindNV = 5333, + BuiltInCurrentRayTimeNV = 5334, BuiltInIncomingRayFlagsKHR = 5351, BuiltInIncomingRayFlagsNV = 5351, BuiltInRayGeometryIndexKHR = 5352, @@ -722,6 +729,7 @@ enum FunctionControlShift { FunctionControlDontInlineShift = 1, FunctionControlPureShift = 2, FunctionControlConstShift = 3, + FunctionControlOptNoneINTELShift = 16, FunctionControlMax = 0x7fffffff, }; @@ -731,6 +739,7 @@ enum FunctionControlMask { FunctionControlDontInlineMask = 0x00000002, FunctionControlPureMask = 0x00000004, FunctionControlConstMask = 0x00000008, + FunctionControlOptNoneINTELMask = 0x00010000, }; enum MemorySemanticsShift { @@ -989,6 +998,7 @@ enum Capability { CapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, CapabilityRayTracingNV = 5340, + CapabilityRayTracingMotionBlurNV = 5341, CapabilityVulkanMemoryModel = 5345, CapabilityVulkanMemoryModelKHR = 5345, CapabilityVulkanMemoryModelDeviceScope = 5346, @@ -1003,6 +1013,7 @@ enum Capability { CapabilityShaderSMBuiltinsNV = 5373, CapabilityFragmentShaderPixelInterlockEXT = 5378, CapabilityDemoteToHelperInvocationEXT = 5379, + CapabilityBindlessTextureNV = 5390, CapabilitySubgroupShuffleINTEL = 5568, CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupImageBlockIOINTEL = 5570, @@ -1049,6 +1060,7 @@ enum Capability { CapabilityAtomicFloat32AddEXT = 6033, CapabilityAtomicFloat64AddEXT = 6034, CapabilityLongConstantCompositeINTEL = 6089, + CapabilityOptNoneINTEL = 6094, CapabilityAtomicFloat16AddEXT = 6095, CapabilityDebugInfoModuleINTEL = 6114, CapabilityMax = 0x7fffffff, @@ -1543,6 +1555,8 @@ enum Op { OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, OpTypeAccelerationStructureKHR = 5341, OpTypeAccelerationStructureNV = 5341, OpExecuteCallableNV = 5344, @@ -1555,6 +1569,13 @@ enum Op { OpEndInvocationInterlockEXT = 5365, OpDemoteToHelperInvocationEXT = 5380, OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1579,7 +1600,7 @@ enum Op { OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, - OpConstFunctionPointerINTEL = 5600, + OpConstantFunctionPointerINTEL = 5600, OpFunctionPointerCallINTEL = 5601, OpAsmTargetINTEL = 5609, OpAsmINTEL = 5610, @@ -2188,6 +2209,8 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; case OpTraceNV: *hasResult = false; *hasResultType = false; break; + case OpTraceMotionNV: *hasResult = false; *hasResultType = false; break; + case OpTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; @@ -2199,6 +2222,13 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; case OpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; case OpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case OpConvertUToImageNV: *hasResult = true; *hasResultType = true; break; + case OpConvertUToSamplerNV: *hasResult = true; *hasResultType = true; break; + case OpConvertImageToUNV: *hasResult = true; *hasResultType = true; break; + case OpConvertSamplerToUNV: *hasResult = true; *hasResultType = true; break; + case OpConvertUToSampledImageNV: *hasResult = true; *hasResultType = true; break; + case OpConvertSampledImageToUNV: *hasResult = true; *hasResultType = true; break; + case OpSamplerImageAddressingModeNV: *hasResult = false; *hasResultType = false; break; case OpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; @@ -2223,7 +2253,7 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case OpConstFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; + case OpConstantFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; case OpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; case OpAsmTargetINTEL: *hasResult = true; *hasResultType = true; break; case OpAsmINTEL: *hasResult = true; *hasResultType = true; break; diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 index e17c6c6d26..677daf73bc 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 @@ -353,6 +353,7 @@ enum class ImageOperandsShift : unsigned { VolatileTexelKHR = 11, SignExtend = 12, ZeroExtend = 13, + Offsets = 16, Max = 0x7fffffff, }; @@ -376,6 +377,7 @@ enum class ImageOperandsMask : unsigned { VolatileTexelKHR = 0x00000800, SignExtend = 0x00001000, ZeroExtend = 0x00002000, + Offsets = 0x00010000, }; enum class FPFastMathModeShift : unsigned { @@ -499,6 +501,10 @@ enum class Decoration : unsigned { RestrictPointerEXT = 5355, AliasedPointer = 5356, AliasedPointerEXT = 5356, + BindlessSamplerNV = 5398, + BindlessImageNV = 5399, + BoundSamplerNV = 5400, + BoundImageNV = 5401, SIMTCallINTEL = 5599, ReferencedIndirectlyINTEL = 5602, ClobberINTEL = 5607, @@ -653,6 +659,7 @@ enum class BuiltIn : unsigned { HitTNV = 5332, HitKindKHR = 5333, HitKindNV = 5333, + CurrentRayTimeNV = 5334, IncomingRayFlagsKHR = 5351, IncomingRayFlagsNV = 5351, RayGeometryIndexKHR = 5352, @@ -722,6 +729,7 @@ enum class FunctionControlShift : unsigned { DontInline = 1, Pure = 2, Const = 3, + OptNoneINTEL = 16, Max = 0x7fffffff, }; @@ -731,6 +739,7 @@ enum class FunctionControlMask : unsigned { DontInline = 0x00000002, Pure = 0x00000004, Const = 0x00000008, + OptNoneINTEL = 0x00010000, }; enum class MemorySemanticsShift : unsigned { @@ -989,6 +998,7 @@ enum class Capability : unsigned { StorageTexelBufferArrayNonUniformIndexing = 5312, StorageTexelBufferArrayNonUniformIndexingEXT = 5312, RayTracingNV = 5340, + RayTracingMotionBlurNV = 5341, VulkanMemoryModel = 5345, VulkanMemoryModelKHR = 5345, VulkanMemoryModelDeviceScope = 5346, @@ -1003,6 +1013,7 @@ enum class Capability : unsigned { ShaderSMBuiltinsNV = 5373, FragmentShaderPixelInterlockEXT = 5378, DemoteToHelperInvocationEXT = 5379, + BindlessTextureNV = 5390, SubgroupShuffleINTEL = 5568, SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, @@ -1049,6 +1060,7 @@ enum class Capability : unsigned { AtomicFloat32AddEXT = 6033, AtomicFloat64AddEXT = 6034, LongConstantCompositeINTEL = 6089, + OptNoneINTEL = 6094, AtomicFloat16AddEXT = 6095, DebugInfoModuleINTEL = 6114, Max = 0x7fffffff, @@ -1543,6 +1555,8 @@ enum class Op : unsigned { OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, OpTypeAccelerationStructureKHR = 5341, OpTypeAccelerationStructureNV = 5341, OpExecuteCallableNV = 5344, @@ -1555,6 +1569,13 @@ enum class Op : unsigned { OpEndInvocationInterlockEXT = 5365, OpDemoteToHelperInvocationEXT = 5380, OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1579,7 +1600,7 @@ enum class Op : unsigned { OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, - OpConstFunctionPointerINTEL = 5600, + OpConstantFunctionPointerINTEL = 5600, OpFunctionPointerCallINTEL = 5601, OpAsmTargetINTEL = 5609, OpAsmINTEL = 5610, @@ -2188,6 +2209,8 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case Op::OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; case Op::OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; case Op::OpTraceNV: *hasResult = false; *hasResultType = false; break; + case Op::OpTraceMotionNV: *hasResult = false; *hasResultType = false; break; + case Op::OpTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; case Op::OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; case Op::OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; case Op::OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; @@ -2199,6 +2222,13 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case Op::OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; case Op::OpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; case Op::OpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertUToImageNV: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertUToSamplerNV: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertImageToUNV: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertSamplerToUNV: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertUToSampledImageNV: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertSampledImageToUNV: *hasResult = true; *hasResultType = true; break; + case Op::OpSamplerImageAddressingModeNV: *hasResult = false; *hasResultType = false; break; case Op::OpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; case Op::OpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; case Op::OpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; @@ -2223,7 +2253,7 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case Op::OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; case Op::OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; case Op::OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case Op::OpConstFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpConstantFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; case Op::OpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; case Op::OpAsmTargetINTEL: *hasResult = true; *hasResultType = true; break; case Op::OpAsmINTEL: *hasResult = true; *hasResultType = true; break; diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json index 1c63036f36..e925ab91c7 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json @@ -395,7 +395,8 @@ "VolatileTexel": 11, "VolatileTexelKHR": 11, "SignExtend": 12, - "ZeroExtend": 13 + "ZeroExtend": 13, + "Offsets": 16 } }, { @@ -527,6 +528,10 @@ "RestrictPointerEXT": 5355, "AliasedPointer": 5356, "AliasedPointerEXT": 5356, + "BindlessSamplerNV": 5398, + "BindlessImageNV": 5399, + "BoundSamplerNV": 5400, + "BoundImageNV": 5401, "SIMTCallINTEL": 5599, "ReferencedIndirectlyINTEL": 5602, "ClobberINTEL": 5607, @@ -684,6 +689,7 @@ "HitTNV": 5332, "HitKindKHR": 5333, "HitKindNV": 5333, + "CurrentRayTimeNV": 5334, "IncomingRayFlagsKHR": 5351, "IncomingRayFlagsNV": 5351, "RayGeometryIndexKHR": 5352, @@ -734,7 +740,8 @@ "Inline": 0, "DontInline": 1, "Pure": 2, - "Const": 3 + "Const": 3, + "OptNoneINTEL": 16 } }, { @@ -976,6 +983,7 @@ "StorageTexelBufferArrayNonUniformIndexing": 5312, "StorageTexelBufferArrayNonUniformIndexingEXT": 5312, "RayTracingNV": 5340, + "RayTracingMotionBlurNV": 5341, "VulkanMemoryModel": 5345, "VulkanMemoryModelKHR": 5345, "VulkanMemoryModelDeviceScope": 5346, @@ -990,6 +998,7 @@ "ShaderSMBuiltinsNV": 5373, "FragmentShaderPixelInterlockEXT": 5378, "DemoteToHelperInvocationEXT": 5379, + "BindlessTextureNV": 5390, "SubgroupShuffleINTEL": 5568, "SubgroupBufferBlockIOINTEL": 5569, "SubgroupImageBlockIOINTEL": 5570, @@ -1036,6 +1045,7 @@ "AtomicFloat32AddEXT": 6033, "AtomicFloat64AddEXT": 6034, "LongConstantCompositeINTEL": 6089, + "OptNoneINTEL": 6094, "AtomicFloat16AddEXT": 6095, "DebugInfoModuleINTEL": 6114 } @@ -1541,6 +1551,8 @@ "OpIgnoreIntersectionNV": 5335, "OpTerminateRayNV": 5336, "OpTraceNV": 5337, + "OpTraceMotionNV": 5338, + "OpTraceRayMotionNV": 5339, "OpTypeAccelerationStructureKHR": 5341, "OpTypeAccelerationStructureNV": 5341, "OpExecuteCallableNV": 5344, @@ -1553,6 +1565,13 @@ "OpEndInvocationInterlockEXT": 5365, "OpDemoteToHelperInvocationEXT": 5380, "OpIsHelperInvocationEXT": 5381, + "OpConvertUToImageNV": 5391, + "OpConvertUToSamplerNV": 5392, + "OpConvertImageToUNV": 5393, + "OpConvertSamplerToUNV": 5394, + "OpConvertUToSampledImageNV": 5395, + "OpConvertSampledImageToUNV": 5396, + "OpSamplerImageAddressingModeNV": 5397, "OpSubgroupShuffleINTEL": 5571, "OpSubgroupShuffleDownINTEL": 5572, "OpSubgroupShuffleUpINTEL": 5573, @@ -1577,7 +1596,7 @@ "OpUSubSatINTEL": 5596, "OpIMul32x16INTEL": 5597, "OpUMul32x16INTEL": 5598, - "OpConstFunctionPointerINTEL": 5600, + "OpConstantFunctionPointerINTEL": 5600, "OpFunctionPointerCallINTEL": 5601, "OpAsmTargetINTEL": 5609, "OpAsmINTEL": 5610, diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua index afdaec9e25..0806dd78de 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua @@ -332,6 +332,7 @@ spv = { VolatileTexelKHR = 11, SignExtend = 12, ZeroExtend = 13, + Offsets = 16, }, ImageOperandsMask = { @@ -354,6 +355,7 @@ spv = { VolatileTexelKHR = 0x00000800, SignExtend = 0x00001000, ZeroExtend = 0x00002000, + Offsets = 0x00010000, }, FPFastMathModeShift = { @@ -472,6 +474,10 @@ spv = { RestrictPointerEXT = 5355, AliasedPointer = 5356, AliasedPointerEXT = 5356, + BindlessSamplerNV = 5398, + BindlessImageNV = 5399, + BoundSamplerNV = 5400, + BoundImageNV = 5401, SIMTCallINTEL = 5599, ReferencedIndirectlyINTEL = 5602, ClobberINTEL = 5607, @@ -625,6 +631,7 @@ spv = { HitTNV = 5332, HitKindKHR = 5333, HitKindNV = 5333, + CurrentRayTimeNV = 5334, IncomingRayFlagsKHR = 5351, IncomingRayFlagsNV = 5351, RayGeometryIndexKHR = 5352, @@ -691,6 +698,7 @@ spv = { DontInline = 1, Pure = 2, Const = 3, + OptNoneINTEL = 16, }, FunctionControlMask = { @@ -699,6 +707,7 @@ spv = { DontInline = 0x00000002, Pure = 0x00000004, Const = 0x00000008, + OptNoneINTEL = 0x00010000, }, MemorySemanticsShift = { @@ -951,6 +960,7 @@ spv = { StorageTexelBufferArrayNonUniformIndexing = 5312, StorageTexelBufferArrayNonUniformIndexingEXT = 5312, RayTracingNV = 5340, + RayTracingMotionBlurNV = 5341, VulkanMemoryModel = 5345, VulkanMemoryModelKHR = 5345, VulkanMemoryModelDeviceScope = 5346, @@ -965,6 +975,7 @@ spv = { ShaderSMBuiltinsNV = 5373, FragmentShaderPixelInterlockEXT = 5378, DemoteToHelperInvocationEXT = 5379, + BindlessTextureNV = 5390, SubgroupShuffleINTEL = 5568, SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, @@ -1011,6 +1022,7 @@ spv = { AtomicFloat32AddEXT = 6033, AtomicFloat64AddEXT = 6034, LongConstantCompositeINTEL = 6089, + OptNoneINTEL = 6094, AtomicFloat16AddEXT = 6095, DebugInfoModuleINTEL = 6114, }, @@ -1494,6 +1506,8 @@ spv = { OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, OpTypeAccelerationStructureKHR = 5341, OpTypeAccelerationStructureNV = 5341, OpExecuteCallableNV = 5344, @@ -1506,6 +1520,13 @@ spv = { OpEndInvocationInterlockEXT = 5365, OpDemoteToHelperInvocationEXT = 5380, OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1530,7 +1551,7 @@ spv = { OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, - OpConstFunctionPointerINTEL = 5600, + OpConstantFunctionPointerINTEL = 5600, OpFunctionPointerCallINTEL = 5601, OpAsmTargetINTEL = 5609, OpAsmINTEL = 5610, diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py index 09755a2039..ad41708063 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py @@ -332,6 +332,7 @@ spv = { 'VolatileTexelKHR' : 11, 'SignExtend' : 12, 'ZeroExtend' : 13, + 'Offsets' : 16, }, 'ImageOperandsMask' : { @@ -354,6 +355,7 @@ spv = { 'VolatileTexelKHR' : 0x00000800, 'SignExtend' : 0x00001000, 'ZeroExtend' : 0x00002000, + 'Offsets' : 0x00010000, }, 'FPFastMathModeShift' : { @@ -472,6 +474,10 @@ spv = { 'RestrictPointerEXT' : 5355, 'AliasedPointer' : 5356, 'AliasedPointerEXT' : 5356, + 'BindlessSamplerNV' : 5398, + 'BindlessImageNV' : 5399, + 'BoundSamplerNV' : 5400, + 'BoundImageNV' : 5401, 'SIMTCallINTEL' : 5599, 'ReferencedIndirectlyINTEL' : 5602, 'ClobberINTEL' : 5607, @@ -625,6 +631,7 @@ spv = { 'HitTNV' : 5332, 'HitKindKHR' : 5333, 'HitKindNV' : 5333, + 'CurrentRayTimeNV' : 5334, 'IncomingRayFlagsKHR' : 5351, 'IncomingRayFlagsNV' : 5351, 'RayGeometryIndexKHR' : 5352, @@ -691,6 +698,7 @@ spv = { 'DontInline' : 1, 'Pure' : 2, 'Const' : 3, + 'OptNoneINTEL' : 16, }, 'FunctionControlMask' : { @@ -699,6 +707,7 @@ spv = { 'DontInline' : 0x00000002, 'Pure' : 0x00000004, 'Const' : 0x00000008, + 'OptNoneINTEL' : 0x00010000, }, 'MemorySemanticsShift' : { @@ -951,6 +960,7 @@ spv = { 'StorageTexelBufferArrayNonUniformIndexing' : 5312, 'StorageTexelBufferArrayNonUniformIndexingEXT' : 5312, 'RayTracingNV' : 5340, + 'RayTracingMotionBlurNV' : 5341, 'VulkanMemoryModel' : 5345, 'VulkanMemoryModelKHR' : 5345, 'VulkanMemoryModelDeviceScope' : 5346, @@ -965,6 +975,7 @@ spv = { 'ShaderSMBuiltinsNV' : 5373, 'FragmentShaderPixelInterlockEXT' : 5378, 'DemoteToHelperInvocationEXT' : 5379, + 'BindlessTextureNV' : 5390, 'SubgroupShuffleINTEL' : 5568, 'SubgroupBufferBlockIOINTEL' : 5569, 'SubgroupImageBlockIOINTEL' : 5570, @@ -1011,6 +1022,7 @@ spv = { 'AtomicFloat32AddEXT' : 6033, 'AtomicFloat64AddEXT' : 6034, 'LongConstantCompositeINTEL' : 6089, + 'OptNoneINTEL' : 6094, 'AtomicFloat16AddEXT' : 6095, 'DebugInfoModuleINTEL' : 6114, }, @@ -1494,6 +1506,8 @@ spv = { 'OpIgnoreIntersectionNV' : 5335, 'OpTerminateRayNV' : 5336, 'OpTraceNV' : 5337, + 'OpTraceMotionNV' : 5338, + 'OpTraceRayMotionNV' : 5339, 'OpTypeAccelerationStructureKHR' : 5341, 'OpTypeAccelerationStructureNV' : 5341, 'OpExecuteCallableNV' : 5344, @@ -1506,6 +1520,13 @@ spv = { 'OpEndInvocationInterlockEXT' : 5365, 'OpDemoteToHelperInvocationEXT' : 5380, 'OpIsHelperInvocationEXT' : 5381, + 'OpConvertUToImageNV' : 5391, + 'OpConvertUToSamplerNV' : 5392, + 'OpConvertImageToUNV' : 5393, + 'OpConvertSamplerToUNV' : 5394, + 'OpConvertUToSampledImageNV' : 5395, + 'OpConvertSampledImageToUNV' : 5396, + 'OpSamplerImageAddressingModeNV' : 5397, 'OpSubgroupShuffleINTEL' : 5571, 'OpSubgroupShuffleDownINTEL' : 5572, 'OpSubgroupShuffleUpINTEL' : 5573, @@ -1530,7 +1551,7 @@ spv = { 'OpUSubSatINTEL' : 5596, 'OpIMul32x16INTEL' : 5597, 'OpUMul32x16INTEL' : 5598, - 'OpConstFunctionPointerINTEL' : 5600, + 'OpConstantFunctionPointerINTEL' : 5600, 'OpFunctionPointerCallINTEL' : 5601, 'OpAsmTargetINTEL' : 5609, 'OpAsmINTEL' : 5610, diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spv.d b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spv.d index 179a6b1604..afff6f4b01 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spv.d +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spv.d @@ -352,6 +352,7 @@ enum ImageOperandsShift : uint VolatileTexelKHR = 11, SignExtend = 12, ZeroExtend = 13, + Offsets = 16, } enum ImageOperandsMask : uint @@ -375,6 +376,7 @@ enum ImageOperandsMask : uint VolatileTexelKHR = 0x00000800, SignExtend = 0x00001000, ZeroExtend = 0x00002000, + Offsets = 0x00010000, } enum FPFastMathModeShift : uint @@ -500,6 +502,10 @@ enum Decoration : uint RestrictPointerEXT = 5355, AliasedPointer = 5356, AliasedPointerEXT = 5356, + BindlessSamplerNV = 5398, + BindlessImageNV = 5399, + BoundSamplerNV = 5400, + BoundImageNV = 5401, SIMTCallINTEL = 5599, ReferencedIndirectlyINTEL = 5602, ClobberINTEL = 5607, @@ -654,6 +660,7 @@ enum BuiltIn : uint HitTNV = 5332, HitKindKHR = 5333, HitKindNV = 5333, + CurrentRayTimeNV = 5334, IncomingRayFlagsKHR = 5351, IncomingRayFlagsNV = 5351, RayGeometryIndexKHR = 5352, @@ -725,6 +732,7 @@ enum FunctionControlShift : uint DontInline = 1, Pure = 2, Const = 3, + OptNoneINTEL = 16, } enum FunctionControlMask : uint @@ -734,6 +742,7 @@ enum FunctionControlMask : uint DontInline = 0x00000002, Pure = 0x00000004, Const = 0x00000008, + OptNoneINTEL = 0x00010000, } enum MemorySemanticsShift : uint @@ -996,6 +1005,7 @@ enum Capability : uint StorageTexelBufferArrayNonUniformIndexing = 5312, StorageTexelBufferArrayNonUniformIndexingEXT = 5312, RayTracingNV = 5340, + RayTracingMotionBlurNV = 5341, VulkanMemoryModel = 5345, VulkanMemoryModelKHR = 5345, VulkanMemoryModelDeviceScope = 5346, @@ -1010,6 +1020,7 @@ enum Capability : uint ShaderSMBuiltinsNV = 5373, FragmentShaderPixelInterlockEXT = 5378, DemoteToHelperInvocationEXT = 5379, + BindlessTextureNV = 5390, SubgroupShuffleINTEL = 5568, SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, @@ -1056,6 +1067,7 @@ enum Capability : uint AtomicFloat32AddEXT = 6033, AtomicFloat64AddEXT = 6034, LongConstantCompositeINTEL = 6089, + OptNoneINTEL = 6094, AtomicFloat16AddEXT = 6095, DebugInfoModuleINTEL = 6114, } @@ -1552,6 +1564,8 @@ enum Op : uint OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, OpTypeAccelerationStructureKHR = 5341, OpTypeAccelerationStructureNV = 5341, OpExecuteCallableNV = 5344, @@ -1564,6 +1578,13 @@ enum Op : uint OpEndInvocationInterlockEXT = 5365, OpDemoteToHelperInvocationEXT = 5380, OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1588,7 +1609,7 @@ enum Op : uint OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, - OpConstFunctionPointerINTEL = 5600, + OpConstantFunctionPointerINTEL = 5600, OpFunctionPointerCallINTEL = 5601, OpAsmTargetINTEL = 5609, OpAsmINTEL = 5610, diff --git a/third_party/spirv-tools/filament-specific-changes.patch b/third_party/spirv-tools/filament-specific-changes.patch index 55e95faff2..39578c398a 100644 --- a/third_party/spirv-tools/filament-specific-changes.patch +++ b/third_party/spirv-tools/filament-specific-changes.patch @@ -1,17 +1,17 @@ -From f2c7730fd3246c70c6cb23f1637aa05a3a8b517a Mon Sep 17 00:00:00 2001 +From 468f1935352773b5f9975cae8800ed148b0c8bf3 Mon Sep 17 00:00:00 2001 From: Benjamin Doherty -Date: Tue, 1 Jun 2021 23:31:16 -0700 +Date: Tue, 2 Nov 2021 14:48:14 -0700 Subject: [PATCH] Filament specific changes --- - third_party/spirv-tools/CMakeLists.txt | 86 ++++++++++++------- + third_party/spirv-tools/CMakeLists.txt | 94 ++++++++++++------- .../spirv-tools/external/CMakeLists.txt | 6 +- .../external/spirv-headers/CMakeLists.txt | 8 +- - third_party/spirv-tools/source/CMakeLists.txt | 26 ++++-- - 4 files changed, 81 insertions(+), 45 deletions(-) + third_party/spirv-tools/source/CMakeLists.txt | 26 +++-- + 4 files changed, 86 insertions(+), 48 deletions(-) diff --git a/third_party/spirv-tools/CMakeLists.txt b/third_party/spirv-tools/CMakeLists.txt -index 55f84e6d8..41ae7897c 100755 +index 70caf857a..3991bf660 100755 --- a/third_party/spirv-tools/CMakeLists.txt +++ b/third_party/spirv-tools/CMakeLists.txt @@ -24,8 +24,19 @@ if (POLICY CMP0054) @@ -35,7 +35,7 @@ index 55f84e6d8..41ae7897c 100755 set(SPIRV_TOOLS "SPIRV-Tools") include(GNUInstallDirs) -@@ -68,7 +79,9 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "") +@@ -71,7 +82,9 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "") set(CMAKE_BUILD_TYPE "Debug") endif() @@ -46,9 +46,9 @@ index 55f84e6d8..41ae7897c 100755 if(NOT ${SKIP_SPIRV_TOOLS_INSTALL}) set(ENABLE_SPIRV_TOOLS_INSTALL ON) endif() -@@ -81,7 +94,10 @@ endif(SPIRV_BUILD_COMPRESSION) +@@ -88,7 +101,10 @@ set(SPIRV_LIB_FUZZING_ENGINE_LINK_OPTIONS "" CACHE STRING "Used by OSS-Fuzz to c - option(SPIRV_BUILD_FUZZER "Build spirv-fuzz" OFF) + option(SPIRV_BUILD_LIBFUZZER_TARGETS "Build libFuzzer targets" OFF) -option(SPIRV_WERROR "Enable error on warning" ON) +# Filament specific changes @@ -58,36 +58,41 @@ index 55f84e6d8..41ae7897c 100755 if(("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") AND (NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))) set(COMPILER_IS_LIKE_GNU TRUE) endif() -@@ -230,7 +246,11 @@ if(NOT COMMAND find_host_program) +@@ -243,7 +259,13 @@ if(NOT COMMAND find_host_program) endif() # Tests require Python3 -find_host_package(PythonInterp 3 REQUIRED) ++# Filament specific changes +if(CMAKE_VERSION VERSION_LESS "3.12" OR ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + find_host_package(PythonInterp 3 REQUIRED) +else() + find_package(Python3 COMPONENTS Interpreter) +endif() ++# End Filament specific changes # Check for symbol exports on Linux. # At the moment, this check will fail on the OSX build machines for the Android NDK. -@@ -273,11 +293,13 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) +@@ -286,11 +308,13 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) endif() # Defaults to OFF if the user didn't set it. -+# Filament specific changes - option(SPIRV_SKIP_EXECUTABLES - "Skip building the executable and tests along with the library" +-option(SPIRV_SKIP_EXECUTABLES +- "Skip building the executable and tests along with the library" - ${SPIRV_SKIP_EXECUTABLES}) -+ ${SPIRV_SKIP_EXECUTABLES_OPTION}) - option(SPIRV_SKIP_TESTS +-option(SPIRV_SKIP_TESTS - "Skip building tests along with the library" ${SPIRV_SKIP_TESTS}) ++# Filament specific changes ++ option(SPIRV_SKIP_EXECUTABLES ++ "Skip building the executable and tests along with the library" ++ ${SPIRV_SKIP_EXECUTABLES_OPTION}) ++ option(SPIRV_SKIP_TESTS + "Skip building tests along with the library" ${SPIRV_SKIP_TESTS_OPTION}) +# End Filament specific changes if ("${SPIRV_SKIP_EXECUTABLES}") set(SPIRV_SKIP_TESTS ON) endif() -@@ -321,8 +343,10 @@ endif() +@@ -334,8 +358,10 @@ endif() add_subdirectory(source) add_subdirectory(tools) @@ -100,7 +105,7 @@ index 55f84e6d8..41ae7897c 100755 if(ENABLE_SPIRV_TOOLS_INSTALL) install( -@@ -347,28 +371,30 @@ set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools-shared") +@@ -360,28 +386,30 @@ set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools-shared") # Build pkg-config file # Use a first-class target so it's regenerated when relevant files are updated. @@ -171,7 +176,7 @@ index 179a4012f..152cfc421 100644 endif() else() diff --git a/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt b/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt -index 6f01ef098..ef2e56606 100644 +index c11150008..1a1fe9548 100644 --- a/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt +++ b/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt @@ -49,11 +49,11 @@ add_custom_target(install-headers @@ -191,10 +196,10 @@ index 6f01ef098..ef2e56606 100644 if(NOT ${SPIRV_HEADERS_SKIP_EXAMPLES}) set(SPIRV_HEADERS_ENABLE_EXAMPLES ON) diff --git a/third_party/spirv-tools/source/CMakeLists.txt b/third_party/spirv-tools/source/CMakeLists.txt -index 6633bc916..5f5904567 100644 +index 331ff6755..ef6eb8e77 100644 --- a/third_party/spirv-tools/source/CMakeLists.txt +++ b/third_party/spirv-tools/source/CMakeLists.txt -@@ -364,13 +364,15 @@ endfunction() +@@ -371,13 +371,15 @@ endfunction() # Always build ${SPIRV_TOOLS}-shared. This is expected distro packages, and # unlike the other SPIRV_TOOLS target, defaults to hidden symbol visibility. @@ -217,7 +222,7 @@ index 6633bc916..5f5904567 100644 if(SPIRV_TOOLS_BUILD_STATIC) add_library(${SPIRV_TOOLS}-static STATIC ${SPIRV_SOURCES}) -@@ -386,11 +388,17 @@ if(SPIRV_TOOLS_BUILD_STATIC) +@@ -393,11 +395,17 @@ if(SPIRV_TOOLS_BUILD_STATIC) add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-static) endif() @@ -238,5 +243,5 @@ index 6633bc916..5f5904567 100644 if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") -- -2.32.0.rc0.204.g9fa02ecfa5-goog +2.33.1.1089.g2158813163f-goog diff --git a/third_party/spirv-tools/include/spirv-tools/libspirv.h b/third_party/spirv-tools/include/spirv-tools/libspirv.h index 039dab18ae..8df14f5fb4 100644 --- a/third_party/spirv-tools/include/spirv-tools/libspirv.h +++ b/third_party/spirv-tools/include/spirv-tools/libspirv.h @@ -309,6 +309,7 @@ typedef enum spv_ext_inst_type_t { SPV_EXT_INST_TYPE_DEBUGINFO, SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100, // Multiple distinct extended instruction set types could return this // value, if they are prefixed with NonSemantic. and are otherwise @@ -515,6 +516,7 @@ typedef enum { SPV_ENV_UNIVERSAL_1_5, // SPIR-V 1.5 latest revision, no other restrictions. SPV_ENV_VULKAN_1_2, // Vulkan 1.2 latest revision. + SPV_ENV_MAX // Keep this as the last enum value. } spv_target_env; // SPIR-V Validator can be parameterized with the following Universal Limits. @@ -658,6 +660,11 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetWorkgroupScalarBlockLayout( SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetSkipBlockLayout( spv_validator_options options, bool val); +// Records whether or not the validator should allow the LocalSizeId +// decoration where the environment otherwise would not allow it. +SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetAllowLocalSizeId( + spv_validator_options options, bool val); + // Creates an optimizer options object with default options. Returns a valid // options object. The object remains valid until it is passed into // |spvOptimizerOptionsDestroy|. diff --git a/third_party/spirv-tools/include/spirv-tools/libspirv.hpp b/third_party/spirv-tools/include/spirv-tools/libspirv.hpp index 0c31a18279..8dfb46b774 100644 --- a/third_party/spirv-tools/include/spirv-tools/libspirv.hpp +++ b/third_party/spirv-tools/include/spirv-tools/libspirv.hpp @@ -115,6 +115,12 @@ class ValidatorOptions { spvValidatorOptionsSetSkipBlockLayout(options_, val); } + // Enables LocalSizeId decorations where the environment would not otherwise + // allow them. + void SetAllowLocalSizeId(bool val) { + spvValidatorOptionsSetAllowLocalSizeId(options_, val); + } + // Records whether or not the validator should relax the rules on pointer // usage in logical addressing mode. // diff --git a/third_party/spirv-tools/include/spirv-tools/linter.hpp b/third_party/spirv-tools/include/spirv-tools/linter.hpp new file mode 100644 index 0000000000..52ed5a4672 --- /dev/null +++ b/third_party/spirv-tools/include/spirv-tools/linter.hpp @@ -0,0 +1,48 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 INCLUDE_SPIRV_TOOLS_LINTER_HPP_ +#define INCLUDE_SPIRV_TOOLS_LINTER_HPP_ + +#include "libspirv.hpp" + +namespace spvtools { + +// C++ interface for SPIR-V linting functionalities. It wraps the context +// (including target environment and the corresponding SPIR-V grammar) and +// provides a method for linting. +// +// Instances of this class provides basic thread-safety guarantee. +class Linter { + public: + explicit Linter(spv_target_env env); + + ~Linter(); + + // 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); + + // Returns a reference to the registered message consumer. + const MessageConsumer& Consumer() const; + + bool Run(const uint32_t* binary, size_t binary_size); + + private: + struct Impl; + std::unique_ptr impl_; +}; +} // namespace spvtools + +#endif // INCLUDE_SPIRV_TOOLS_LINTER_HPP_ diff --git a/third_party/spirv-tools/include/spirv-tools/optimizer.hpp b/third_party/spirv-tools/include/spirv-tools/optimizer.hpp index 700f59f70f..21059cbe35 100644 --- a/third_party/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/third_party/spirv-tools/include/spirv-tools/optimizer.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "libspirv.hpp" @@ -27,7 +28,8 @@ namespace spvtools { namespace opt { class Pass; -} +struct DescriptorSetAndBinding; +} // namespace opt // C++ interface for SPIR-V optimization functionalities. It wraps the context // (including target environment and the corresponding SPIR-V grammar) and @@ -512,7 +514,12 @@ Optimizer::PassToken CreateDeadInsertElimPass(); // Conversion, which tends to cause cycles of dead code to be left after // Store/Load elimination passes are completed. These cycles cannot be // eliminated with standard dead code elimination. -Optimizer::PassToken CreateAggressiveDCEPass(); +// +// If |preserve_interface| is true, all non-io variables in the entry point +// interface are considered live and are not eliminated. This mode is needed +// by GPU-Assisted validation instrumentation, where a change in the interface +// is not allowed. +Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface = false); // Creates a remove-unused-interface-variables pass. // Removes variables referenced on the |OpEntryPoint| instruction that are not @@ -699,8 +706,11 @@ Optimizer::PassToken CreateVectorDCEPass(); // Create a pass to reduce the size of loads. // This pass looks for loads of structures where only a few of its members are // used. It replaces the loads feeding an OpExtract with an OpAccessChain and -// a load of the specific elements. -Optimizer::PassToken CreateReduceLoadSizePass(); +// a load of the specific elements. The parameter is a threshold to determine +// whether we have to replace the load or not. If the ratio of the used +// components of the load is less than the threshold, we replace the load. +Optimizer::PassToken CreateReduceLoadSizePass( + double load_replacement_threshold = 0.9); // Create a pass to combine chained access chains. // This pass looks for access chains fed by other access chains and combines @@ -823,6 +833,13 @@ Optimizer::PassToken CreateFixStorageClassPass(); // inclusive. Optimizer::PassToken CreateGraphicsRobustAccessPass(); +// Create a pass to replace a descriptor access using variable index. +// This pass replaces every access using a variable index to array variable +// |desc| that has a DescriptorSet and Binding decorations with a constant +// element of the array. In order to replace the access using a variable index +// with the constant element, it uses a switch statement. +Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass(); + // Create descriptor scalar replacement pass. // This pass replaces every array variable |desc| that has a DescriptorSet and // Binding decorations with a new variable for each element of the array. @@ -854,6 +871,16 @@ Optimizer::PassToken CreateAmdExtToKhrPass(); // propagated into their final positions. Optimizer::PassToken CreateInterpolateFixupPass(); +// Creates a convert-to-sampled-image pass to convert images and/or +// samplers with given pairs of descriptor set and binding to sampled image. +// If a pair of an image and a sampler have the same pair of descriptor set and +// binding that is one of the given pairs, they will be converted to a sampled +// image. In addition, if only an image has the descriptor set and binding that +// is one of the given pairs, it will be converted to a sampled image as well. +Optimizer::PassToken CreateConvertToSampledImagePass( + const std::vector& + descriptor_set_binding_pairs); + } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/third_party/spirv-tools/kokoro/linux-clang-ubsan/build.sh b/third_party/spirv-tools/kokoro/linux-clang-ubsan/build.sh new file mode 100755 index 0000000000..b5941e3400 --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-ubsan/build.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright (c) 2021 Google LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Linux Build Script. + +# Fail on any error. +set -e +# Display commands being run. +set -x + +SCRIPT_DIR=`dirname "$BASH_SOURCE"` +source $SCRIPT_DIR/../scripts/linux/build.sh UBSAN clang cmake diff --git a/third_party/spirv-tools/kokoro/linux-clang-ubsan/continuous.cfg b/third_party/spirv-tools/kokoro/linux-clang-ubsan/continuous.cfg new file mode 100644 index 0000000000..cb5535e14d --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-ubsan/continuous.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2021 Google LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/linux-clang-ubsan/build.sh" diff --git a/third_party/spirv-tools/kokoro/linux-clang-ubsan/presubmit.cfg b/third_party/spirv-tools/kokoro/linux-clang-ubsan/presubmit.cfg new file mode 100644 index 0000000000..029c74a52e --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-ubsan/presubmit.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2021 Google LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/linux-clang-ubsan/build.sh" diff --git a/third_party/spirv-tools/kokoro/scripts/linux/build-docker.sh b/third_party/spirv-tools/kokoro/scripts/linux/build-docker.sh index ba21698745..8f76803c78 100755 --- a/third_party/spirv-tools/kokoro/scripts/linux/build-docker.sh +++ b/third_party/spirv-tools/kokoro/scripts/linux/build-docker.sh @@ -51,14 +51,14 @@ clone_if_missing https://github.com/google/googletest external/googlete pushd external/googletest; git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7; popd clone_if_missing https://github.com/google/effcee external/effcee --depth=1 clone_if_missing https://github.com/google/re2 external/re2 --depth=1 -clone_if_missing https://github.com/protocolbuffers/protobuf external/protobuf --branch v3.13.0 +clone_if_missing https://github.com/protocolbuffers/protobuf external/protobuf --branch v3.13.0.1 if [ $TOOL = "cmake" ]; then using cmake-3.17.2 using ninja-1.10.0 # Possible configurations are: - # ASAN, COVERAGE, RELEASE, DEBUG, DEBUG_EXCEPTION, RELEASE_MINGW + # ASAN, UBSAN, COVERAGE, RELEASE, DEBUG, DEBUG_EXCEPTION, RELEASE_MINGW BUILD_TYPE="Debug" if [ $CONFIG = "RELEASE" ] || [ $CONFIG = "RELEASE_MINGW" ]; then BUILD_TYPE="RelWithDebInfo" @@ -69,6 +69,13 @@ if [ $TOOL = "cmake" ]; then if [ $CONFIG = "ASAN" ]; then ADDITIONAL_CMAKE_FLAGS="-DSPIRV_USE_SANITIZER=address,bounds,null" [ $COMPILER = "clang" ] || { echo "$CONFIG requires clang"; exit 1; } + elif [ $CONFIG = "UBSAN" ]; then + # UBSan requires RTTI, and by default UBSan does not exit when errors are + # encountered - additional compiler options are required to force this. + # The -DSPIRV_USE_SANITIZER=undefined option instructs SPIR-V Tools to be + # built with UBSan enabled. + ADDITIONAL_CMAKE_FLAGS="-DSPIRV_USE_SANITIZER=undefined -DENABLE_RTTI=ON -DCMAKE_C_FLAGS=-fno-sanitize-recover=all -DCMAKE_CXX_FLAGS=-fno-sanitize-recover=all" + [ $COMPILER = "clang" ] || { echo "$CONFIG requires clang"; exit 1; } elif [ $CONFIG = "COVERAGE" ]; then ADDITIONAL_CMAKE_FLAGS="-DENABLE_CODE_COVERAGE=ON" SKIP_TESTS="True" @@ -79,6 +86,10 @@ if [ $TOOL = "cmake" ]; then SKIP_TESTS="True" fi + if [ $COMPILER = "clang" ]; then + ADDITIONAL_CMAKE_FLAGS="$ADDITIONAL_CMAKE_FLAGS -DSPIRV_BUILD_LIBFUZZER_TARGETS=ON" + fi + clean_dir "$ROOT_DIR/build" cd "$ROOT_DIR/build" diff --git a/third_party/spirv-tools/kokoro/scripts/macos/build.sh b/third_party/spirv-tools/kokoro/scripts/macos/build.sh index 44c9a41247..46128238a6 100644 --- a/third_party/spirv-tools/kokoro/scripts/macos/build.sh +++ b/third_party/spirv-tools/kokoro/scripts/macos/build.sh @@ -36,7 +36,7 @@ git clone https://github.com/google/googletest external/googletest cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. git clone --depth=1 https://github.com/google/effcee external/effcee git clone --depth=1 https://github.com/google/re2 external/re2 -git clone --depth=1 --branch v3.13.0 https://github.com/protocolbuffers/protobuf external/protobuf +git clone --depth=1 --branch v3.13.0.1 https://github.com/protocolbuffers/protobuf external/protobuf mkdir build && cd $SRC/build diff --git a/third_party/spirv-tools/kokoro/scripts/windows/build.bat b/third_party/spirv-tools/kokoro/scripts/windows/build.bat index c964320d7d..24e29ccf08 100644 --- a/third_party/spirv-tools/kokoro/scripts/windows/build.bat +++ b/third_party/spirv-tools/kokoro/scripts/windows/build.bat @@ -30,7 +30,7 @@ git clone https://github.com/google/googletest external/googletest cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. git clone --depth=1 https://github.com/google/effcee external/effcee git clone --depth=1 https://github.com/google/re2 external/re2 -git clone --depth=1 --branch v3.13.0 https://github.com/protocolbuffers/protobuf external/protobuf +git clone --depth=1 --branch v3.13.0.1 https://github.com/protocolbuffers/protobuf external/protobuf :: ######################################### :: set up msvc build env @@ -93,4 +93,4 @@ zip -r install.zip install rm -rf %SRC%\build rm -rf %SRC%\external -exit /b 0 \ No newline at end of file +exit /b 0 diff --git a/third_party/spirv-tools/source/CMakeLists.txt b/third_party/spirv-tools/source/CMakeLists.txt index 5f59045671..ef6eb8e770 100644 --- a/third_party/spirv-tools/source/CMakeLists.txt +++ b/third_party/spirv-tools/source/CMakeLists.txt @@ -17,10 +17,10 @@ set(VIMSYNTAX_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_vim_sy set(XML_REGISTRY_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_registry_tables.py") set(LANG_HEADER_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_language_headers.py") -# For now, assume the DebugInfo grammar file is in the current directory. -# It might migrate to SPIRV-Headers. +# Pull in grammar files that have migrated to SPIRV-Headers set(DEBUGINFO_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.debuginfo.grammar.json") set(CLDEBUGINFO100_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.opencl.debuginfo.100.grammar.json") +set(VKDEBUGINFO100_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json") # macro() definitions are used in the following because we need to append .inc # file paths into some global lists (*_CPP_DEPENDS). And those global lists are @@ -113,6 +113,9 @@ endmacro(spvtools_opencl_tables) macro(spvtools_vendor_tables VENDOR_TABLE SHORT_NAME OPERAND_KIND_PREFIX) set(INSTS_FILE "${spirv-tools_BINARY_DIR}/${VENDOR_TABLE}.insts.inc") set(GRAMMAR_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.${VENDOR_TABLE}.grammar.json") + if(NOT EXISTS ${GRAMMAR_FILE}) + set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json") + endif() add_custom_command(OUTPUT ${INSTS_FILE} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} --extinst-vendor-grammar=${GRAMMAR_FILE} @@ -148,9 +151,11 @@ spvtools_vendor_tables("spv-amd-gcn-shader" "spv-amd-gs" "") spvtools_vendor_tables("spv-amd-shader-ballot" "spv-amd-sb" "") spvtools_vendor_tables("debuginfo" "debuginfo" "") spvtools_vendor_tables("opencl.debuginfo.100" "cldi100" "CLDEBUG100_") +spvtools_vendor_tables("nonsemantic.shader.debuginfo.100" "shdi100" "SHDEBUG100_") spvtools_vendor_tables("nonsemantic.clspvreflection" "clspvreflection" "") spvtools_extinst_lang_headers("DebugInfo" ${DEBUGINFO_GRAMMAR_JSON_FILE}) spvtools_extinst_lang_headers("OpenCLDebugInfo100" ${CLDEBUGINFO100_GRAMMAR_JSON_FILE}) +spvtools_extinst_lang_headers("NonSemanticShaderDebugInfo100" ${VKDEBUGINFO100_GRAMMAR_JSON_FILE}) spvtools_vimsyntax("unified1" "1.0") add_custom_target(spirv-tools-vimsyntax DEPENDS ${VIMSYNTAX_FILE}) @@ -211,6 +216,7 @@ add_subdirectory(opt) add_subdirectory(reduce) add_subdirectory(fuzz) add_subdirectory(link) +add_subdirectory(lint) set(SPIRV_SOURCES ${spirv-tools_SOURCE_DIR}/include/spirv-tools/libspirv.h @@ -226,6 +232,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.h ${CMAKE_CURRENT_SOURCE_DIR}/binary.h ${CMAKE_CURRENT_SOURCE_DIR}/cfa.h + ${CMAKE_CURRENT_SOURCE_DIR}/common_debug_info.h ${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.h ${CMAKE_CURRENT_SOURCE_DIR}/disassemble.h ${CMAKE_CURRENT_SOURCE_DIR}/enum_set.h @@ -429,8 +436,10 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) # Special config file for root library compared to other libs. file(WRITE ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake "include(\${CMAKE_CURRENT_LIST_DIR}/${SPIRV_TOOLS}Target.cmake)\n" - "set(${SPIRV_TOOLS}_LIBRARIES ${SPIRV_TOOLS})\n" - "get_target_property(${SPIRV_TOOLS}_INCLUDE_DIRS ${SPIRV_TOOLS} INTERFACE_INCLUDE_DIRECTORIES)\n") + "if(TARGET ${SPIRV_TOOLS})\n" + " set(${SPIRV_TOOLS}_LIBRARIES ${SPIRV_TOOLS})\n" + " get_target_property(${SPIRV_TOOLS}_INCLUDE_DIRS ${SPIRV_TOOLS} INTERFACE_INCLUDE_DIRECTORIES)\n" + "endif()\n") install(FILES ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/third_party/spirv-tools/source/binary.cpp b/third_party/spirv-tools/source/binary.cpp index 090cccfecd..93d5da7aba 100644 --- a/third_party/spirv-tools/source/binary.cpp +++ b/third_party/spirv-tools/source/binary.cpp @@ -507,7 +507,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: { assert(SpvOpSpecConstantOp == opcode); - if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) { + if (word > static_cast(SpvOp::SpvOpMax) || + grammar_.lookupSpecConstantOpcode(SpvOp(word))) { return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": " << word; } diff --git a/third_party/spirv-tools/source/common_debug_info.h b/third_party/spirv-tools/source/common_debug_info.h new file mode 100644 index 0000000000..ffa5d340c0 --- /dev/null +++ b/third_party/spirv-tools/source/common_debug_info.h @@ -0,0 +1,64 @@ +// Copyright (c) 2021 The Khronos Group Inc. +// Copyright (c) 2021 Valve Corporation +// Copyright (c) 2021 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_COMMON_DEBUG_INFO_HEADER_H_ +#define SOURCE_COMMON_DEBUG_INFO_HEADER_H_ + +// This enum defines the known common set of instructions that are the same +// between OpenCL.DebugInfo.100 and NonSemantic.Shader.DebugInfo.100. +// Note that NonSemantic.Shader.* instructions can still have slightly +// different encoding, as it does not use literals anywhere and only constants. +enum CommonDebugInfoInstructions { + CommonDebugInfoDebugInfoNone = 0, + CommonDebugInfoDebugCompilationUnit = 1, + CommonDebugInfoDebugTypeBasic = 2, + CommonDebugInfoDebugTypePointer = 3, + CommonDebugInfoDebugTypeQualifier = 4, + CommonDebugInfoDebugTypeArray = 5, + CommonDebugInfoDebugTypeVector = 6, + CommonDebugInfoDebugTypedef = 7, + CommonDebugInfoDebugTypeFunction = 8, + CommonDebugInfoDebugTypeEnum = 9, + CommonDebugInfoDebugTypeComposite = 10, + CommonDebugInfoDebugTypeMember = 11, + CommonDebugInfoDebugTypeInheritance = 12, + CommonDebugInfoDebugTypePtrToMember = 13, + CommonDebugInfoDebugTypeTemplate = 14, + CommonDebugInfoDebugTypeTemplateParameter = 15, + CommonDebugInfoDebugTypeTemplateTemplateParameter = 16, + CommonDebugInfoDebugTypeTemplateParameterPack = 17, + CommonDebugInfoDebugGlobalVariable = 18, + CommonDebugInfoDebugFunctionDeclaration = 19, + CommonDebugInfoDebugFunction = 20, + CommonDebugInfoDebugLexicalBlock = 21, + CommonDebugInfoDebugLexicalBlockDiscriminator = 22, + CommonDebugInfoDebugScope = 23, + CommonDebugInfoDebugNoScope = 24, + CommonDebugInfoDebugInlinedAt = 25, + CommonDebugInfoDebugLocalVariable = 26, + CommonDebugInfoDebugInlinedVariable = 27, + CommonDebugInfoDebugDeclare = 28, + CommonDebugInfoDebugValue = 29, + CommonDebugInfoDebugOperation = 30, + CommonDebugInfoDebugExpression = 31, + CommonDebugInfoDebugMacroDef = 32, + CommonDebugInfoDebugMacroUndef = 33, + CommonDebugInfoDebugImportedEntity = 34, + CommonDebugInfoDebugSource = 35, + CommonDebugInfoInstructionsMax = 0x7ffffff +}; + +#endif // SOURCE_COMMON_DEBUG_INFO_HEADER_H_ diff --git a/third_party/spirv-tools/source/ext_inst.cpp b/third_party/spirv-tools/source/ext_inst.cpp index 795cb0f3f7..812053ec0a 100644 --- a/third_party/spirv-tools/source/ext_inst.cpp +++ b/third_party/spirv-tools/source/ext_inst.cpp @@ -29,6 +29,7 @@ #include "debuginfo.insts.inc" #include "glsl.std.450.insts.inc" #include "nonsemantic.clspvreflection.insts.inc" +#include "nonsemantic.shader.debuginfo.100.insts.inc" #include "opencl.debuginfo.100.insts.inc" #include "opencl.std.insts.inc" @@ -55,6 +56,9 @@ static const spv_ext_inst_group_t kGroups_1_0[] = { debuginfo_entries}, {SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, ARRAY_SIZE(opencl_debuginfo_100_entries), opencl_debuginfo_100_entries}, + {SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100, + ARRAY_SIZE(nonsemantic_shader_debuginfo_100_entries), + nonsemantic_shader_debuginfo_100_entries}, {SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, ARRAY_SIZE(nonsemantic_clspvreflection_entries), nonsemantic_clspvreflection_entries}, @@ -126,6 +130,9 @@ spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name) { if (!strcmp("OpenCL.DebugInfo.100", name)) { return SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100; } + if (!strcmp("NonSemantic.Shader.DebugInfo.100", name)) { + return SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100; + } if (!strncmp("NonSemantic.ClspvReflection.", name, 28)) { return SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION; } @@ -139,6 +146,7 @@ spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name) { bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type) { if (type == SPV_EXT_INST_TYPE_NONSEMANTIC_UNKNOWN || + type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100 || type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) { return true; } @@ -147,6 +155,7 @@ bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type) { bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type) { if (type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || + type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100 || type == SPV_EXT_INST_TYPE_DEBUGINFO) { return true; } diff --git a/third_party/spirv-tools/source/fuzz/CMakeLists.txt b/third_party/spirv-tools/source/fuzz/CMakeLists.txt index a80616623a..dd674dd04c 100644 --- a/third_party/spirv-tools/source/fuzz/CMakeLists.txt +++ b/third_party/spirv-tools/source/fuzz/CMakeLists.txt @@ -124,6 +124,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_pass_swap_functions.h fuzzer_pass_toggle_access_chain_instruction.h fuzzer_pass_wrap_regions_in_selections.h + fuzzer_pass_wrap_vector_synonym.h fuzzer_util.h id_use_descriptor.h instruction_descriptor.h @@ -230,6 +231,7 @@ if(SPIRV_BUILD_FUZZER) transformation_vector_shuffle.h transformation_wrap_early_terminator_in_function.h transformation_wrap_region_in_selection.h + transformation_wrap_vector_synonym.h uniform_buffer_element_descriptor.h ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h @@ -319,6 +321,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_pass_swap_functions.cpp fuzzer_pass_toggle_access_chain_instruction.cpp fuzzer_pass_wrap_regions_in_selections.cpp + fuzzer_pass_wrap_vector_synonym.cpp fuzzer_util.cpp id_use_descriptor.cpp instruction_descriptor.cpp @@ -423,6 +426,7 @@ if(SPIRV_BUILD_FUZZER) transformation_vector_shuffle.cpp transformation_wrap_early_terminator_in_function.cpp transformation_wrap_region_in_selection.cpp + transformation_wrap_vector_synonym.cpp uniform_buffer_element_descriptor.cpp ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc ) diff --git a/third_party/spirv-tools/source/fuzz/fuzzer.cpp b/third_party/spirv-tools/source/fuzz/fuzzer.cpp index fe88a55b02..9838e64fc8 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer.cpp @@ -90,6 +90,7 @@ #include "source/fuzz/fuzzer_pass_swap_functions.h" #include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h" #include "source/fuzz/fuzzer_pass_wrap_regions_in_selections.h" +#include "source/fuzz/fuzzer_pass_wrap_vector_synonym.h" #include "source/fuzz/pass_management/repeated_pass_manager.h" #include "source/fuzz/pass_management/repeated_pass_recommender_standard.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" @@ -109,7 +110,8 @@ Fuzzer::Fuzzer(std::unique_ptr ir_context, bool enable_all_passes, RepeatedPassStrategy repeated_pass_strategy, bool validate_after_each_fuzzer_pass, - spv_validator_options validator_options) + spv_validator_options validator_options, + bool ignore_inapplicable_transformations /* = true */) : consumer_(std::move(consumer)), enable_all_passes_(enable_all_passes), validate_after_each_fuzzer_pass_(validate_after_each_fuzzer_pass), @@ -123,7 +125,9 @@ Fuzzer::Fuzzer(std::unique_ptr ir_context, pass_instances_(), repeated_pass_recommender_(nullptr), repeated_pass_manager_(nullptr), - final_passes_() { + final_passes_(), + ignore_inapplicable_transformations_( + ignore_inapplicable_transformations) { assert(ir_context_ && "IRContext is not initialized"); assert(fuzzer_context_ && "FuzzerContext is not initialized"); assert(transformation_context_ && "TransformationContext is not initialized"); @@ -214,6 +218,7 @@ Fuzzer::Fuzzer(std::unique_ptr ir_context, MaybeAddRepeatedPass( &pass_instances_); MaybeAddRepeatedPass(&pass_instances_); + MaybeAddRepeatedPass(&pass_instances_); // There is a theoretical possibility that no pass instances were created // until now; loop again if so. } while (pass_instances_.GetPasses().empty()); @@ -255,7 +260,8 @@ void Fuzzer::MaybeAddRepeatedPass(uint32_t percentage_chance_of_adding_pass, fuzzer_context_->ChoosePercentage(percentage_chance_of_adding_pass)) { pass_instances->SetPass(MakeUnique( ir_context_.get(), transformation_context_.get(), fuzzer_context_.get(), - &transformation_sequence_out_, std::forward(extra_args)...)); + &transformation_sequence_out_, ignore_inapplicable_transformations_, + std::forward(extra_args)...)); } } @@ -265,7 +271,8 @@ void Fuzzer::MaybeAddFinalPass(std::vector>* passes, if (enable_all_passes_ || fuzzer_context_->ChooseEven()) { passes->push_back(MakeUnique( ir_context_.get(), transformation_context_.get(), fuzzer_context_.get(), - &transformation_sequence_out_, std::forward(extra_args)...)); + &transformation_sequence_out_, ignore_inapplicable_transformations_, + std::forward(extra_args)...)); } } diff --git a/third_party/spirv-tools/source/fuzz/fuzzer.h b/third_party/spirv-tools/source/fuzz/fuzzer.h index 1e7d6860c2..4c38977fb9 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer.h @@ -62,7 +62,8 @@ class Fuzzer { const std::vector& donor_suppliers, bool enable_all_passes, RepeatedPassStrategy repeated_pass_strategy, bool validate_after_each_fuzzer_pass, - spv_validator_options validator_options); + spv_validator_options validator_options, + bool ignore_inapplicable_transformations = true); // Disables copy/move constructor/assignment operations. Fuzzer(const Fuzzer&) = delete; @@ -187,6 +188,12 @@ class Fuzzer { // Some passes that it does not make sense to apply repeatedly, as they do not // unlock other passes. std::vector> final_passes_; + + // When set, this flag causes inapplicable transformations that should be + // applicable by construction to be ignored. This is useful when the fuzzer + // is being deployed at scale to test a SPIR-V processing tool, and where it + // is desirable to ignore bugs in the fuzzer itself. + const bool ignore_inapplicable_transformations_; }; } // namespace fuzz diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_context.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_context.cpp index 9e9650f646..c2175425b2 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_context.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_context.cpp @@ -42,6 +42,8 @@ const std::pair kChanceOfAddingAnotherPassToPassLoop = {50, const std::pair kChanceOfAddingAnotherStructField = {20, 90}; const std::pair kChanceOfAddingArrayOrStructType = {20, 90}; +const std::pair KChanceOfAddingAtomicLoad = {30, 90}; +const std::pair KChanceOfAddingAtomicStore = {20, 90}; const std::pair kChanceOfAddingBitInstructionSynonym = {5, 20}; const std::pair @@ -162,6 +164,7 @@ const std::pair kChanceOfTogglingAccessChainInstruction = { 20, 90}; const std::pair kChanceOfWrappingRegionInSelection = {70, 90}; +const std::pair kChanceOfWrappingVectorSynonym = {10, 90}; // Default limits for various quantities that are chosen during fuzzing. // Keep them in alphabetical order. @@ -215,6 +218,10 @@ FuzzerContext::FuzzerContext(std::unique_ptr random_generator, ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField); chance_of_adding_array_or_struct_type_ = ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType); + chance_of_adding_atomic_load_ = + ChooseBetweenMinAndMax(KChanceOfAddingAtomicLoad); + chance_of_adding_atomic_store_ = + ChooseBetweenMinAndMax(KChanceOfAddingAtomicStore); chance_of_adding_bit_instruction_synonym_ = ChooseBetweenMinAndMax(kChanceOfAddingBitInstructionSynonym); chance_of_adding_both_branches_when_replacing_opselect_ = @@ -369,6 +376,8 @@ FuzzerContext::FuzzerContext(std::unique_ptr random_generator, ChooseBetweenMinAndMax(kChanceOfTogglingAccessChainInstruction); chance_of_wrapping_region_in_selection_ = ChooseBetweenMinAndMax(kChanceOfWrappingRegionInSelection); + chance_of_wrapping_vector_synonym_ = + ChooseBetweenMinAndMax(kChanceOfWrappingVectorSynonym); } FuzzerContext::~FuzzerContext() = default; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_context.h b/third_party/spirv-tools/source/fuzz/fuzzer_context.h index ef2cc2c548..77a5d40045 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_context.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_context.h @@ -142,6 +142,12 @@ class FuzzerContext { uint32_t GetChanceOfAddingArrayOrStructType() const { return chance_of_adding_array_or_struct_type_; } + uint32_t GetChanceOfAddingAtomicLoad() const { + return chance_of_adding_atomic_load_; + } + uint32_t GetChanceOfAddingAtomicStore() const { + return chance_of_adding_atomic_store_; + } uint32_t GetChanceOfAddingBitInstructionSynonym() const { return chance_of_adding_bit_instruction_synonym_; } @@ -381,6 +387,10 @@ class FuzzerContext { return chance_of_wrapping_region_in_selection_; } + uint32_t GetChanceOfWrappingVectorSynonym() const { + return chance_of_wrapping_vector_synonym_; + } + // Other functions to control transformations. Keep them in alphabetical // order. uint32_t GetMaximumEquivalenceClassSizeForDataSynonymFactClosure() const { @@ -425,6 +435,9 @@ class FuzzerContext { uint32_t GetRandomIndexForCompositeInsert(uint32_t number_of_components) { return random_generator_->RandomUint32(number_of_components); } + uint32_t GetRandomIndexForWrappingVector(uint32_t vector_width) { + return random_generator_->RandomUint32(vector_width); + } int64_t GetRandomValueForStepConstantInLoop() { return random_generator_->RandomUint64(UINT64_MAX); } @@ -462,6 +475,9 @@ class FuzzerContext { // Ensure that the number of unused components is non-zero. return random_generator_->RandomUint32(max_unused_component_count) + 1; } + uint32_t GetWidthOfWrappingVector() { + return 2 + random_generator_->RandomUint32(3); + } bool GoDeeperInConstantObfuscation(uint32_t depth) { return go_deeper_in_constant_obfuscation_(depth, random_generator_.get()); } @@ -482,6 +498,8 @@ class FuzzerContext { uint32_t chance_of_adding_another_pass_to_pass_loop_; uint32_t chance_of_adding_another_struct_field_; uint32_t chance_of_adding_array_or_struct_type_; + uint32_t chance_of_adding_atomic_load_; + uint32_t chance_of_adding_atomic_store_; uint32_t chance_of_adding_bit_instruction_synonym_; uint32_t chance_of_adding_both_branches_when_replacing_opselect_; uint32_t chance_of_adding_composite_extract_; @@ -562,6 +580,7 @@ class FuzzerContext { uint32_t chance_of_swapping_functions_; uint32_t chance_of_toggling_access_chain_instruction_; uint32_t chance_of_wrapping_region_in_selection_; + uint32_t chance_of_wrapping_vector_synonym_; // Limits associated with various quantities for which random values are // chosen during fuzzing. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp index 9e95190c1d..d91482cc7e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp @@ -43,11 +43,14 @@ namespace fuzz { FuzzerPass::FuzzerPass(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : ir_context_(ir_context), transformation_context_(transformation_context), fuzzer_context_(fuzzer_context), - transformations_(transformations) {} + transformations_(transformations), + ignore_inapplicable_transformations_( + ignore_inapplicable_transformations) {} FuzzerPass::~FuzzerPass() = default; @@ -183,9 +186,23 @@ void FuzzerPass::ForEachInstructionWithInstructionDescriptor( } void FuzzerPass::ApplyTransformation(const Transformation& transformation) { - assert(transformation.IsApplicable(GetIRContext(), - *GetTransformationContext()) && - "Transformation should be applicable by construction."); + if (ignore_inapplicable_transformations_) { + // If an applicable-by-construction transformation turns out to be + // inapplicable, this is a bug in the fuzzer. However, when deploying the + // fuzzer at scale for finding bugs in SPIR-V processing tools it is + // desirable to silently ignore such bugs. This code path caters for that + // scenario. + if (!transformation.IsApplicable(GetIRContext(), + *GetTransformationContext())) { + return; + } + } else { + // This code path caters for debugging bugs in the fuzzer, where an + // applicable-by-construction transformation turns out to be inapplicable. + assert(transformation.IsApplicable(GetIRContext(), + *GetTransformationContext()) && + "Transformation should be applicable by construction."); + } transformation.Apply(GetIRContext(), GetTransformationContext()); auto transformation_message = transformation.ToMessage(); assert(transformation_message.transformation_case() != diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass.h index ec254855a2..2655b5406c 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass.h @@ -33,7 +33,8 @@ class FuzzerPass { FuzzerPass(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); virtual ~FuzzerPass(); @@ -321,6 +322,10 @@ class FuzzerPass { TransformationContext* transformation_context_; FuzzerContext* fuzzer_context_; protobufs::TransformationSequence* transformations_; + // If set, then transformations that should be applicable by construction are + // still tested for applicability, and ignored if they turn out to be + // inapplicable. Otherwise, applicability by construction is asserted. + const bool ignore_inapplicable_transformations_; }; } // namespace fuzz diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.cpp index c498642c06..39f193d940 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassAddAccessChains::FuzzerPassAddAccessChains( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddAccessChains::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.h index e80c2c6c71..5e209cd29f 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.h @@ -28,7 +28,8 @@ class FuzzerPassAddAccessChains : public FuzzerPass { FuzzerPassAddAccessChains(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp index 78abf5be07..1b0d7b107f 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassAddBitInstructionSynonyms::FuzzerPassAddBitInstructionSynonyms( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddBitInstructionSynonyms::Apply() { for (auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h index 28f95779cc..38d81aa7d4 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h @@ -28,7 +28,8 @@ class FuzzerPassAddBitInstructionSynonyms : public FuzzerPass { FuzzerPassAddBitInstructionSynonyms( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.cpp index 19f9902435..dbbec0ca0c 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.cpp @@ -26,9 +26,10 @@ namespace fuzz { FuzzerPassAddCompositeExtract::FuzzerPassAddCompositeExtract( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddCompositeExtract::Apply() { std::vector composite_synonyms; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.h index 32ac190a53..e7ed18af31 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_extract.h @@ -27,7 +27,8 @@ class FuzzerPassAddCompositeExtract : public FuzzerPass { FuzzerPassAddCompositeExtract( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.cpp index cf314d30bc..2ac12de42d 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassAddCompositeInserts::FuzzerPassAddCompositeInserts( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddCompositeInserts::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.h index 4d511f6c75..d9f42d588a 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.h @@ -27,7 +27,8 @@ class FuzzerPassAddCompositeInserts : public FuzzerPass { FuzzerPassAddCompositeInserts( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp index 3dfbd690f7..af36ad06eb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassAddCompositeTypes::FuzzerPassAddCompositeTypes( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddCompositeTypes::Apply() { MaybeAddMissingVectorTypes(); diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h index 89d48f8ab0..f16c79e353 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h @@ -27,7 +27,8 @@ class FuzzerPassAddCompositeTypes : public FuzzerPass { FuzzerPassAddCompositeTypes( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp index b654927f6e..6551f49f38 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassAddCopyMemory::FuzzerPassAddCopyMemory( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddCopyMemory::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h index 0f7db0c7e5..e258752ccc 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h @@ -27,7 +27,8 @@ class FuzzerPassAddCopyMemory : public FuzzerPass { FuzzerPassAddCopyMemory(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp index 8c166a2033..82d53ebba9 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp @@ -31,9 +31,10 @@ const size_t kMaxTransformationsInOnePass = 100U; FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddDeadBlocks::Apply() { // We iterate over all blocks in the module collecting up those at which we diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h index a87c05c385..4567e87d0c 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h @@ -27,7 +27,8 @@ class FuzzerPassAddDeadBlocks : public FuzzerPass { FuzzerPassAddDeadBlocks(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp index 0c18da9099..c3664c87cd 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddDeadBreaks::Apply() { // We first collect up lots of possibly-applicable transformations. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h index d1086fc4fb..361c3464e7 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h @@ -26,7 +26,8 @@ class FuzzerPassAddDeadBreaks : public FuzzerPass { FuzzerPassAddDeadBreaks(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp index 1ab40b7371..3881481137 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassAddDeadContinues::FuzzerPassAddDeadContinues( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddDeadContinues::Apply() { // Consider every block in every function. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h index bf0009e444..4f1bd60144 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h @@ -23,10 +23,11 @@ namespace fuzz { // A fuzzer pass for adding dead continue edges to the module. class FuzzerPassAddDeadContinues : public FuzzerPass { public: - FuzzerPassAddDeadContinues( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + FuzzerPassAddDeadContinues(opt::IRContext* ir_context, + TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.cpp index 15554b7a63..4bbded8e18 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.cpp @@ -45,9 +45,10 @@ bool IsBitWidthSupported(opt::IRContext* ir_context, uint32_t bit_width) { FuzzerPassAddEquationInstructions::FuzzerPassAddEquationInstructions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddEquationInstructions::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.h index dbec5bacd1..dc9a27b3a6 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.h @@ -29,7 +29,8 @@ class FuzzerPassAddEquationInstructions : public FuzzerPass { FuzzerPassAddEquationInstructions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.cpp index 2240696b94..033f4a276e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.cpp @@ -26,9 +26,10 @@ namespace fuzz { FuzzerPassAddFunctionCalls::FuzzerPassAddFunctionCalls( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddFunctionCalls::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.h index 081510c1ad..80b03d7b94 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.h @@ -24,10 +24,11 @@ namespace fuzz { // anywhere, and (b) any functions, from dead blocks. class FuzzerPassAddFunctionCalls : public FuzzerPass { public: - FuzzerPassAddFunctionCalls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + FuzzerPassAddFunctionCalls(opt::IRContext* ir_context, + TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp index 067974134e..061f44d069 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddGlobalVariables::Apply() { SpvStorageClass variable_storage_class = SpvStorageClassPrivate; @@ -47,6 +48,10 @@ void FuzzerPassAddGlobalVariables::Apply() { // These are the basic types that are available to this fuzzer pass. auto& basic_types = basic_type_ids_and_pointers.first; + if (basic_types.empty()) { + // There are no basic types, so there is nothing this fuzzer pass can do. + return; + } // These are the pointers to those basic types that are *initially* available // to the fuzzer pass. The fuzzer pass might add pointer types in cases where diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.h index 3745c5c387..1496646ee5 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.h @@ -27,7 +27,8 @@ class FuzzerPassAddGlobalVariables : public FuzzerPass { FuzzerPassAddGlobalVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp index c10db720e5..19661d103b 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp @@ -27,9 +27,10 @@ FuzzerPassAddImageSampleUnusedComponents:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddImageSampleUnusedComponents::Apply() { // SPIR-V module to help understand the transformation. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h index f5dea8bfbc..1a278931ca 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h @@ -28,7 +28,8 @@ class FuzzerPassAddImageSampleUnusedComponents : public FuzzerPass { FuzzerPassAddImageSampleUnusedComponents( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.cpp index 2e50da2628..ab91543b09 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassAddLoads::FuzzerPassAddLoads( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddLoads::Apply() { ForEachInstructionWithInstructionDescriptor( @@ -38,18 +39,22 @@ void FuzzerPassAddLoads::Apply() { "The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction"); - // Check whether it is legitimate to insert a load before this - // instruction. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, inst_it)) { - return; - } - // Randomly decide whether to try inserting a load here. if (!GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->GetChanceOfAddingLoad())) { return; } + // Check whether it is legitimate to insert a load or atomic load before + // this instruction. + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, inst_it)) { + return; + } + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicLoad, + inst_it)) { + return; + } + std::vector relevant_instructions = FindAvailableInstructions( function, block, inst_it, @@ -79,13 +84,53 @@ void FuzzerPassAddLoads::Apply() { return; } - // Choose a pointer at random, and create and apply a loading - // transformation based on it. - ApplyTransformation(TransformationLoad( - GetFuzzerContext()->GetFreshId(), + auto chosen_instruction = relevant_instructions[GetFuzzerContext()->RandomIndex( - relevant_instructions)] - ->result_id(), + relevant_instructions)]; + + bool is_atomic_load = false; + uint32_t memory_scope_id = 0; + uint32_t memory_semantics_id = 0; + + auto storage_class = static_cast( + GetIRContext() + ->get_def_use_mgr() + ->GetDef(chosen_instruction->type_id()) + ->GetSingleWordInOperand(0)); + + switch (storage_class) { + case SpvStorageClassStorageBuffer: + case SpvStorageClassPhysicalStorageBuffer: + case SpvStorageClassWorkgroup: + case SpvStorageClassCrossWorkgroup: + case SpvStorageClassAtomicCounter: + case SpvStorageClassImage: + if (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingAtomicLoad())) { + is_atomic_load = true; + + memory_scope_id = FindOrCreateConstant( + {SpvScopeInvocation}, + FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()), + false); + + memory_semantics_id = FindOrCreateConstant( + {static_cast( + fuzzerutil::GetMemorySemanticsForStorageClass( + storage_class))}, + FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()), + false); + } + break; + + default: + break; + } + + // Create and apply the transformation. + ApplyTransformation(TransformationLoad( + GetFuzzerContext()->GetFreshId(), chosen_instruction->result_id(), + is_atomic_load, memory_scope_id, memory_semantics_id, instruction_descriptor)); }); } diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.h index 3913c6246c..14460e7f95 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loads.h @@ -26,7 +26,8 @@ class FuzzerPassAddLoads : public FuzzerPass { FuzzerPassAddLoads(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.cpp index a50b0b072d..a4e739f8e0 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassAddLocalVariables::FuzzerPassAddLocalVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddLocalVariables::Apply() { auto basic_type_ids_and_pointers = @@ -34,6 +35,10 @@ void FuzzerPassAddLocalVariables::Apply() { // These are the basic types that are available to this fuzzer pass. auto& basic_types = basic_type_ids_and_pointers.first; + if (basic_types.empty()) { + // The pass cannot do anything if there are no basic types. + return; + } // These are the pointers to those basic types that are *initially* available // to the fuzzer pass. The fuzzer pass might add pointer types in cases where diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.h index d73dae29ce..c969ba06c7 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.h @@ -27,7 +27,8 @@ class FuzzerPassAddLocalVariables : public FuzzerPass { FuzzerPassAddLocalVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp index 1cfed866ca..e8c9e964fb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassAddLoopPreheaders::FuzzerPassAddLoopPreheaders( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddLoopPreheaders::Apply() { for (auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.h index 8ac2dac8c2..2a13dbacea 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.h @@ -30,7 +30,8 @@ class FuzzerPassAddLoopPreheaders : public FuzzerPass { FuzzerPassAddLoopPreheaders( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp index 69e0697f87..1a65ef6171 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp @@ -29,9 +29,10 @@ FuzzerPassAddLoopsToCreateIntConstantSynonyms:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddLoopsToCreateIntConstantSynonyms::Apply() { std::vector constants; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h index 2eacef5fc7..14e1754236 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h @@ -28,7 +28,8 @@ class FuzzerPassAddLoopsToCreateIntConstantSynonyms : public FuzzerPass { FuzzerPassAddLoopsToCreateIntConstantSynonyms( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp index d0753100ca..8ae6e90aff 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp @@ -22,9 +22,10 @@ namespace fuzz { FuzzerPassAddNoContractionDecorations::FuzzerPassAddNoContractionDecorations( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddNoContractionDecorations::Apply() { // Consider every instruction in every block in every function. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h index 74212d8719..7aeb26deac 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h @@ -26,7 +26,8 @@ class FuzzerPassAddNoContractionDecorations : public FuzzerPass { FuzzerPassAddNoContractionDecorations( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp index be6e7ea1aa..73b6b0ac74 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassAddOpPhiSynonyms::FuzzerPassAddOpPhiSynonyms( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddOpPhiSynonyms::Apply() { // Get a list of synonymous ids with the same type that can be used in the diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.h index 9077118e25..c45c9a8a12 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.h @@ -25,10 +25,11 @@ namespace fuzz { // synonymous with the others. class FuzzerPassAddOpPhiSynonyms : public FuzzerPass { public: - FuzzerPassAddOpPhiSynonyms( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + FuzzerPassAddOpPhiSynonyms(opt::IRContext* ir_context, + TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.cpp index 784653d8ec..1cb6a79d11 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassAddParameters::FuzzerPassAddParameters( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddParameters::Apply() { // Compute type candidates for the new parameter. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.h index 47dde390e3..c79f0e0969 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.h @@ -30,7 +30,8 @@ class FuzzerPassAddParameters : public FuzzerPass { FuzzerPassAddParameters(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp index 58c6d1b2a0..b8c2b559eb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp @@ -22,9 +22,10 @@ namespace fuzz { FuzzerPassAddRelaxedDecorations::FuzzerPassAddRelaxedDecorations( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddRelaxedDecorations::Apply() { // Consider every instruction in every block in every function. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.h index 723c4a0afe..51eb59424d 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.h @@ -26,7 +26,8 @@ class FuzzerPassAddRelaxedDecorations : public FuzzerPass { FuzzerPassAddRelaxedDecorations( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp index f89428d3d4..606e4a634f 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassAddStores::FuzzerPassAddStores( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddStores::Apply() { ForEachInstructionWithInstructionDescriptor( @@ -38,16 +39,20 @@ void FuzzerPassAddStores::Apply() { "The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction"); + // Randomly decide whether to try inserting a store here. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingStore())) { + return; + } + // Check whether it is legitimate to insert a store before this // instruction. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, inst_it)) { return; } - - // Randomly decide whether to try inserting a store here. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingStore())) { + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicStore, + inst_it)) { return; } @@ -116,10 +121,49 @@ void FuzzerPassAddStores::Apply() { return; } - // Choose a value at random, and create and apply a storing - // transformation based on it and the pointer. + bool is_atomic_store = false; + uint32_t memory_scope_id = 0; + uint32_t memory_semantics_id = 0; + + auto storage_class = + static_cast(GetIRContext() + ->get_def_use_mgr() + ->GetDef(pointer->type_id()) + ->GetSingleWordInOperand(0)); + + switch (storage_class) { + case SpvStorageClassStorageBuffer: + case SpvStorageClassPhysicalStorageBuffer: + case SpvStorageClassWorkgroup: + case SpvStorageClassCrossWorkgroup: + case SpvStorageClassAtomicCounter: + case SpvStorageClassImage: + if (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingAtomicStore())) { + is_atomic_store = true; + + memory_scope_id = FindOrCreateConstant( + {SpvScopeInvocation}, + FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()), + false); + + memory_semantics_id = FindOrCreateConstant( + {static_cast( + fuzzerutil::GetMemorySemanticsForStorageClass( + storage_class))}, + FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()), + false); + } + break; + + default: + break; + } + + // Create and apply the transformation. ApplyTransformation(TransformationStore( - pointer->result_id(), + pointer->result_id(), is_atomic_store, memory_scope_id, + memory_semantics_id, relevant_values[GetFuzzerContext()->RandomIndex(relevant_values)] ->result_id(), instruction_descriptor)); diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.h index 9519c385bb..b18dde1fe7 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_stores.h @@ -28,7 +28,8 @@ class FuzzerPassAddStores : public FuzzerPass { FuzzerPassAddStores(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.cpp index fd866f985b..1d188deb85 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassAddSynonyms::FuzzerPassAddSynonyms( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddSynonyms::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.h index ccf4a88671..b0c174bc4b 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.h @@ -27,7 +27,8 @@ class FuzzerPassAddSynonyms : public FuzzerPass { FuzzerPassAddSynonyms(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp index e2eaaa0a48..a29d1d34d2 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassAddVectorShuffleInstructions::FuzzerPassAddVectorShuffleInstructions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAddVectorShuffleInstructions::Apply() { ForEachInstructionWithInstructionDescriptor( @@ -75,7 +76,7 @@ void FuzzerPassAddVectorShuffleInstructions::Apply() { ->IdIsIrrelevant(instruction->result_id()) && !fuzzerutil::CanMakeSynonymOf(ir_context, *GetTransformationContext(), - instruction)) { + *instruction)) { // If the id is irrelevant, we can use it since it will not // participate in DataSynonym fact. Otherwise, we should be // able to produce a synonym out of the id. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h index c5af374cd3..64d6608a13 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h @@ -26,7 +26,8 @@ class FuzzerPassAddVectorShuffleInstructions : public FuzzerPass { FuzzerPassAddVectorShuffleInstructions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp index 3c4f3803d7..94428f72cc 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassAdjustBranchWeights::FuzzerPassAdjustBranchWeights( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAdjustBranchWeights::Apply() { // For all OpBranchConditional instructions, diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.h index de2f33d3b2..ae1ea3458b 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.h @@ -28,7 +28,8 @@ class FuzzerPassAdjustBranchWeights : public FuzzerPass { FuzzerPassAdjustBranchWeights( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp index b38bd212c7..1c2bc8cf76 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp @@ -22,9 +22,10 @@ namespace fuzz { FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAdjustFunctionControls::Apply() { // Consider every function in the module. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h index 5ef32a180c..7a8c492793 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h @@ -26,7 +26,8 @@ class FuzzerPassAdjustFunctionControls : public FuzzerPass { FuzzerPassAdjustFunctionControls( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp index 0f7cf037ec..fe855cade2 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp @@ -22,9 +22,10 @@ namespace fuzz { FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAdjustLoopControls::Apply() { // Consider every merge instruction in the module (via looking through all diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h index 4ca670b780..25e8304701 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h @@ -26,7 +26,8 @@ class FuzzerPassAdjustLoopControls : public FuzzerPass { FuzzerPassAdjustLoopControls( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp index 778d43ff0e..d2ff40e6fc 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAdjustMemoryOperandsMasks::Apply() { // Consider every block in every function. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h index a068b8dd94..3197f91b34 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h @@ -27,7 +27,8 @@ class FuzzerPassAdjustMemoryOperandsMasks : public FuzzerPass { FuzzerPassAdjustMemoryOperandsMasks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp index d9b4e2939d..7d8e6b5782 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp @@ -22,9 +22,10 @@ namespace fuzz { FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassAdjustSelectionControls::Apply() { // Consider every merge instruction in the module (via looking through all diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h index 6931f942c7..ac55de7925 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h @@ -26,7 +26,8 @@ class FuzzerPassAdjustSelectionControls : public FuzzerPass { FuzzerPassAdjustSelectionControls( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp index 712083132c..5c3b86b954 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp @@ -28,9 +28,10 @@ namespace fuzz { FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassApplyIdSynonyms::Apply() { // Compute a closure of data synonym facts, to enrich the pool of synonyms @@ -197,7 +198,7 @@ bool FuzzerPassApplyIdSynonyms::DataDescriptorsHaveCompatibleTypes( GetIRContext(), base_object_type_id_2, dd2.index()); assert(type_id_1 && type_id_2 && "Data descriptors have invalid types"); - return TransformationReplaceIdWithSynonym::TypesAreCompatible( + return fuzzerutil::TypesAreCompatible( GetIRContext(), opcode, use_in_operand_index, type_id_1, type_id_2); } diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h index b402b50924..3da9c5d69a 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h @@ -28,7 +28,8 @@ class FuzzerPassApplyIdSynonyms : public FuzzerPass { FuzzerPassApplyIdSynonyms(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp index 1a174cf16b..ff022fcca3 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp @@ -26,9 +26,10 @@ namespace fuzz { FuzzerPassConstructComposites::FuzzerPassConstructComposites( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassConstructComposites::Apply() { // Gather up the ids of all composite types, but skip block-/buffer @@ -61,7 +62,7 @@ void FuzzerPassConstructComposites::Apply() { return GetTransformationContext()->GetFactManager()->IdIsIrrelevant( inst->result_id()) || fuzzerutil::CanMakeSynonymOf(ir_context, - *GetTransformationContext(), inst); + *GetTransformationContext(), *inst); }); ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h index 333ac93160..8141398095 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h @@ -29,7 +29,8 @@ class FuzzerPassConstructComposites : public FuzzerPass { FuzzerPassConstructComposites( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp index 09b5368a4c..80cc2a5725 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassCopyObjects::FuzzerPassCopyObjects( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassCopyObjects::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h index 461cd97927..2fb5a53f98 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h @@ -26,7 +26,8 @@ class FuzzerPassCopyObjects : public FuzzerPass { FuzzerPassCopyObjects(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp index 2f2ed50a72..5bdf6973eb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp @@ -45,10 +45,11 @@ FuzzerPassDonateModules::FuzzerPassDonateModules( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations, - const std::vector& donor_suppliers) + bool ignore_inapplicable_transformations, + std::vector donor_suppliers) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations), - donor_suppliers_(donor_suppliers) {} + transformations, ignore_inapplicable_transformations), + donor_suppliers_(std::move(donor_suppliers)) {} void FuzzerPassDonateModules::Apply() { // If there are no donor suppliers, this fuzzer pass is a no-op. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h index 1581a8a4a7..924dd358cd 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h @@ -31,7 +31,8 @@ class FuzzerPassDonateModules : public FuzzerPass { opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations, - const std::vector& donor_suppliers); + bool ignore_inapplicable_transformations, + std::vector donor_suppliers); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp index e08d65b121..3a9a7e6648 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp @@ -25,9 +25,10 @@ FuzzerPassDuplicateRegionsWithSelections:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassDuplicateRegionsWithSelections::Apply() { // Iterate over all of the functions in the module. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h index 7cb1197db0..74343a668e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h @@ -29,7 +29,8 @@ class FuzzerPassDuplicateRegionsWithSelections : public FuzzerPass { FuzzerPassDuplicateRegionsWithSelections( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp index e25dcbc3eb..5bf0461d31 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassExpandVectorReductions::FuzzerPassExpandVectorReductions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassExpandVectorReductions::Apply() { for (auto& function : *GetIRContext()->module()) { @@ -46,7 +47,7 @@ void FuzzerPassExpandVectorReductions::Apply() { // It must be able to make a synonym of |instruction|. if (!fuzzerutil::CanMakeSynonymOf( - GetIRContext(), *GetTransformationContext(), &instruction)) { + GetIRContext(), *GetTransformationContext(), instruction)) { continue; } diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.h index ed0225df1d..c0673e12fc 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_expand_vector_reductions.h @@ -28,7 +28,8 @@ class FuzzerPassExpandVectorReductions : public FuzzerPass { FuzzerPassExpandVectorReductions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp index 84da7a749e..70fa6a12ca 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp @@ -26,9 +26,10 @@ namespace fuzz { FuzzerPassFlattenConditionalBranches::FuzzerPassFlattenConditionalBranches( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassFlattenConditionalBranches::Apply() { for (auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.h index e7d7dc36ab..abfbc3c1b0 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_flatten_conditional_branches.h @@ -25,7 +25,8 @@ class FuzzerPassFlattenConditionalBranches : public FuzzerPass { FuzzerPassFlattenConditionalBranches( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.cpp index 405afd8b16..4024096f46 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassInlineFunctions::FuzzerPassInlineFunctions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassInlineFunctions::Apply() { // |function_call_instructions| are the instructions that will be inlined. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.h index a6ed8cad55..c4e0b83186 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.h @@ -28,7 +28,8 @@ class FuzzerPassInlineFunctions : public FuzzerPass { FuzzerPassInlineFunctions(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp index 675cae9ade..d8780ff747 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp @@ -27,9 +27,10 @@ FuzzerPassInterchangeSignednessOfIntegerOperands:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassInterchangeSignednessOfIntegerOperands::Apply() { assert(!GetFuzzerContext()->IsWgslCompatible() && diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h index 11b8fb6e8b..6a10e89720 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h @@ -32,7 +32,8 @@ class FuzzerPassInterchangeSignednessOfIntegerOperands : public FuzzerPass { FuzzerPassInterchangeSignednessOfIntegerOperands( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp index 5d0a222377..2c16cd5bb7 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassInterchangeZeroLikeConstants::FuzzerPassInterchangeZeroLikeConstants( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} uint32_t FuzzerPassInterchangeZeroLikeConstants::FindOrCreateToggledConstant( opt::Instruction* declaration) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h index 012f03d3b5..bb4a4dc759 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h @@ -33,7 +33,8 @@ class FuzzerPassInterchangeZeroLikeConstants : public FuzzerPass { FuzzerPassInterchangeZeroLikeConstants( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp index 542748e95d..130f75029e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassInvertComparisonOperators::FuzzerPassInvertComparisonOperators( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassInvertComparisonOperators::Apply() { GetIRContext()->module()->ForEachInst([this](const opt::Instruction* inst) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h index 5f015c28dc..d0d09edb6b 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h @@ -27,7 +27,8 @@ class FuzzerPassInvertComparisonOperators : public FuzzerPass { FuzzerPassInvertComparisonOperators( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp index 7bf07a4952..b755d2357e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassMakeVectorOperationsDynamic::FuzzerPassMakeVectorOperationsDynamic( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassMakeVectorOperationsDynamic::Apply() { for (auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h index da27825a41..b6a46c7887 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h @@ -27,7 +27,8 @@ class FuzzerPassMakeVectorOperationsDynamic : public FuzzerPass { FuzzerPassMakeVectorOperationsDynamic( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp index a8ec784c9c..702006292c 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassMergeBlocks::FuzzerPassMergeBlocks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassMergeBlocks::Apply() { // First we populate a sequence of transformations that we might consider diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h index 66cf4c64c1..46e257f127 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h @@ -26,7 +26,8 @@ class FuzzerPassMergeBlocks : public FuzzerPass { FuzzerPassMergeBlocks(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.cpp index ee82eca5e3..220f707b5c 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.cpp @@ -26,9 +26,10 @@ namespace fuzz { FuzzerPassMergeFunctionReturns::FuzzerPassMergeFunctionReturns( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassMergeFunctionReturns::Apply() { // The pass might add new functions to the module (due to wrapping early diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.h index ddd2c9dc38..a799b8be07 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_function_returns.h @@ -31,7 +31,8 @@ class FuzzerPassMergeFunctionReturns : public FuzzerPass { FuzzerPassMergeFunctionReturns( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.cpp index f021a978ac..bbe05409b0 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassMutatePointers::FuzzerPassMutatePointers( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassMutatePointers::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.h index 5ef6a2ab4a..45c6a7cc5c 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_mutate_pointers.h @@ -26,7 +26,8 @@ class FuzzerPassMutatePointers : public FuzzerPass { FuzzerPassMutatePointers(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp index 32318e8965..f60c1b4cdf 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp @@ -30,9 +30,10 @@ namespace fuzz { FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair( uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h index 82b1092c70..30e64d28cb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h @@ -30,7 +30,8 @@ class FuzzerPassObfuscateConstants : public FuzzerPass { FuzzerPassObfuscateConstants( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp index bfde61f7c3..b90c12dc34 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp @@ -27,9 +27,10 @@ namespace fuzz { FuzzerPassOutlineFunctions::FuzzerPassOutlineFunctions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassOutlineFunctions::Apply() { std::vector original_functions; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h index 45e52ff44e..d80dc4a74e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h @@ -24,10 +24,11 @@ namespace fuzz { // flow graph into their own functions. class FuzzerPassOutlineFunctions : public FuzzerPass { public: - FuzzerPassOutlineFunctions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + FuzzerPassOutlineFunctions(opt::IRContext* ir_context, + TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp index 769c49f069..e55fae32ff 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp @@ -22,9 +22,10 @@ namespace fuzz { FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassPermuteBlocks::Apply() { // For now we do something very simple: we randomly decide whether to move a diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h index e40178e656..39326c2b40 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h @@ -27,7 +27,8 @@ class FuzzerPassPermuteBlocks : public FuzzerPass { FuzzerPassPermuteBlocks(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.cpp index 9a61bea0f9..a8035b90cf 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.cpp @@ -28,9 +28,10 @@ namespace fuzz { FuzzerPassPermuteFunctionParameters::FuzzerPassPermuteFunctionParameters( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassPermuteFunctionParameters::Apply() { for (const auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.h index a4bf2ca52d..c5b6ad437a 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.h @@ -32,7 +32,8 @@ class FuzzerPassPermuteFunctionParameters : public FuzzerPass { FuzzerPassPermuteFunctionParameters( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.cpp index a4e19e3b19..f8b9b45034 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.cpp @@ -29,9 +29,11 @@ namespace fuzz { FuzzerPassPermuteFunctionVariables::FuzzerPassPermuteFunctionVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} // Here we call parent constructor. + transformations, ignore_inapplicable_transformations) { +} // Here we call parent constructor. void FuzzerPassPermuteFunctionVariables::Apply() { // Permuting OpVariable instructions in each function. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.h index 47f1de281f..2ebc15f237 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.h @@ -26,7 +26,8 @@ class FuzzerPassPermuteFunctionVariables : public FuzzerPass { FuzzerPassPermuteFunctionVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.cpp index f17e018778..3ef76be476 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassPermuteInstructions::FuzzerPassPermuteInstructions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassPermuteInstructions::Apply() { // We are iterating over all instructions in all basic blocks. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.h index 027101dd44..b7ccbccb84 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.h @@ -27,7 +27,8 @@ class FuzzerPassPermuteInstructions : public FuzzerPass { FuzzerPassPermuteInstructions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.cpp index f2cc52314e..5fac98161b 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.cpp @@ -28,9 +28,10 @@ namespace fuzz { FuzzerPassPermutePhiOperands::FuzzerPassPermutePhiOperands( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassPermutePhiOperands::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.h index 7999956288..30a9d4f5fa 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.h @@ -27,7 +27,8 @@ class FuzzerPassPermutePhiOperands : public FuzzerPass { FuzzerPassPermutePhiOperands( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp index 89e14370f5..4c46dcd34e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassPropagateInstructionsDown::FuzzerPassPropagateInstructionsDown( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassPropagateInstructionsDown::Apply() { for (const auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.h index a2a0aac828..18f0165495 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_down.h @@ -26,7 +26,8 @@ class FuzzerPassPropagateInstructionsDown : public FuzzerPass { FuzzerPassPropagateInstructionsDown( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp index 8cd7437bdb..5e45da83fd 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassPropagateInstructionsUp::FuzzerPassPropagateInstructionsUp( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassPropagateInstructionsUp::Apply() { for (const auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.h index b89be48dd5..0cb8396be4 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.h @@ -27,7 +27,8 @@ class FuzzerPassPropagateInstructionsUp : public FuzzerPass { FuzzerPassPropagateInstructionsUp( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp index 6aebac6687..a6c07b4b34 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassPushIdsThroughVariables::FuzzerPassPushIdsThroughVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassPushIdsThroughVariables::Apply() { ForEachInstructionWithInstructionDescriptor( @@ -102,7 +103,7 @@ void FuzzerPassPushIdsThroughVariables::Apply() { ->IdIsIrrelevant(instruction->result_id()) && !fuzzerutil::CanMakeSynonymOf(ir_context, *GetTransformationContext(), - instruction)) { + *instruction)) { return false; } diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.h index 53008ee223..71b6949251 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.h @@ -28,7 +28,8 @@ class FuzzerPassPushIdsThroughVariables : public FuzzerPass { FuzzerPassPushIdsThroughVariables( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp index 8a83d3bc51..467e613493 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp @@ -29,9 +29,10 @@ FuzzerPassReplaceAddsSubsMulsWithCarryingExtended:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceAddsSubsMulsWithCarryingExtended::Apply() { std::vector instructions_for_transformation; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h index 0e29a6c6b0..268655f97a 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h @@ -29,7 +29,8 @@ class FuzzerPassReplaceAddsSubsMulsWithCarryingExtended : public FuzzerPass { FuzzerPassReplaceAddsSubsMulsWithCarryingExtended( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp index a516f3d45b..995657cc13 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp @@ -28,9 +28,10 @@ FuzzerPassReplaceBranchesFromDeadBlocksWithExits:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceBranchesFromDeadBlocksWithExits::Apply() { // OpKill can only be used as a terminator in a function that is guaranteed diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h index ab7e00e5c5..cdbb66f266 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h @@ -28,7 +28,8 @@ class FuzzerPassReplaceBranchesFromDeadBlocksWithExits : public FuzzerPass { FuzzerPassReplaceBranchesFromDeadBlocksWithExits( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp index f17339a9c8..af1aacee34 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp @@ -26,9 +26,10 @@ FuzzerPassReplaceCopyMemoriesWithLoadsStores:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceCopyMemoriesWithLoadsStores::Apply() { GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h index cffe1cb92c..7d954abebc 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h @@ -28,7 +28,8 @@ class FuzzerPassReplaceCopyMemoriesWithLoadsStores : public FuzzerPass { FuzzerPassReplaceCopyMemoriesWithLoadsStores( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp index 24f2255b74..d0992a3ffb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp @@ -26,9 +26,10 @@ FuzzerPassReplaceCopyObjectsWithStoresLoads:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceCopyObjectsWithStoresLoads::Apply() { GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h index e7b11ce107..2ffc00b651 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h @@ -28,7 +28,8 @@ class FuzzerPassReplaceCopyObjectsWithStoresLoads : public FuzzerPass { FuzzerPassReplaceCopyObjectsWithStoresLoads( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp index 7e9d7baaa1..4d55ae840d 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp @@ -27,9 +27,10 @@ namespace fuzz { FuzzerPassReplaceIrrelevantIds::FuzzerPassReplaceIrrelevantIds( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceIrrelevantIds::Apply() { // Keep track of the irrelevant ids. This includes all the ids that are diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h index 1dc6b5d386..80f8eb8626 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h @@ -28,7 +28,8 @@ class FuzzerPassReplaceIrrelevantIds : public FuzzerPass { FuzzerPassReplaceIrrelevantIds( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp index 0890c2fe70..445dbfe1a0 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp @@ -26,9 +26,10 @@ FuzzerPassReplaceLinearAlgebraInstructions:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceLinearAlgebraInstructions::Apply() { // For each instruction, checks whether it is a linear algebra instruction. In diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h index 5d2f204287..5734bf1f2c 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h @@ -27,7 +27,8 @@ class FuzzerPassReplaceLinearAlgebraInstructions : public FuzzerPass { FuzzerPassReplaceLinearAlgebraInstructions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp index f2cf80fae4..38ac048bf3 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp @@ -27,9 +27,10 @@ FuzzerPassReplaceLoadsStoresWithCopyMemories:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceLoadsStoresWithCopyMemories::Apply() { // We look for matching pairs of instructions OpLoad and diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h index f30fc2b77f..f6209fc058 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h @@ -28,7 +28,8 @@ class FuzzerPassReplaceLoadsStoresWithCopyMemories : public FuzzerPass { FuzzerPassReplaceLoadsStoresWithCopyMemories( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp index b0a3d57c60..ea90a7ac73 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp @@ -24,9 +24,10 @@ FuzzerPassReplaceOpPhiIdsFromDeadPredecessors:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceOpPhiIdsFromDeadPredecessors::Apply() { // Keep a vector of the transformations to apply. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h index a2bc1886a9..b01e242f64 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h @@ -27,7 +27,8 @@ class FuzzerPassReplaceOpPhiIdsFromDeadPredecessors : public FuzzerPass { FuzzerPassReplaceOpPhiIdsFromDeadPredecessors( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp index 10bb90adbd..72ed0936a5 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp @@ -27,9 +27,10 @@ FuzzerPassReplaceOpSelectsWithConditionalBranches:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceOpSelectsWithConditionalBranches::Apply() { // Keep track of the instructions that we want to replace. We need to collect diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h index ec743890eb..174962ee0d 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h @@ -27,7 +27,8 @@ class FuzzerPassReplaceOpSelectsWithConditionalBranches : public FuzzerPass { FuzzerPassReplaceOpSelectsWithConditionalBranches( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp index 5c256bb057..7fb7b0d27f 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp @@ -27,9 +27,10 @@ namespace fuzz { FuzzerPassReplaceParameterWithGlobal::FuzzerPassReplaceParameterWithGlobal( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceParameterWithGlobal::Apply() { for (const auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h index 2ae494696b..4eb508660a 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h @@ -27,7 +27,8 @@ class FuzzerPassReplaceParameterWithGlobal : public FuzzerPass { FuzzerPassReplaceParameterWithGlobal( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp index c045e19f7c..f029316ec1 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp @@ -27,9 +27,10 @@ namespace fuzz { FuzzerPassReplaceParamsWithStruct::FuzzerPassReplaceParamsWithStruct( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassReplaceParamsWithStruct::Apply() { for (const auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.h index f17f520713..3af7367aed 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.h @@ -27,7 +27,8 @@ class FuzzerPassReplaceParamsWithStruct : public FuzzerPass { FuzzerPassReplaceParamsWithStruct( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp index 7b493559bc..40a4151d32 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassSplitBlocks::FuzzerPassSplitBlocks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassSplitBlocks::Apply() { // Gather up pointers to all the blocks in the module. We are then able to diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h index 58f10ddbc0..b1b9424002 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h @@ -27,7 +27,8 @@ class FuzzerPassSplitBlocks : public FuzzerPass { FuzzerPassSplitBlocks(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp index 27fadd173a..dce65f087e 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassSwapCommutableOperands::FuzzerPassSwapCommutableOperands( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassSwapCommutableOperands::Apply() { auto context = GetIRContext(); diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.h index 93de1728d8..13d8fb6ed4 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.h @@ -28,7 +28,8 @@ class FuzzerPassSwapCommutableOperands : public FuzzerPass { FuzzerPassSwapCommutableOperands( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp index b145b3bcad..f8bf111dcf 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp @@ -27,9 +27,10 @@ FuzzerPassSwapBranchConditionalOperands:: opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassSwapBranchConditionalOperands::Apply() { ForEachInstructionWithInstructionDescriptor( diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h index 0137f38b97..7f71f9b1f5 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h @@ -27,7 +27,8 @@ class FuzzerPassSwapBranchConditionalOperands : public FuzzerPass { FuzzerPassSwapBranchConditionalOperands( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.cpp index 171f6cb82c..8eeec850eb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.cpp @@ -23,9 +23,10 @@ namespace fuzz { FuzzerPassSwapFunctions::FuzzerPassSwapFunctions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassSwapFunctions::Apply() { // Collect all function ids in a module. diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.h index ac551f6970..7af527f0d5 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.h @@ -26,7 +26,8 @@ class FuzzerPassSwapFunctions : public FuzzerPass { FuzzerPassSwapFunctions(opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp index e5afd9ee7e..ac2b1565dc 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp @@ -24,9 +24,10 @@ namespace fuzz { FuzzerPassToggleAccessChainInstruction::FuzzerPassToggleAccessChainInstruction( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassToggleAccessChainInstruction::Apply() { auto context = GetIRContext(); diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h index ff2f5d457a..f0b6166b89 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h @@ -27,7 +27,8 @@ class FuzzerPassToggleAccessChainInstruction : public FuzzerPass { FuzzerPassToggleAccessChainInstruction( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; }; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp index 66bbcd81ac..3a3b12c151 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp @@ -25,9 +25,10 @@ namespace fuzz { FuzzerPassWrapRegionsInSelections::FuzzerPassWrapRegionsInSelections( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, ignore_inapplicable_transformations) {} void FuzzerPassWrapRegionsInSelections::Apply() { for (auto& function : *GetIRContext()->module()) { diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h index 822c308f43..fc3d7df9b3 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h @@ -27,7 +27,8 @@ class FuzzerPassWrapRegionsInSelections : public FuzzerPass { FuzzerPassWrapRegionsInSelections( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); void Apply() override; diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp new file mode 100644 index 0000000000..35adcfec00 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp @@ -0,0 +1,144 @@ +// Copyright (c) 2021 Shiyu Liu +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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_wrap_vector_synonym.h" +#include "source/fuzz/fuzzer_context.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/transformation_composite_construct.h" +#include "source/fuzz/transformation_wrap_vector_synonym.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassWrapVectorSynonym::FuzzerPassWrapVectorSynonym( + opt::IRContext* ir_context, TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations) + : FuzzerPass(ir_context, transformation_context, fuzzer_context, + transformations, ignore_inapplicable_transformations) {} + +void FuzzerPassWrapVectorSynonym::Apply() { + ForEachInstructionWithInstructionDescriptor( + [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, + opt::BasicBlock::iterator instruction_iterator, + const protobufs::InstructionDescriptor& instruction_descriptor) + -> void { + + // Randomly decide whether to wrap it to a vector operation. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfWrappingVectorSynonym())) { + return; + } + + // The transformation is not applicable if the instruction has missing + // result id, type id, or is not supported type. + if (!TransformationWrapVectorSynonym::IsInstructionSupported( + GetIRContext(), *instruction_iterator)) { + return; + } + + // It must be valid to insert an OpCompositeConstruct instruction + // before |instruction_iterator|. + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpCompositeConstruct, instruction_iterator)) { + return; + } + + // Get the scalar operands from the original instruction. + opt::Instruction* operand1 = GetIRContext()->get_def_use_mgr()->GetDef( + instruction_iterator->GetSingleWordInOperand(0)); + opt::Instruction* operand2 = GetIRContext()->get_def_use_mgr()->GetDef( + instruction_iterator->GetSingleWordInOperand(1)); + + // We need to be able to make a synonym of the scalar operation's result + // id, as well as the operand ids (for example, they cannot be + // irrelevant). + if (!fuzzerutil::CanMakeSynonymOf(GetIRContext(), + *GetTransformationContext(), + *instruction_iterator)) { + return; + } + if (!fuzzerutil::CanMakeSynonymOf( + GetIRContext(), *GetTransformationContext(), *operand1)) { + return; + } + if (!fuzzerutil::CanMakeSynonymOf( + GetIRContext(), *GetTransformationContext(), *operand2)) { + return; + } + + // Get a random vector size from 2 to 4. + uint32_t vector_size = GetFuzzerContext()->GetWidthOfWrappingVector(); + + // Randomly choose a position that target ids should be placed at. + // The position is in range [0, n - 1], where n is the size of the + // vector. + uint32_t position = + GetFuzzerContext()->GetRandomIndexForWrappingVector(vector_size); + + // Stores the ids of scalar constants. + std::vector vec1_components; + std::vector vec2_components; + + // Populate components based on vector type and size. + for (uint32_t i = 0; i < vector_size; ++i) { + if (i == position) { + vec1_components.emplace_back(operand1->result_id()); + vec2_components.emplace_back(operand2->result_id()); + } else { + vec1_components.emplace_back( + FindOrCreateZeroConstant(operand1->type_id(), true)); + vec2_components.emplace_back( + FindOrCreateZeroConstant(operand2->type_id(), true)); + } + } + + // Add two OpCompositeConstruct to the module with result id returned. + // The added vectors may have different types, for instance if the + // scalar instruction operates on integers with differing sign. + + // Add the first OpCompositeConstruct that wraps the id of the first + // operand. + uint32_t result_id1 = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationCompositeConstruct( + FindOrCreateVectorType(operand1->type_id(), vector_size), + vec1_components, instruction_descriptor, result_id1)); + + // Add the second OpCompositeConstruct that wraps the id of the second + // operand. + uint32_t result_id2 = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationCompositeConstruct( + FindOrCreateVectorType(operand2->type_id(), vector_size), + vec2_components, instruction_descriptor, result_id2)); + + // The result of the vector instruction that + // TransformationWrapVectorSynonym will create should be a vector of the + // right size, with the scalar instruction's result type as its element + // type. This can be distinct from the types of the operands, if the + // scalar instruction adds two signed integers and stores the result in + // an unsigned id, for example. A transformation is applied to add the + // right type to the module. + FindOrCreateVectorType(instruction_iterator->type_id(), vector_size); + + // Apply transformation to do vector operation and add synonym between + // the result vector id and the id of the original instruction. + ApplyTransformation(TransformationWrapVectorSynonym( + instruction_iterator->result_id(), result_id1, result_id2, + GetFuzzerContext()->GetFreshId(), position)); + }); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.h new file mode 100644 index 0000000000..514583832e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.h @@ -0,0 +1,38 @@ +// Copyright (c) 2021 Shiyu Liu +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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_WRAP_VECTOR_SYNONYM_H_ +#define SOURCE_FUZZ_FUZZER_PASS_WRAP_VECTOR_SYNONYM_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// Randomly wrap a scalar operation into a vector operation. +class FuzzerPassWrapVectorSynonym : public FuzzerPass { + public: + FuzzerPassWrapVectorSynonym( + opt::IRContext* ir_context, TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + bool ignore_inapplicable_transformations); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_WRAP_VECTOR_SYNONYM_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_util.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_util.cpp index 4beb67fde6..1d368a9fa6 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_util.cpp +++ b/third_party/spirv-tools/source/fuzz/fuzzer_util.cpp @@ -305,34 +305,34 @@ bool CanInsertOpcodeBeforeInstruction( bool CanMakeSynonymOf(opt::IRContext* ir_context, const TransformationContext& transformation_context, - opt::Instruction* inst) { - if (inst->opcode() == SpvOpSampledImage) { + const opt::Instruction& inst) { + if (inst.opcode() == SpvOpSampledImage) { // The SPIR-V data rules say that only very specific instructions may // may consume the result id of an OpSampledImage, and this excludes the // instructions that are used for making synonyms. return false; } - if (!inst->HasResultId()) { + if (!inst.HasResultId()) { // We can only make a synonym of an instruction that generates an id. return false; } if (transformation_context.GetFactManager()->IdIsIrrelevant( - inst->result_id())) { + inst.result_id())) { // An irrelevant id can't be a synonym of anything. return false; } - if (!inst->type_id()) { + if (!inst.type_id()) { // We can only make a synonym of an instruction that has a type. return false; } - auto type_inst = ir_context->get_def_use_mgr()->GetDef(inst->type_id()); + auto type_inst = ir_context->get_def_use_mgr()->GetDef(inst.type_id()); if (type_inst->opcode() == SpvOpTypeVoid) { // We only make synonyms of instructions that define objects, and an object // cannot have void type. return false; } if (type_inst->opcode() == SpvOpTypePointer) { - switch (inst->opcode()) { + switch (inst.opcode()) { case SpvOpConstantNull: case SpvOpUndef: // We disallow making synonyms of null or undefined pointers. This is @@ -348,7 +348,7 @@ bool CanMakeSynonymOf(opt::IRContext* ir_context, // not decorated analogously, using the original object vs. its synonymous // form may not be equivalent. return ir_context->get_decoration_mgr() - ->GetDecorationsFor(inst->result_id(), true) + ->GetDecorationsFor(inst.result_id(), true) .empty(); } @@ -455,6 +455,30 @@ uint32_t GetBoundForCompositeIndex(const opt::Instruction& composite_type_inst, } } +SpvMemorySemanticsMask GetMemorySemanticsForStorageClass( + SpvStorageClass storage_class) { + switch (storage_class) { + case SpvStorageClassWorkgroup: + return SpvMemorySemanticsWorkgroupMemoryMask; + + case SpvStorageClassStorageBuffer: + case SpvStorageClassPhysicalStorageBuffer: + return SpvMemorySemanticsUniformMemoryMask; + + case SpvStorageClassCrossWorkgroup: + return SpvMemorySemanticsCrossWorkgroupMemoryMask; + + case SpvStorageClassAtomicCounter: + return SpvMemorySemanticsAtomicCounterMemoryMask; + + case SpvStorageClassImage: + return SpvMemorySemanticsImageMemoryMask; + + default: + return SpvMemorySemanticsMaskNone; + } +} + bool IsValid(const opt::IRContext* context, spv_validator_options validator_options, MessageConsumer consumer) { @@ -502,8 +526,12 @@ bool IsValidAndWellFormed(const opt::IRContext* ir_context, // this is a useful aid to debugging. std::unordered_map unique_ids; bool found_duplicate = false; - ir_context->module()->ForEachInst([&consumer, &found_duplicate, + ir_context->module()->ForEachInst([&consumer, &found_duplicate, ir_context, &unique_ids](opt::Instruction* inst) { + (void)ir_context; // Only used in an assertion; keep release-mode compilers + // happy. + assert(inst->context() == ir_context && + "Instruction has wrong IR context."); if (unique_ids.count(inst->unique_id()) != 0) { consumer(SPV_MSG_INFO, nullptr, {}, "Two instructions have the same unique id (set a breakpoint to " @@ -787,11 +815,38 @@ uint32_t InOperandIndexFromOperandIndex(const opt::Instruction& inst, return absolute_index - inst.NumOperands() + inst.NumInOperands(); } -bool IsNullConstantSupported(const opt::analysis::Type& type) { - return type.AsBool() || type.AsInteger() || type.AsFloat() || - type.AsMatrix() || type.AsVector() || type.AsArray() || - type.AsStruct() || type.AsPointer() || type.AsEvent() || - type.AsDeviceEvent() || type.AsReserveId() || type.AsQueue(); +bool IsNullConstantSupported(opt::IRContext* ir_context, + const opt::Instruction& type_inst) { + switch (type_inst.opcode()) { + case SpvOpTypeArray: + case SpvOpTypeBool: + case SpvOpTypeDeviceEvent: + case SpvOpTypeEvent: + case SpvOpTypeFloat: + case SpvOpTypeInt: + case SpvOpTypeMatrix: + case SpvOpTypeQueue: + case SpvOpTypeReserveId: + case SpvOpTypeVector: + case SpvOpTypeStruct: + return true; + case SpvOpTypePointer: + // Null pointers are allowed if the VariablePointers capability is + // enabled, or if the VariablePointersStorageBuffer capability is enabled + // and the pointer type has StorageBuffer as its storage class. + if (ir_context->get_feature_mgr()->HasCapability( + SpvCapabilityVariablePointers)) { + return true; + } + if (ir_context->get_feature_mgr()->HasCapability( + SpvCapabilityVariablePointersStorageBuffer)) { + return type_inst.GetSingleWordInOperand(0) == + SpvStorageClassStorageBuffer; + } + return false; + default: + return false; + } } bool GlobalVariablesMustBeDeclaredInEntryPointInterfaces( @@ -1616,6 +1671,44 @@ bool IdUseCanBeReplaced(opt::IRContext* ir_context, return false; } + if (ir_context->get_feature_mgr()->HasCapability(SpvCapabilityShader)) { + // With the Shader capability, memory scope and memory semantics operands + // are required to be constants, so they cannot be replaced arbitrarily. + switch (use_instruction->opcode()) { + case SpvOpAtomicLoad: + case SpvOpAtomicStore: + case SpvOpAtomicExchange: + case SpvOpAtomicIIncrement: + case SpvOpAtomicIDecrement: + case SpvOpAtomicIAdd: + case SpvOpAtomicISub: + case SpvOpAtomicSMin: + case SpvOpAtomicUMin: + case SpvOpAtomicSMax: + case SpvOpAtomicUMax: + case SpvOpAtomicAnd: + case SpvOpAtomicOr: + case SpvOpAtomicXor: + if (use_in_operand_index == 1 || use_in_operand_index == 2) { + return false; + } + break; + case SpvOpAtomicCompareExchange: + if (use_in_operand_index == 1 || use_in_operand_index == 2 || + use_in_operand_index == 3) { + return false; + } + break; + case SpvOpAtomicCompareExchangeWeak: + case SpvOpAtomicFlagTestAndSet: + case SpvOpAtomicFlagClear: + case SpvOpAtomicFAddEXT: + assert(false && "Not allowed with the Shader capability."); + default: + break; + } + } + return true; } @@ -1925,6 +2018,93 @@ opt::Module::iterator GetFunctionIterator(opt::IRContext* ir_context, }); } +// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3582): Add all +// opcodes that are agnostic to signedness of operands to function. +// This is not exhaustive yet. +bool IsAgnosticToSignednessOfOperand(SpvOp opcode, + uint32_t use_in_operand_index) { + switch (opcode) { + case SpvOpSNegate: + case SpvOpNot: + case SpvOpIAdd: + case SpvOpISub: + case SpvOpIMul: + case SpvOpSDiv: + case SpvOpSRem: + case SpvOpSMod: + case SpvOpShiftRightLogical: + case SpvOpShiftRightArithmetic: + case SpvOpShiftLeftLogical: + case SpvOpBitwiseOr: + case SpvOpBitwiseXor: + case SpvOpBitwiseAnd: + case SpvOpIEqual: + case SpvOpINotEqual: + case SpvOpULessThan: + case SpvOpSLessThan: + case SpvOpUGreaterThan: + case SpvOpSGreaterThan: + case SpvOpULessThanEqual: + case SpvOpSLessThanEqual: + case SpvOpUGreaterThanEqual: + case SpvOpSGreaterThanEqual: + return true; + + case SpvOpAtomicStore: + case SpvOpAtomicExchange: + case SpvOpAtomicIAdd: + case SpvOpAtomicISub: + case SpvOpAtomicSMin: + case SpvOpAtomicUMin: + case SpvOpAtomicSMax: + case SpvOpAtomicUMax: + case SpvOpAtomicAnd: + case SpvOpAtomicOr: + case SpvOpAtomicXor: + case SpvOpAtomicFAddEXT: // Capability AtomicFloat32AddEXT, + // AtomicFloat64AddEXT. + assert(use_in_operand_index != 0 && + "Signedness check should not occur on a pointer operand."); + return use_in_operand_index == 1 || use_in_operand_index == 2; + + case SpvOpAtomicCompareExchange: + case SpvOpAtomicCompareExchangeWeak: // Capability Kernel. + assert(use_in_operand_index != 0 && + "Signedness check should not occur on a pointer operand."); + return use_in_operand_index >= 1 && use_in_operand_index <= 3; + + case SpvOpAtomicLoad: + case SpvOpAtomicIIncrement: + case SpvOpAtomicIDecrement: + case SpvOpAtomicFlagTestAndSet: // Capability Kernel. + case SpvOpAtomicFlagClear: // Capability Kernel. + assert(use_in_operand_index != 0 && + "Signedness check should not occur on a pointer operand."); + return use_in_operand_index >= 1; + + case SpvOpAccessChain: + // The signedness of indices does not matter. + return use_in_operand_index > 0; + + default: + // Conservatively assume that the id cannot be swapped in other + // instructions. + return false; + } +} + +bool TypesAreCompatible(opt::IRContext* ir_context, SpvOp opcode, + uint32_t use_in_operand_index, uint32_t type_id_1, + uint32_t type_id_2) { + assert(ir_context->get_type_mgr()->GetType(type_id_1) && + ir_context->get_type_mgr()->GetType(type_id_2) && + "Type ids are invalid"); + + return type_id_1 == type_id_2 || + (IsAgnosticToSignednessOfOperand(opcode, use_in_operand_index) && + fuzzerutil::TypesAreEqualUpToSign(ir_context, type_id_1, type_id_2)); +} + } // namespace fuzzerutil } // namespace fuzz } // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_util.h b/third_party/spirv-tools/source/fuzz/fuzzer_util.h index b956507a91..54aa14a2fb 100644 --- a/third_party/spirv-tools/source/fuzz/fuzzer_util.h +++ b/third_party/spirv-tools/source/fuzz/fuzzer_util.h @@ -118,7 +118,7 @@ bool CanInsertOpcodeBeforeInstruction( // does not participate in IdIsIrrelevant fact. bool CanMakeSynonymOf(opt::IRContext* ir_context, const TransformationContext& transformation_context, - opt::Instruction* inst); + const opt::Instruction& inst); // Determines whether the given type is a composite; that is: an array, matrix, // struct or vector. @@ -169,6 +169,10 @@ uint32_t GetArraySize(const opt::Instruction& array_type_instruction, uint32_t GetBoundForCompositeIndex(const opt::Instruction& composite_type_inst, opt::IRContext* ir_context); +// Returns memory semantics mask for specific storage class. +SpvMemorySemanticsMask GetMemorySemanticsForStorageClass( + SpvStorageClass storage_class); + // Returns true if and only if |context| is valid, according to the validator // instantiated with |validator_options|. |consumer| is used for error // reporting. @@ -273,8 +277,10 @@ uint32_t InOperandIndexFromOperandIndex(const opt::Instruction& inst, uint32_t absolute_index); // Returns true if and only if |type| is one of the types for which it is legal -// to have an OpConstantNull value. -bool IsNullConstantSupported(const opt::analysis::Type& type); +// to have an OpConstantNull value. This may depend on the capabilities declared +// in |context|. +bool IsNullConstantSupported(opt::IRContext* context, + const opt::Instruction& type); // Returns true if and only if the SPIR-V version being used requires that // global variables accessed in the static call graph of an entry point need @@ -598,6 +604,21 @@ bool NewTerminatorPreservesDominationRules(opt::IRContext* ir_context, opt::Module::iterator GetFunctionIterator(opt::IRContext* ir_context, uint32_t function_id); +// Returns true if the instruction with opcode |opcode| does not change its +// behaviour depending on the signedness of the operand at +// |use_in_operand_index|. +// Assumes that the operand must be the id of an integer scalar or vector. +bool IsAgnosticToSignednessOfOperand(SpvOp opcode, + uint32_t use_in_operand_index); + +// Returns true if |type_id_1| and |type_id_2| represent compatible types +// given the context of the instruction with |opcode| (i.e. we can replace +// an operand of |opcode| of the first type with an id of the second type +// and vice-versa). +bool TypesAreCompatible(opt::IRContext* ir_context, SpvOp opcode, + uint32_t use_in_operand_index, uint32_t type_id_1, + uint32_t type_id_2); + } // namespace fuzzerutil } // namespace fuzz } // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_instances.h b/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_instances.h index 80ac0875e5..da61fdabc7 100644 --- a/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_instances.h +++ b/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_instances.h @@ -73,6 +73,7 @@ #include "source/fuzz/fuzzer_pass_split_blocks.h" #include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h" #include "source/fuzz/fuzzer_pass_wrap_regions_in_selections.h" +#include "source/fuzz/fuzzer_pass_wrap_vector_synonym.h" namespace spvtools { namespace fuzz { @@ -168,6 +169,7 @@ class RepeatedPassInstances { REPEATED_PASS_INSTANCE(SplitBlocks); REPEATED_PASS_INSTANCE(SwapBranchConditionalOperands); REPEATED_PASS_INSTANCE(WrapRegionsInSelections); + REPEATED_PASS_INSTANCE(WrapVectorSynonym); #undef REPEATED_PASS_INSTANCE public: diff --git a/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_recommender_standard.cpp b/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_recommender_standard.cpp index a933848d4c..6c61c0d4e4 100644 --- a/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_recommender_standard.cpp +++ b/third_party/spirv-tools/source/fuzz/pass_management/repeated_pass_recommender_standard.cpp @@ -351,6 +351,12 @@ RepeatedPassRecommenderStandard::GetFuturePassRecommendations( pass_instances_->GetReplaceIrrelevantIds(), pass_instances_->GetFlattenConditionalBranches()}); } + if (&pass == pass_instances_->GetWrapVectorSynonym()) { + // This transformation introduces synonym facts and irrelevant ids. + return RandomOrderAndNonNull({pass_instances_->GetApplyIdSynonyms(), + pass_instances_->GetReplaceIrrelevantIds()}); + } + assert(false && "Unreachable: every fuzzer pass should be dealt with."); return {}; } diff --git a/third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h b/third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h index eb8cb14514..46c218814e 100644 --- a/third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h +++ b/third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h @@ -23,8 +23,11 @@ #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-parameter" +#pragma clang diagnostic ignored "-Wunknown-warning-option" // Must come first +#pragma clang diagnostic ignored "-Wreserved-identifier" #pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wsuggest-destructor-override" +#pragma clang diagnostic ignored "-Wunused-parameter" #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" diff --git a/third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto index 657e807616..cba9397b54 100644 --- a/third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto +++ b/third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -559,6 +559,7 @@ message Transformation { TransformationExpandVectorReduction expand_vector_reduction = 85; TransformationSwapFunctionVariables swap_function_variables = 86; TransformationSwapTwoFunctions swap_two_functions = 87; + TransformationWrapVectorSynonym wrap_vector_synonym = 88; // Add additional option using the next available number. } } @@ -1568,17 +1569,26 @@ message TransformationInvertComparisonOperator { message TransformationLoad { - // Transformation that adds an OpLoad instruction from a pointer into an id. + // Transformation that adds an OpLoad or OpAtomicLoad instruction from a pointer into an id. - // The result of the load instruction + // The result of the load instruction. uint32 fresh_id = 1; - // The pointer to be loaded from + // The pointer to be loaded from. uint32 pointer_id = 2; + // True if and only if the load should be atomic. + bool is_atomic = 3; + + // The memory scope for the atomic load. Ignored unless |is_atomic| is true. + uint32 memory_scope_id = 4; + + // The memory semantics for the atomic load. Ignored unless |is_atomic| is true. + uint32 memory_semantics_id = 5; + // A descriptor for an instruction in a block before which the new OpLoad - // instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 3; + // instruction should be inserted. + InstructionDescriptor instruction_to_insert_before = 6; } @@ -2235,17 +2245,26 @@ message TransformationSplitBlock { message TransformationStore { - // Transformation that adds an OpStore instruction of an id to a pointer. + // Transformation that adds an OpStore or OpAtomicStore instruction of an id to a pointer. - // The pointer to be stored to + // The pointer to be stored to. uint32 pointer_id = 1; - // The value to be stored - uint32 value_id = 2; + // True if and only if the load should be atomic. + bool is_atomic = 2; + + // The memory scope for the atomic load. Ignored unless |is_atomic| is true. + uint32 memory_scope_id = 3; + + // The memory semantics for the atomic load. Ignored unless |is_atomic| is true. + uint32 memory_semantics_id = 4; + + // The value to be stored. + uint32 value_id = 5; // A descriptor for an instruction in a block before which the new OpStore - // instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 3; + // instruction should be inserted. + InstructionDescriptor instruction_to_insert_before = 6; } @@ -2371,3 +2390,39 @@ message TransformationWrapRegionInSelection { bool branch_condition = 3; } + +message TransformationWrapVectorSynonym { + // A transformation that wraps an arithmetic operation into a vector operation + // and get the result of the original operation from the corresponding index. + // For instance, for this transformation, an scalar operation between two scalars: + // define op ∈ {+, -, *} + // c = a op b + // + // requires the availability of two vectors: + // + // va = vector(..., a, ...) + // vb = vector(..., b, ...) + // + // where a and b are in the same position i in each of their correponding vector + // and a is synonymous with va[i] and b is synonymous with vb[i]. + // + // The transformation then add an instruction vc = va op vb where c is synonymous + // with vc[i]. + + // The result if of the original scalar operation instruction. + uint32 instruction_id = 1; + + // The result id for the first vector that contains the first value of the scalar operation. + uint32 vector_operand1 = 2; + + // The result id for the second vector that contains the second value of the scalar operation. + uint32 vector_operand2 = 3; + + // A fresh id for the resulted vector from the addition of the first and second vector. + uint32 fresh_id = 4; + + // The position in the vector where the value of original instruction is located. Must be in + // the corresponding vector range. + uint32 scalar_position = 5; + +} diff --git a/third_party/spirv-tools/source/fuzz/transformation.cpp b/third_party/spirv-tools/source/fuzz/transformation.cpp index 4ea0c773c6..70a302b752 100644 --- a/third_party/spirv-tools/source/fuzz/transformation.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation.cpp @@ -104,6 +104,7 @@ #include "source/fuzz/transformation_vector_shuffle.h" #include "source/fuzz/transformation_wrap_early_terminator_in_function.h" #include "source/fuzz/transformation_wrap_region_in_selection.h" +#include "source/fuzz/transformation_wrap_vector_synonym.h" #include "source/util/make_unique.h" namespace spvtools { @@ -382,6 +383,9 @@ std::unique_ptr Transformation::FromMessage( case protobufs::Transformation::TransformationCase::kWrapRegionInSelection: return MakeUnique( message.wrap_region_in_selection()); + case protobufs::Transformation::TransformationCase::kWrapVectorSynonym: + return MakeUnique( + message.wrap_vector_synonym()); case protobufs::Transformation::TRANSFORMATION_NOT_SET: assert(false && "An unset transformation was encountered."); return nullptr; diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_constant_null.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_constant_null.cpp index 32544e6deb..c0f736709d 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_add_constant_null.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_add_constant_null.cpp @@ -35,14 +35,14 @@ bool TransformationAddConstantNull::IsApplicable( if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { return false; } - auto type = context->get_type_mgr()->GetType(message_.type_id()); + auto type = context->get_def_use_mgr()->GetDef(message_.type_id()); // The type must exist. if (!type) { return false; } // The type must be one of the types for which null constants are allowed, // according to the SPIR-V spec. - return fuzzerutil::IsNullConstantSupported(*type); + return fuzzerutil::IsNullConstantSupported(context, *type); } void TransformationAddConstantNull::Apply( diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp index eb390ea0df..ec0574a44b 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp @@ -15,6 +15,7 @@ #include "source/fuzz/transformation_add_global_undef.h" #include "source/fuzz/fuzzer_util.h" +#include "source/opt/reflect.h" namespace spvtools { namespace fuzz { @@ -35,9 +36,11 @@ bool TransformationAddGlobalUndef::IsApplicable( if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { return false; } - auto type = ir_context->get_type_mgr()->GetType(message_.type_id()); - // The type must exist, and must not be a function type. - return type && !type->AsFunction(); + auto type = ir_context->get_def_use_mgr()->GetDef(message_.type_id()); + // The type must exist, and must not be a function or pointer type. + return type != nullptr && opt::IsTypeInst(type->opcode()) && + type->opcode() != SpvOpTypeFunction && + type->opcode() != SpvOpTypePointer; } void TransformationAddGlobalUndef::Apply( diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h index 37542c3fda..fff1ad9d6c 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h +++ b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h @@ -31,7 +31,7 @@ class TransformationAddGlobalUndef : public Transformation { TransformationAddGlobalUndef(uint32_t fresh_id, uint32_t type_id); // - |message_.fresh_id| must be fresh - // - |message_.type_id| must be the id of a non-function type + // - |message_.type_id| must be the id of a non-function, non-pointer type bool IsApplicable( opt::IRContext* ir_context, const TransformationContext& transformation_context) const override; diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_synonym.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_synonym.cpp index a1949fbcea..69269e5e34 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_add_synonym.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_add_synonym.cpp @@ -151,7 +151,8 @@ bool TransformationAddSynonym::IsInstructionValid( return false; } - if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, inst)) { + if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, + *inst)) { return false; } diff --git a/third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp b/third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp index 0cd2308bc8..2d8e59918a 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp @@ -297,7 +297,7 @@ void TransformationCompositeConstruct::AddDataSynonymFacts( composite_type->AsVector() && component_type->AsVector(); if (!fuzzerutil::CanMakeSynonymOf( ir_context, *transformation_context, - ir_context->get_def_use_mgr()->GetDef(component))) { + *ir_context->get_def_use_mgr()->GetDef(component))) { // We can't make a synonym of this component, so we skip on to the next // component. In the case where we're packing a vector into a vector we // have to skip as many components of the resulting vectors as there are diff --git a/third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp b/third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp index 647cd74e6d..0fbd4e1b19 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp @@ -125,7 +125,7 @@ void TransformationCompositeExtract::AddDataSynonymFacts( // or if the result id into which we are extracting is irrelevant. if (!fuzzerutil::CanMakeSynonymOf( ir_context, *transformation_context, - ir_context->get_def_use_mgr()->GetDef(message_.composite_id())) || + *ir_context->get_def_use_mgr()->GetDef(message_.composite_id())) || transformation_context->GetFactManager()->IdIsIrrelevant( message_.fresh_id())) { return; diff --git a/third_party/spirv-tools/source/fuzz/transformation_composite_insert.cpp b/third_party/spirv-tools/source/fuzz/transformation_composite_insert.cpp index 05162bfc9e..60fa562815 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_composite_insert.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_composite_insert.cpp @@ -219,9 +219,9 @@ void TransformationCompositeInsert::AddDataSynonymFacts( continue; } current_index.push_back(i); - if (fuzzerutil::CanMakeSynonymOf( - ir_context, *transformation_context, - ir_context->get_def_use_mgr()->GetDef(message_.composite_id()))) { + if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context, + *ir_context->get_def_use_mgr()->GetDef( + message_.composite_id()))) { transformation_context->GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(message_.fresh_id(), current_index), MakeDataDescriptor(message_.composite_id(), current_index)); @@ -235,7 +235,7 @@ void TransformationCompositeInsert::AddDataSynonymFacts( // synonymous with the result of the insert instruction at the given index. if (fuzzerutil::CanMakeSynonymOf( ir_context, *transformation_context, - ir_context->get_def_use_mgr()->GetDef(message_.object_id()))) { + *ir_context->get_def_use_mgr()->GetDef(message_.object_id()))) { transformation_context->GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(message_.object_id(), {}), MakeDataDescriptor(message_.fresh_id(), index)); diff --git a/third_party/spirv-tools/source/fuzz/transformation_duplicate_region_with_selection.cpp b/third_party/spirv-tools/source/fuzz/transformation_duplicate_region_with_selection.cpp index dee1207fa6..a80becd97b 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_duplicate_region_with_selection.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_duplicate_region_with_selection.cpp @@ -309,9 +309,9 @@ void TransformationDuplicateRegionWithSelection::Apply( // Construct the merge block. std::unique_ptr merge_block = - MakeUnique(MakeUnique(opt::Instruction( + MakeUnique(MakeUnique( ir_context, SpvOpLabel, 0, message_.merge_label_fresh_id(), - opt::Instruction::OperandList()))); + opt::Instruction::OperandList())); // Get the maps from the protobuf. std::map original_label_to_duplicate_label = diff --git a/third_party/spirv-tools/source/fuzz/transformation_expand_vector_reduction.cpp b/third_party/spirv-tools/source/fuzz/transformation_expand_vector_reduction.cpp index 9938706698..bafcf9292c 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_expand_vector_reduction.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_expand_vector_reduction.cpp @@ -129,7 +129,7 @@ void TransformationExpandVectorReduction::Apply( // If it's possible to make a synonym of |instruction|, then add the fact that // the last |logical_instruction| is a synonym of |instruction|. if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context, - instruction)) { + *instruction)) { transformation_context->GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(logical_instruction.result_id(), {}), MakeDataDescriptor(instruction->result_id(), {})); diff --git a/third_party/spirv-tools/source/fuzz/transformation_load.cpp b/third_party/spirv-tools/source/fuzz/transformation_load.cpp index e22f8dd292..bf48d996bc 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_load.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_load.cpp @@ -24,10 +24,15 @@ TransformationLoad::TransformationLoad(protobufs::TransformationLoad message) : message_(std::move(message)) {} TransformationLoad::TransformationLoad( - uint32_t fresh_id, uint32_t pointer_id, + uint32_t fresh_id, uint32_t pointer_id, bool is_atomic, + uint32_t memory_scope, uint32_t memory_semantics, const protobufs::InstructionDescriptor& instruction_to_insert_before) { message_.set_fresh_id(fresh_id); message_.set_pointer_id(pointer_id); + message_.set_is_atomic(is_atomic); + message_.set_memory_scope_id(memory_scope); + message_.set_memory_semantics_id(memory_semantics); + *message_.mutable_instruction_to_insert_before() = instruction_to_insert_before; } @@ -68,11 +73,98 @@ bool TransformationLoad::IsApplicable( if (!insert_before) { return false; } - // ... and it must be legitimate to insert a store before it. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, insert_before)) { + // ... and it must be legitimate to insert a load before it. + if (!message_.is_atomic() && + !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, insert_before)) { return false; } + if (message_.is_atomic() && !fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpAtomicLoad, insert_before)) { + return false; + } + + if (message_.is_atomic()) { + // Check the exists of memory scope and memory semantics ids. + auto memory_scope_instruction = + ir_context->get_def_use_mgr()->GetDef(message_.memory_scope_id()); + auto memory_semantics_instruction = + ir_context->get_def_use_mgr()->GetDef(message_.memory_semantics_id()); + + if (!memory_scope_instruction) { + return false; + } + if (!memory_semantics_instruction) { + return false; + } + // The memory scope and memory semantics instructions must have the + // 'OpConstant' opcode. + if (memory_scope_instruction->opcode() != SpvOpConstant) { + return false; + } + if (memory_semantics_instruction->opcode() != SpvOpConstant) { + return false; + } + // The memory scope and memory semantics need to be available before + // |insert_before|. + if (!fuzzerutil::IdIsAvailableBeforeInstruction( + ir_context, insert_before, message_.memory_scope_id())) { + return false; + } + if (!fuzzerutil::IdIsAvailableBeforeInstruction( + ir_context, insert_before, message_.memory_semantics_id())) { + return false; + } + // The memory scope and memory semantics instructions must have an Integer + // operand type with signedness does not matters. + if (ir_context->get_def_use_mgr() + ->GetDef(memory_scope_instruction->type_id()) + ->opcode() != SpvOpTypeInt) { + return false; + } + if (ir_context->get_def_use_mgr() + ->GetDef(memory_semantics_instruction->type_id()) + ->opcode() != SpvOpTypeInt) { + return false; + } + + // The size of the integer for memory scope and memory semantics + // instructions must be equal to 32 bits. + auto memory_scope_int_width = + ir_context->get_def_use_mgr() + ->GetDef(memory_scope_instruction->type_id()) + ->GetSingleWordInOperand(0); + auto memory_semantics_int_width = + ir_context->get_def_use_mgr() + ->GetDef(memory_semantics_instruction->type_id()) + ->GetSingleWordInOperand(0); + + if (memory_scope_int_width != 32) { + return false; + } + if (memory_semantics_int_width != 32) { + return false; + } + + // The memory scope constant value must be that of SpvScopeInvocation. + auto memory_scope_const_value = + memory_scope_instruction->GetSingleWordInOperand(0); + if (memory_scope_const_value != SpvScopeInvocation) { + return false; + } + + // The memory semantics constant value must match the storage class of the + // pointer being loaded from. + auto memory_semantics_const_value = static_cast( + memory_semantics_instruction->GetSingleWordInOperand(0)); + if (memory_semantics_const_value != + fuzzerutil::GetMemorySemanticsForStorageClass( + static_cast( + pointer_type->GetSingleWordInOperand(0)))) { + return false; + } + } + // The pointer needs to be available at the insertion point. return fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, message_.pointer_id()); @@ -80,22 +172,46 @@ bool TransformationLoad::IsApplicable( void TransformationLoad::Apply(opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - uint32_t result_type = fuzzerutil::GetPointeeTypeIdFromPointerType( - ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id())); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - auto insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - auto new_instruction = MakeUnique( - ir_context, SpvOpLoad, result_type, message_.fresh_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}})); - auto new_instruction_ptr = new_instruction.get(); - insert_before->InsertBefore(std::move(new_instruction)); - // Inform the def-use manager about the new instruction and record its basic - // block. - ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); - ir_context->set_instr_block(new_instruction_ptr, - ir_context->get_instr_block(insert_before)); + if (message_.is_atomic()) { + // OpAtomicLoad instruction. + uint32_t result_type = fuzzerutil::GetPointeeTypeIdFromPointerType( + ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id())); + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + auto new_instruction = MakeUnique( + ir_context, SpvOpAtomicLoad, result_type, message_.fresh_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, + {SPV_OPERAND_TYPE_SCOPE_ID, {message_.memory_scope_id()}}, + {SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID, + {message_.memory_semantics_id()}}})); + auto new_instruction_ptr = new_instruction.get(); + insert_before->InsertBefore(std::move(new_instruction)); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); + } else { + // OpLoad instruction. + uint32_t result_type = fuzzerutil::GetPointeeTypeIdFromPointerType( + ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id())); + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + auto new_instruction = MakeUnique( + ir_context, SpvOpLoad, result_type, message_.fresh_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}})); + auto new_instruction_ptr = new_instruction.get(); + insert_before->InsertBefore(std::move(new_instruction)); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); + } } protobufs::Transformation TransformationLoad::ToMessage() const { diff --git a/third_party/spirv-tools/source/fuzz/transformation_load.h b/third_party/spirv-tools/source/fuzz/transformation_load.h index d10b0073d8..57b4a53516 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_load.h +++ b/third_party/spirv-tools/source/fuzz/transformation_load.h @@ -28,11 +28,20 @@ class TransformationLoad : public Transformation { explicit TransformationLoad(protobufs::TransformationLoad message); TransformationLoad( - uint32_t fresh_id, uint32_t pointer_id, + uint32_t fresh_id, uint32_t pointer_id, bool is_atomic, + uint32_t memory_scope, uint32_t memory_semantics, const protobufs::InstructionDescriptor& instruction_to_insert_before); // - |message_.fresh_id| must be fresh // - |message_.pointer_id| must be the id of a pointer + // - |message_.is_atomic| must be true if want to work with OpAtomicLoad + // - If |is_atomic| is true then |message_memory_scope_id| must be the id of + // an OpConstant 32 bit integer instruction with the value + // SpvScopeInvocation. + // - If |is_atomic| is true then |message_.memory_semantics_id| must be the id + // of an OpConstant 32 bit integer instruction with the values + // SpvMemorySemanticsWorkgroupMemoryMask or + // SpvMemorySemanticsUniformMemoryMask. // - The pointer must not be OpConstantNull or OpUndef // - |message_.instruction_to_insert_before| must identify an instruction // before which it is valid to insert an OpLoad, and where diff --git a/third_party/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp b/third_party/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp index ff52516545..55a57a1518 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp @@ -155,7 +155,7 @@ void TransformationPushIdThroughVariable::Apply( // We should be able to create a synonym of |value_id| if it's not irrelevant. if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context, - value_instruction) && + *value_instruction) && !transformation_context->GetFactManager()->IdIsIrrelevant( message_.value_synonym_id())) { // Adds the fact that |message_.value_synonym_id| diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp index 92ce751dd5..8d21d233a4 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp @@ -65,9 +65,10 @@ bool TransformationReplaceIdWithSynonym::IsApplicable( // If the id of interest and the synonym are scalar or vector integer // constants with different signedness, their use can only be swapped if the // instruction is agnostic to the signedness of the operand. - if (!TypesAreCompatible(ir_context, use_instruction->opcode(), - message_.id_use_descriptor().in_operand_index(), - type_id_of_interest, type_id_synonym)) { + if (!fuzzerutil::TypesAreCompatible( + ir_context, use_instruction->opcode(), + message_.id_use_descriptor().in_operand_index(), type_id_of_interest, + type_id_synonym)) { return false; } @@ -109,59 +110,6 @@ protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage() return result; } -// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3582): Add all -// opcodes that are agnostic to signedness of operands to function. -// This is not exhaustive yet. -bool TransformationReplaceIdWithSynonym::IsAgnosticToSignednessOfOperand( - SpvOp opcode, uint32_t use_in_operand_index) { - switch (opcode) { - case SpvOpSNegate: - case SpvOpNot: - case SpvOpIAdd: - case SpvOpISub: - case SpvOpIMul: - case SpvOpSDiv: - case SpvOpSRem: - case SpvOpSMod: - case SpvOpShiftRightLogical: - case SpvOpShiftRightArithmetic: - case SpvOpShiftLeftLogical: - case SpvOpBitwiseOr: - case SpvOpBitwiseXor: - case SpvOpBitwiseAnd: - case SpvOpIEqual: - case SpvOpINotEqual: - case SpvOpULessThan: - case SpvOpSLessThan: - case SpvOpUGreaterThan: - case SpvOpSGreaterThan: - case SpvOpULessThanEqual: - case SpvOpSLessThanEqual: - case SpvOpUGreaterThanEqual: - case SpvOpSGreaterThanEqual: - return true; - case SpvOpAccessChain: - // The signedness of indices does not matter. - return use_in_operand_index > 0; - default: - // Conservatively assume that the id cannot be swapped in other - // instructions. - return false; - } -} - -bool TransformationReplaceIdWithSynonym::TypesAreCompatible( - opt::IRContext* ir_context, SpvOp opcode, uint32_t use_in_operand_index, - uint32_t type_id_1, uint32_t type_id_2) { - assert(ir_context->get_type_mgr()->GetType(type_id_1) && - ir_context->get_type_mgr()->GetType(type_id_2) && - "Type ids are invalid"); - - return type_id_1 == type_id_2 || - (IsAgnosticToSignednessOfOperand(opcode, use_in_operand_index) && - fuzzerutil::TypesAreEqualUpToSign(ir_context, type_id_1, type_id_2)); -} - std::unordered_set TransformationReplaceIdWithSynonym::GetFreshIds() const { return std::unordered_set(); diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h index 1ac636b4b5..4570fcefec 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h @@ -52,22 +52,7 @@ class TransformationReplaceIdWithSynonym : public Transformation { protobufs::Transformation ToMessage() const override; - // Returns true if |type_id_1| and |type_id_2| represent compatible types - // given the context of the instruction with |opcode| (i.e. we can replace - // an operand of |opcode| of the first type with an id of the second type - // and vice-versa). - static bool TypesAreCompatible(opt::IRContext* ir_context, SpvOp opcode, - uint32_t use_in_operand_index, - uint32_t type_id_1, uint32_t type_id_2); - private: - // Returns true if the instruction with opcode |opcode| does not change its - // behaviour depending on the signedness of the operand at - // |use_in_operand_index|. - // Assumes that the operand must be the id of an integer scalar or vector. - static bool IsAgnosticToSignednessOfOperand(SpvOp opcode, - uint32_t use_in_operand_index); - protobufs::TransformationReplaceIdWithSynonym message_; }; diff --git a/third_party/spirv-tools/source/fuzz/transformation_store.cpp b/third_party/spirv-tools/source/fuzz/transformation_store.cpp index f8c6d013ba..c00cd345d7 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_store.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_store.cpp @@ -24,9 +24,13 @@ TransformationStore::TransformationStore(protobufs::TransformationStore message) : message_(std::move(message)) {} TransformationStore::TransformationStore( - uint32_t pointer_id, uint32_t value_id, + uint32_t pointer_id, bool is_atomic, uint32_t memory_scope, + uint32_t memory_semantics, uint32_t value_id, const protobufs::InstructionDescriptor& instruction_to_insert_before) { message_.set_pointer_id(pointer_id); + message_.set_is_atomic(is_atomic); + message_.set_memory_scope_id(memory_scope); + message_.set_memory_semantics_id(memory_semantics); message_.set_value_id(value_id); *message_.mutable_instruction_to_insert_before() = instruction_to_insert_before; @@ -70,8 +74,12 @@ bool TransformationStore::IsApplicable( return false; } // ... and it must be legitimate to insert a store before it. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, - insert_before)) { + if (!message_.is_atomic() && !fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpStore, insert_before)) { + return false; + } + if (message_.is_atomic() && !fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpAtomicStore, insert_before)) { return false; } @@ -102,6 +110,87 @@ bool TransformationStore::IsApplicable( return false; } + if (message_.is_atomic()) { + // Check the exists of memory scope and memory semantics ids. + auto memory_scope_instruction = + ir_context->get_def_use_mgr()->GetDef(message_.memory_scope_id()); + auto memory_semantics_instruction = + ir_context->get_def_use_mgr()->GetDef(message_.memory_semantics_id()); + + if (!memory_scope_instruction) { + return false; + } + if (!memory_semantics_instruction) { + return false; + } + // The memory scope and memory semantics instructions must have the + // 'OpConstant' opcode. + if (memory_scope_instruction->opcode() != SpvOpConstant) { + return false; + } + if (memory_semantics_instruction->opcode() != SpvOpConstant) { + return false; + } + // The memory scope and memory semantics need to be available before + // |insert_before|. + if (!fuzzerutil::IdIsAvailableBeforeInstruction( + ir_context, insert_before, message_.memory_scope_id())) { + return false; + } + if (!fuzzerutil::IdIsAvailableBeforeInstruction( + ir_context, insert_before, message_.memory_semantics_id())) { + return false; + } + // The memory scope and memory semantics instructions must have an Integer + // operand type with signedness does not matters. + if (ir_context->get_def_use_mgr() + ->GetDef(memory_scope_instruction->type_id()) + ->opcode() != SpvOpTypeInt) { + return false; + } + if (ir_context->get_def_use_mgr() + ->GetDef(memory_semantics_instruction->type_id()) + ->opcode() != SpvOpTypeInt) { + return false; + } + + // The size of the integer for memory scope and memory semantics + // instructions must be equal to 32 bits. + auto memory_scope_int_width = + ir_context->get_def_use_mgr() + ->GetDef(memory_scope_instruction->type_id()) + ->GetSingleWordInOperand(0); + auto memory_semantics_int_width = + ir_context->get_def_use_mgr() + ->GetDef(memory_semantics_instruction->type_id()) + ->GetSingleWordInOperand(0); + + if (memory_scope_int_width != 32) { + return false; + } + if (memory_semantics_int_width != 32) { + return false; + } + + // The memory scope constant value must be that of SpvScopeInvocation. + auto memory_scope_const_value = + memory_scope_instruction->GetSingleWordInOperand(0); + if (memory_scope_const_value != SpvScopeInvocation) { + return false; + } + + // The memory semantics constant value must match the storage class of the + // pointer being loaded from. + auto memory_semantics_const_value = static_cast( + memory_semantics_instruction->GetSingleWordInOperand(0)); + if (memory_semantics_const_value != + fuzzerutil::GetMemorySemanticsForStorageClass( + static_cast( + pointer_type->GetSingleWordInOperand(0)))) { + return false; + } + } + // The value needs to be available at the insertion point. return fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, message_.value_id()); @@ -109,20 +198,43 @@ bool TransformationStore::IsApplicable( void TransformationStore::Apply(opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - auto new_instruction = MakeUnique( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.value_id()}}})); - auto new_instruction_ptr = new_instruction.get(); - insert_before->InsertBefore(std::move(new_instruction)); - // Inform the def-use manager about the new instruction and record its basic - // block. - ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); - ir_context->set_instr_block(new_instruction_ptr, - ir_context->get_instr_block(insert_before)); + if (message_.is_atomic()) { + // OpAtomicStore instruction. + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + auto new_instruction = MakeUnique( + ir_context, SpvOpAtomicStore, 0, 0, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, + {SPV_OPERAND_TYPE_SCOPE_ID, {message_.memory_scope_id()}}, + {SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID, + {message_.memory_semantics_id()}}, + {SPV_OPERAND_TYPE_ID, {message_.value_id()}}})); + auto new_instruction_ptr = new_instruction.get(); + insert_before->InsertBefore(std::move(new_instruction)); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); + + } else { + // OpStore instruction. + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + auto new_instruction = MakeUnique( + ir_context, SpvOpStore, 0, 0, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, + {SPV_OPERAND_TYPE_ID, {message_.value_id()}}})); + auto new_instruction_ptr = new_instruction.get(); + insert_before->InsertBefore(std::move(new_instruction)); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); + } } protobufs::Transformation TransformationStore::ToMessage() const { diff --git a/third_party/spirv-tools/source/fuzz/transformation_store.h b/third_party/spirv-tools/source/fuzz/transformation_store.h index 18ba1d7d22..638713bb77 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_store.h +++ b/third_party/spirv-tools/source/fuzz/transformation_store.h @@ -28,12 +28,21 @@ class TransformationStore : public Transformation { explicit TransformationStore(protobufs::TransformationStore message); TransformationStore( - uint32_t pointer_id, uint32_t value_id, + uint32_t pointer_id, bool is_atomic, uint32_t memory_scope, + uint32_t memory_semantics, uint32_t value_id, const protobufs::InstructionDescriptor& instruction_to_insert_before); // - |message_.pointer_id| must be the id of a pointer // - The pointer type must not have read-only storage class // - The pointer must not be OpConstantNull or OpUndef + // - |message_.is_atomic| must be true if want to work with OpAtomicStore. + // - If |is_atomic| is true then |message_memory_scope_id| must be the id of + // an OpConstant 32 bit integer instruction with the value + // SpvScopeInvocation. + // - If |is_atomic| is true then |message_.memory_semantics_id| must be the id + // of an OpConstant 32 bit integer instruction with the values + // SpvMemorySemanticsWorkgroupMemoryMask or + // SpvMemorySemanticsUniformMemoryMask. // - |message_.value_id| must be an instruction result id that has the same // type as the pointee type of |message_.pointer_id| // - |message_.instruction_to_insert_before| must identify an instruction diff --git a/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp b/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp index ac0e3ccba2..742a2c8056 100644 --- a/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp +++ b/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp @@ -204,7 +204,7 @@ void TransformationVectorShuffle::AddDataSynonymFacts( // Check that the first vector can participate in data synonym facts. if (!fuzzerutil::CanMakeSynonymOf( ir_context, *transformation_context, - ir_context->get_def_use_mgr()->GetDef(message_.vector1()))) { + *ir_context->get_def_use_mgr()->GetDef(message_.vector1()))) { continue; } descriptor_for_source_component = @@ -213,7 +213,7 @@ void TransformationVectorShuffle::AddDataSynonymFacts( // Check that the second vector can participate in data synonym facts. if (!fuzzerutil::CanMakeSynonymOf( ir_context, *transformation_context, - ir_context->get_def_use_mgr()->GetDef(message_.vector2()))) { + *ir_context->get_def_use_mgr()->GetDef(message_.vector2()))) { continue; } auto index_into_vector_2 = diff --git a/third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.cpp b/third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.cpp new file mode 100644 index 0000000000..490bcd7827 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.cpp @@ -0,0 +1,200 @@ +// Copyright (c) 2021 Shiyu Liu +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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_wrap_vector_synonym.h" + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/opt/instruction.h" + +namespace spvtools { +namespace fuzz { + +TransformationWrapVectorSynonym::TransformationWrapVectorSynonym( + protobufs::TransformationWrapVectorSynonym message) + : message_(std::move(message)) {} + +TransformationWrapVectorSynonym::TransformationWrapVectorSynonym( + uint32_t instruction_id, uint32_t vector_operand1, uint32_t vector_operand2, + uint32_t fresh_id, uint32_t pos) { + message_.set_instruction_id(instruction_id); + message_.set_vector_operand1(vector_operand1); + message_.set_vector_operand2(vector_operand2); + message_.set_fresh_id(fresh_id); + message_.set_scalar_position(pos); +} + +bool TransformationWrapVectorSynonym::IsApplicable( + opt::IRContext* ir_context, + const TransformationContext& transformation_context) const { + // |fresh_id| must be fresh. + if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { + return false; + } + + const opt::Instruction* instruction = + ir_context->get_def_use_mgr()->GetDef(message_.instruction_id()); + + // |instruction_id| must refer to an existing instruction. + if (instruction == nullptr) { + return false; + } + + if (!IsInstructionSupported(ir_context, *instruction)) { + return false; + } + + // It must be possible to make a synonym of the result id of the scalar + // operation + if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, + *instruction)) { + return false; + } + + // |vector_operand1| and |vector_operand2| must exist. + auto vec1 = ir_context->get_def_use_mgr()->GetDef(message_.vector_operand1()); + auto vec2 = ir_context->get_def_use_mgr()->GetDef(message_.vector_operand2()); + + if (vec1 == nullptr || vec2 == nullptr) { + return false; + } + + // The 2 vectors must have compatible vector types. + auto vec1_type_id = vec1->type_id(); + auto vec2_type_id = vec2->type_id(); + + for (auto operand_index : {0, 1}) { + if (!fuzzerutil::TypesAreCompatible(ir_context, instruction->opcode(), + operand_index, vec1_type_id, + vec2_type_id)) { + return false; + } + } + + auto vec1_type = ir_context->get_def_use_mgr()->GetDef(vec1_type_id); + if (vec1_type->opcode() != SpvOpTypeVector) { + return false; + } + + // A suitable vector for the result type of the new vector instruction must + // exist in the module. This is a vector of the right length, whose element + // type matches the result type of the scalar instruction. + uint32_t vector_size = vec1_type->GetSingleWordInOperand(1); + if (!fuzzerutil::MaybeGetVectorType(ir_context, instruction->type_id(), + vector_size)) { + return false; + } + + // |scalar_position| needs to be a non-negative integer less than the vector + // length. + // OpTypeVector instruction has the component count at index 2. + if (message_.scalar_position() >= ir_context->get_def_use_mgr() + ->GetDef(vec1_type_id) + ->GetSingleWordInOperand(1)) { + return false; + } + + if (!transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(message_.vector_operand1(), + {message_.scalar_position()}), + MakeDataDescriptor(instruction->GetSingleWordInOperand(0), {}))) { + return false; + } + + if (!transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(message_.vector_operand2(), + {message_.scalar_position()}), + MakeDataDescriptor(instruction->GetSingleWordInOperand(1), {}))) { + return false; + } + + return true; +} + +void TransformationWrapVectorSynonym::Apply( + opt::IRContext* ir_context, + TransformationContext* transformation_context) const { + // Create an instruction descriptor for the original instruction. + auto instruction = + ir_context->get_def_use_mgr()->GetDef(message_.instruction_id()); + auto destination_block = ir_context->get_instr_block(instruction); + + // Populate input operand list with two vectors for vector operation. + opt::Instruction::OperandList in_operands; + in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.vector_operand1()}}); + in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.vector_operand2()}}); + + // Make a new arithmetic instruction: %fresh_id = OpXX %type_id %result_id1 + // %result_id2. + auto vector_operand_type = ir_context->get_def_use_mgr()->GetDef( + fuzzerutil::GetTypeId(ir_context, message_.vector_operand1())); + uint32_t vector_size = vector_operand_type->GetSingleWordInOperand(1); + auto vec_type_id = fuzzerutil::MaybeGetVectorType( + ir_context, instruction->type_id(), vector_size); + auto new_instruction = MakeUnique( + ir_context, instruction->opcode(), vec_type_id, message_.fresh_id(), + std::move(in_operands)); + auto new_instruction_ptr = new_instruction.get(); + instruction->InsertBefore(std::move(new_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, destination_block); + + // Add |fresh_id| to id bound. + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + + // Add synonyms between |fresh_id| and |instruction_id|. + transformation_context->GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(message_.fresh_id(), {message_.scalar_position()}), + MakeDataDescriptor(message_.instruction_id(), {})); +} + +protobufs::Transformation TransformationWrapVectorSynonym::ToMessage() const { + protobufs::Transformation result; + *result.mutable_wrap_vector_synonym() = message_; + return result; +} + +std::unordered_set TransformationWrapVectorSynonym::GetFreshIds() + const { + return std::unordered_set{message_.fresh_id()}; +} + +bool TransformationWrapVectorSynonym::IsInstructionSupported( + opt::IRContext* ir_context, const opt::Instruction& instruction) { + if (!instruction.result_id() || !instruction.type_id()) { + return false; + } + auto type_instruction = + ir_context->get_def_use_mgr()->GetDef(instruction.type_id()); + + if ((type_instruction->opcode() != SpvOpTypeInt && + type_instruction->opcode() != SpvOpTypeFloat)) { + return false; + } + + switch (instruction.opcode()) { + case SpvOpIAdd: + case SpvOpISub: + case SpvOpIMul: + case SpvOpFAdd: + case SpvOpFSub: + case SpvOpFMul: + return true; + default: + return false; + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.h b/third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.h new file mode 100644 index 0000000000..94437fe597 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.h @@ -0,0 +1,80 @@ +// Copyright (c) 2021 Shiyu Liu +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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_WRAP_VECTOR_SYNONYM_H_ +#define SOURCE_FUZZ_TRANSFORMATION_WRAP_VECTOR_SYNONYM_H_ + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/fuzz/transformation_context.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationWrapVectorSynonym : public Transformation { + public: + explicit TransformationWrapVectorSynonym( + protobufs::TransformationWrapVectorSynonym message); + + TransformationWrapVectorSynonym(uint32_t instruction_id, + uint32_t vector_operand1, + uint32_t vector_operand2, uint32_t fresh_id, + uint32_t pos); + // - |instruction_id| must be the id of a supported arithmetic operation + // and must be relevant. + // - |vector_operand1| and |vector_operand2| represents the result ids of the + // two vector operands. + // - |fresh_id| is an unused id that will be used as a result id of the + // created instruction. + // - |vector_operand1| and |vector_operand2| must have compatible vector types + // that are supported by this transformation. + // - |pos| is an index of the operands of |instruction_id| in the + // |vector_operand1| and |vector_operand2|. It must be less than the size + // of those vector operands. + // - A vector type with the same width as the types of the vector operands, + // and element type matching the type of |instruction_id|, must exist in the + // module. + bool IsApplicable( + opt::IRContext* ir_context, + const TransformationContext& transformation_context) const override; + + // Adds a new instruction before the |instruction_id| with |fresh_id| + // result id and |instruction_id|'s opcode. The added instruction has + // two operands: |vector_operand1| and |vector_operand2| and its type + // id is equal to the type ids of those operands. A new fact is added + // to the fact manager specifying that |fresh_id[pos]| is synonymous + // to |instruction_id|. + void Apply(opt::IRContext* ir_context, + TransformationContext* transformation_context) const override; + + std::unordered_set GetFreshIds() const override; + protobufs::Transformation ToMessage() const override; + + // Checks whether the instruction given is supported by the transformation. + // A valid instruction must: + // - has both result id and type id. + // - is a supported scalar operation instruction. + // - has a supported type that is either int or float. + static bool IsInstructionSupported(opt::IRContext* ir_context, + const opt::Instruction& instruction); + + private: + protobufs::TransformationWrapVectorSynonym message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_WRAP_VECTOR_SYNONYM_H_ diff --git a/third_party/spirv-tools/source/link/linker.cpp b/third_party/spirv-tools/source/link/linker.cpp index 8da4a98d88..c5ca5625d6 100644 --- a/third_party/spirv-tools/source/link/linker.cpp +++ b/third_party/spirv-tools/source/link/linker.cpp @@ -34,6 +34,7 @@ #include "source/opt/pass_manager.h" #include "source/opt/remove_duplicates_pass.h" #include "source/opt/type_manager.h" +#include "source/spirv_constant.h" #include "source/spirv_target_env.h" #include "source/util/make_unique.h" #include "spirv-tools/libspirv.hpp" @@ -207,7 +208,7 @@ spv_result_t GenerateHeader(const MessageConsumer& consumer, header->magic_number = SpvMagicNumber; header->version = version; - header->generator = 17u; + header->generator = SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_LINKER, 0); header->bound = max_id_bound; header->reserved = 0u; diff --git a/third_party/spirv-tools/source/lint/CMakeLists.txt b/third_party/spirv-tools/source/lint/CMakeLists.txt new file mode 100644 index 0000000000..1feae3f94d --- /dev/null +++ b/third_party/spirv-tools/source/lint/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (c) 2021 Google LLC. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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(SPIRV_TOOLS_LINT_SOURCES + divergence_analysis.h + lints.h + + linter.cpp + divergence_analysis.cpp + lint_divergent_derivatives.cpp +) + +if(MSVC AND (NOT ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))) + # Enable parallel builds across four cores for this lib. + add_definitions(/MP4) +endif() + +add_library(SPIRV-Tools-lint ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_TOOLS_LINT_SOURCES}) + +spvtools_default_compile_options(SPIRV-Tools-lint) +target_include_directories(SPIRV-Tools-lint + PUBLIC + $ + $ + $ + PRIVATE ${spirv-tools_BINARY_DIR} +) +# We need the assembling and disassembling functionalities in the main library. +target_link_libraries(SPIRV-Tools-lint + PUBLIC ${SPIRV_TOOLS_FULL_VISIBILITY}) +# We need the internals of spirv-opt. +target_link_libraries(SPIRV-Tools-lint + PUBLIC SPIRV-Tools-opt) + +set_property(TARGET SPIRV-Tools-lint PROPERTY FOLDER "SPIRV-Tools libraries") +spvtools_check_symbol_exports(SPIRV-Tools-lint) + +if(ENABLE_SPIRV_TOOLS_INSTALL) + install(TARGETS SPIRV-Tools-lint EXPORT SPIRV-Tools-lintTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + export(EXPORT SPIRV-Tools-lintTargets FILE SPIRV-Tools-lintTargets.cmake) + + spvtools_config_package_dir(SPIRV-Tools-lint PACKAGE_DIR) + install(EXPORT SPIRV-Tools-lintTargets FILE SPIRV-Tools-lintTargets.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-lint) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-lintConfig.cmake DESTINATION ${PACKAGE_DIR}) +endif(ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/third_party/spirv-tools/source/lint/divergence_analysis.cpp b/third_party/spirv-tools/source/lint/divergence_analysis.cpp new file mode 100644 index 0000000000..b5a72b459d --- /dev/null +++ b/third_party/spirv-tools/source/lint/divergence_analysis.cpp @@ -0,0 +1,245 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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/lint/divergence_analysis.h" + +#include "source/opt/basic_block.h" +#include "source/opt/control_dependence.h" +#include "source/opt/dataflow.h" +#include "source/opt/function.h" +#include "source/opt/instruction.h" +#include "spirv/unified1/spirv.h" + +namespace spvtools { +namespace lint { + +void DivergenceAnalysis::EnqueueSuccessors(opt::Instruction* inst) { + // Enqueue control dependents of block, if applicable. + // There are two ways for a dependence source to be updated: + // 1. control -> control: source block is marked divergent. + // 2. data -> control: branch condition is marked divergent. + uint32_t block_id; + if (inst->IsBlockTerminator()) { + block_id = context().get_instr_block(inst)->id(); + } else if (inst->opcode() == SpvOpLabel) { + block_id = inst->result_id(); + opt::BasicBlock* bb = context().cfg()->block(block_id); + // Only enqueue phi instructions, as other uses don't affect divergence. + bb->ForEachPhiInst([this](opt::Instruction* phi) { Enqueue(phi); }); + } else { + opt::ForwardDataFlowAnalysis::EnqueueUsers(inst); + return; + } + if (!cd_.HasBlock(block_id)) { + return; + } + for (const spvtools::opt::ControlDependence& dep : + cd_.GetDependenceTargets(block_id)) { + opt::Instruction* target_inst = + context().cfg()->block(dep.target_bb_id())->GetLabelInst(); + Enqueue(target_inst); + } +} + +opt::DataFlowAnalysis::VisitResult DivergenceAnalysis::Visit( + opt::Instruction* inst) { + if (inst->opcode() == SpvOpLabel) { + return VisitBlock(inst->result_id()); + } else { + return VisitInstruction(inst); + } +} + +opt::DataFlowAnalysis::VisitResult DivergenceAnalysis::VisitBlock(uint32_t id) { + if (!cd_.HasBlock(id)) { + return opt::DataFlowAnalysis::VisitResult::kResultFixed; + } + DivergenceLevel& cur_level = divergence_[id]; + if (cur_level == DivergenceLevel::kDivergent) { + return opt::DataFlowAnalysis::VisitResult::kResultFixed; + } + DivergenceLevel orig = cur_level; + for (const spvtools::opt::ControlDependence& dep : + cd_.GetDependenceSources(id)) { + if (divergence_[dep.source_bb_id()] > cur_level) { + cur_level = divergence_[dep.source_bb_id()]; + divergence_source_[id] = dep.source_bb_id(); + } else if (dep.source_bb_id() != 0) { + uint32_t condition_id = dep.GetConditionID(*context().cfg()); + DivergenceLevel dep_level = divergence_[condition_id]; + // Check if we are along the chain of unconditional branches starting from + // the branch target. + if (follow_unconditional_branches_[dep.branch_target_bb_id()] != + follow_unconditional_branches_[dep.target_bb_id()]) { + // We must have reconverged in order to reach this block. + // Promote partially uniform to divergent. + if (dep_level == DivergenceLevel::kPartiallyUniform) { + dep_level = DivergenceLevel::kDivergent; + } + } + if (dep_level > cur_level) { + cur_level = dep_level; + divergence_source_[id] = condition_id; + divergence_dependence_source_[id] = dep.source_bb_id(); + } + } + } + return cur_level > orig ? VisitResult::kResultChanged + : VisitResult::kResultFixed; +} + +opt::DataFlowAnalysis::VisitResult DivergenceAnalysis::VisitInstruction( + opt::Instruction* inst) { + if (inst->IsBlockTerminator()) { + // This is called only when the condition has changed, so return changed. + return VisitResult::kResultChanged; + } + if (!inst->HasResultId()) { + return VisitResult::kResultFixed; + } + uint32_t id = inst->result_id(); + DivergenceLevel& cur_level = divergence_[id]; + if (cur_level == DivergenceLevel::kDivergent) { + return opt::DataFlowAnalysis::VisitResult::kResultFixed; + } + DivergenceLevel orig = cur_level; + cur_level = ComputeInstructionDivergence(inst); + return cur_level > orig ? VisitResult::kResultChanged + : VisitResult::kResultFixed; +} + +DivergenceAnalysis::DivergenceLevel +DivergenceAnalysis::ComputeInstructionDivergence(opt::Instruction* inst) { + // TODO(kuhar): Check to see if inst is decorated with Uniform or UniformId + // and use that to short circuit other checks. Uniform is for subgroups which + // would satisfy derivative groups too. UniformId takes a scope, so if it is + // subgroup or greater it could satisfy derivative group and + // Device/QueueFamily could satisfy fully uniform. + uint32_t id = inst->result_id(); + // Handle divergence roots. + if (inst->opcode() == SpvOpFunctionParameter) { + divergence_source_[id] = 0; + return divergence_[id] = DivergenceLevel::kDivergent; + } else if (inst->IsLoad()) { + spvtools::opt::Instruction* var = inst->GetBaseAddress(); + if (var->opcode() != SpvOpVariable) { + // Assume divergent. + divergence_source_[id] = 0; + return DivergenceLevel::kDivergent; + } + DivergenceLevel ret = ComputeVariableDivergence(var); + if (ret > DivergenceLevel::kUniform) { + divergence_source_[inst->result_id()] = 0; + } + return divergence_[id] = ret; + } + // Get the maximum divergence of the operands. + DivergenceLevel ret = DivergenceLevel::kUniform; + inst->ForEachInId([this, inst, &ret](const uint32_t* op) { + if (!op) return; + if (divergence_[*op] > ret) { + divergence_source_[inst->result_id()] = *op; + ret = divergence_[*op]; + } + }); + divergence_[inst->result_id()] = ret; + return ret; +} + +DivergenceAnalysis::DivergenceLevel +DivergenceAnalysis::ComputeVariableDivergence(opt::Instruction* var) { + uint32_t type_id = var->type_id(); + spvtools::opt::analysis::Pointer* type = + context().get_type_mgr()->GetType(type_id)->AsPointer(); + assert(type != nullptr); + uint32_t def_id = var->result_id(); + DivergenceLevel ret; + switch (type->storage_class()) { + case SpvStorageClassFunction: + case SpvStorageClassGeneric: + case SpvStorageClassAtomicCounter: + case SpvStorageClassStorageBuffer: + case SpvStorageClassPhysicalStorageBuffer: + case SpvStorageClassOutput: + case SpvStorageClassWorkgroup: + case SpvStorageClassImage: // Image atomics probably aren't uniform. + case SpvStorageClassPrivate: + ret = DivergenceLevel::kDivergent; + break; + case SpvStorageClassInput: + ret = DivergenceLevel::kDivergent; + // If this variable has a Flat decoration, it is partially uniform. + // TODO(kuhar): Track access chain indices and also consider Flat members + // of a structure. + context().get_decoration_mgr()->WhileEachDecoration( + def_id, SpvDecorationFlat, [&ret](const opt::Instruction&) { + ret = DivergenceLevel::kPartiallyUniform; + return false; + }); + break; + case SpvStorageClassUniformConstant: + // May be a storage image which is also written to; mark those as + // divergent. + if (!var->IsVulkanStorageImage() || var->IsReadOnlyPointer()) { + ret = DivergenceLevel::kUniform; + } else { + ret = DivergenceLevel::kDivergent; + } + break; + case SpvStorageClassUniform: + case SpvStorageClassPushConstant: + case SpvStorageClassCrossWorkgroup: // Not for shaders; default uniform. + default: + ret = DivergenceLevel::kUniform; + break; + } + return ret; +} + +void DivergenceAnalysis::Setup(opt::Function* function) { + // TODO(kuhar): Run functions called by |function| so we can detect + // reconvergence caused by multiple returns. + cd_.ComputeControlDependenceGraph( + *context().cfg(), *context().GetPostDominatorAnalysis(function)); + context().cfg()->ForEachBlockInPostOrder( + function->entry().get(), [this](const opt::BasicBlock* bb) { + uint32_t id = bb->id(); + if (bb->terminator() == nullptr || + bb->terminator()->opcode() != SpvOpBranch) { + follow_unconditional_branches_[id] = id; + } else { + uint32_t target_id = bb->terminator()->GetSingleWordInOperand(0); + // Target is guaranteed to have been visited before us in postorder. + follow_unconditional_branches_[id] = + follow_unconditional_branches_[target_id]; + } + }); +} + +std::ostream& operator<<(std::ostream& os, + DivergenceAnalysis::DivergenceLevel level) { + switch (level) { + case DivergenceAnalysis::DivergenceLevel::kUniform: + return os << "uniform"; + case DivergenceAnalysis::DivergenceLevel::kPartiallyUniform: + return os << "partially uniform"; + case DivergenceAnalysis::DivergenceLevel::kDivergent: + return os << "divergent"; + default: + return os << ""; + } +} + +} // namespace lint +} // namespace spvtools diff --git a/third_party/spirv-tools/source/lint/divergence_analysis.h b/third_party/spirv-tools/source/lint/divergence_analysis.h new file mode 100644 index 0000000000..4d595ec282 --- /dev/null +++ b/third_party/spirv-tools/source/lint/divergence_analysis.h @@ -0,0 +1,163 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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_LINT_DIVERGENCE_ANALYSIS_H_ +#define SOURCE_LINT_DIVERGENCE_ANALYSIS_H_ + +#include +#include +#include + +#include "source/opt/basic_block.h" +#include "source/opt/control_dependence.h" +#include "source/opt/dataflow.h" +#include "source/opt/function.h" +#include "source/opt/instruction.h" + +namespace spvtools { +namespace lint { + +// Computes the static divergence level for blocks (control flow) and values. +// +// A value is uniform if all threads that execute it are guaranteed to have the +// same value. Similarly, a value is partially uniform if this is true only +// within each derivative group. If neither apply, it is divergent. +// +// Control flow through a block is uniform if for any possible execution and +// point in time, all threads are executing it, or no threads are executing it. +// In particular, it is never possible for some threads to be inside the block +// and some threads not executing. +// TODO(kuhar): Clarify the difference between uniform, divergent, and +// partially-uniform execution in this analysis. +// +// Caveat: +// As we use control dependence to determine how divergence is propagated, this +// analysis can be overly permissive when the merge block for a conditional +// branch or switch is later than (strictly postdominates) the expected merge +// block, which is the immediate postdominator. However, this is not expected to +// be a problem in practice, given that SPIR-V is generally output by compilers +// and other automated tools, which would assign the earliest possible merge +// block, rather than written by hand. +// TODO(kuhar): Handle late merges. +class DivergenceAnalysis : public opt::ForwardDataFlowAnalysis { + public: + // The tightest (most uniform) level of divergence that can be determined + // statically for a value or control flow for a block. + // + // The values are ordered such that A > B means that A is potentially more + // divergent than B. + // TODO(kuhar): Rename |PartiallyUniform' to something less confusing. For + // example, the enum could be based on scopes. + enum class DivergenceLevel { + // The value or control flow is uniform across the entire invocation group. + kUniform = 0, + // The value or control flow is uniform across the derivative group, but not + // the invocation group. + kPartiallyUniform = 1, + // The value or control flow is not statically uniform. + kDivergent = 2, + }; + + DivergenceAnalysis(opt::IRContext& context) + : ForwardDataFlowAnalysis(context, LabelPosition::kLabelsAtEnd) {} + + // Returns the divergence level for the given value (non-label instructions), + // or control flow for the given block. + DivergenceLevel GetDivergenceLevel(uint32_t id) { + auto it = divergence_.find(id); + if (it == divergence_.end()) { + return DivergenceLevel::kUniform; + } + return it->second; + } + + // Returns the divergence source for the given id. The following types of + // divergence flows from A to B are possible: + // + // data -> data: A is used as an operand in the definition of B. + // data -> control: B is control-dependent on a branch with condition A. + // control -> data: B is a OpPhi instruction in which A is a block operand. + // control -> control: B is control-dependent on A. + uint32_t GetDivergenceSource(uint32_t id) { + auto it = divergence_source_.find(id); + if (it == divergence_source_.end()) { + return 0; + } + return it->second; + } + + // Returns the dependence source for the control dependence for the given id. + // This only exists for data -> control edges. + // + // In other words, if block 2 is dependent on block 1 due to value 3 (e.g. + // block 1 terminates with OpBranchConditional %3 %2 %4): + // * GetDivergenceSource(2) = 3 + // * GetDivergenceDependenceSource(2) = 1 + // + // Returns 0 if not applicable. + uint32_t GetDivergenceDependenceSource(uint32_t id) { + auto it = divergence_dependence_source_.find(id); + if (it == divergence_dependence_source_.end()) { + return 0; + } + return it->second; + } + + void InitializeWorklist(opt::Function* function, + bool is_first_iteration) override { + // Since |EnqueueSuccessors| is complete, we only need one pass. + if (is_first_iteration) { + Setup(function); + opt::ForwardDataFlowAnalysis::InitializeWorklist(function, true); + } + } + + void EnqueueSuccessors(opt::Instruction* inst) override; + + VisitResult Visit(opt::Instruction* inst) override; + + private: + VisitResult VisitBlock(uint32_t id); + VisitResult VisitInstruction(opt::Instruction* inst); + + // Computes the divergence level for the result of the given instruction + // based on the current state of the analysis. This is always an + // underapproximation, which will be improved as the analysis proceeds. + DivergenceLevel ComputeInstructionDivergence(opt::Instruction* inst); + + // Computes the divergence level for a variable, which is used for loads. + DivergenceLevel ComputeVariableDivergence(opt::Instruction* var); + + // Initializes data structures for performing dataflow on the given function. + void Setup(opt::Function* function); + + std::unordered_map divergence_; + std::unordered_map divergence_source_; + std::unordered_map divergence_dependence_source_; + + // Stores the result of following unconditional branches starting from the + // given block. This is used to detect when reconvergence needs to be + // accounted for. + std::unordered_map follow_unconditional_branches_; + + opt::ControlDependenceAnalysis cd_; +}; + +std::ostream& operator<<(std::ostream& os, + DivergenceAnalysis::DivergenceLevel level); + +} // namespace lint +} // namespace spvtools + +#endif // SOURCE_LINT_DIVERGENCE_ANALYSIS_H_ diff --git a/third_party/spirv-tools/source/lint/lint_divergent_derivatives.cpp b/third_party/spirv-tools/source/lint/lint_divergent_derivatives.cpp new file mode 100644 index 0000000000..512847b0ce --- /dev/null +++ b/third_party/spirv-tools/source/lint/lint_divergent_derivatives.cpp @@ -0,0 +1,169 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 "source/diagnostic.h" +#include "source/lint/divergence_analysis.h" +#include "source/lint/lints.h" +#include "source/opt/basic_block.h" +#include "source/opt/cfg.h" +#include "source/opt/control_dependence.h" +#include "source/opt/def_use_manager.h" +#include "source/opt/dominator_analysis.h" +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" +#include "spirv-tools/libspirv.h" +#include "spirv/unified1/spirv.h" + +namespace spvtools { +namespace lint { +namespace lints { +namespace { +// Returns the %name[id], where `name` is the first name associated with the +// given id, or just %id if one is not found. +std::string GetFriendlyName(opt::IRContext* context, uint32_t id) { + auto names = context->GetNames(id); + std::stringstream ss; + ss << "%"; + if (names.empty()) { + ss << id; + } else { + opt::Instruction* inst_name = names.begin()->second; + if (inst_name->opcode() == SpvOpName) { + ss << names.begin()->second->GetInOperand(0).AsString(); + ss << "[" << id << "]"; + } else { + ss << id; + } + } + return ss.str(); +} + +bool InstructionHasDerivative(const opt::Instruction& inst) { + static const SpvOp derivative_opcodes[] = { + // Implicit derivatives. + SpvOpImageSampleImplicitLod, + SpvOpImageSampleDrefImplicitLod, + SpvOpImageSampleProjImplicitLod, + SpvOpImageSampleProjDrefImplicitLod, + SpvOpImageSparseSampleImplicitLod, + SpvOpImageSparseSampleDrefImplicitLod, + SpvOpImageSparseSampleProjImplicitLod, + SpvOpImageSparseSampleProjDrefImplicitLod, + // Explicit derivatives. + SpvOpDPdx, + SpvOpDPdy, + SpvOpFwidth, + SpvOpDPdxFine, + SpvOpDPdyFine, + SpvOpFwidthFine, + SpvOpDPdxCoarse, + SpvOpDPdyCoarse, + SpvOpFwidthCoarse, + }; + return std::find(std::begin(derivative_opcodes), std::end(derivative_opcodes), + inst.opcode()) != std::end(derivative_opcodes); +} + +spvtools::DiagnosticStream Warn(opt::IRContext* context, + opt::Instruction* inst) { + if (inst == nullptr) { + return DiagnosticStream({0, 0, 0}, context->consumer(), "", SPV_WARNING); + } else { + // TODO(kuhar): Use line numbers based on debug info. + return DiagnosticStream( + {0, 0, 0}, context->consumer(), + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES), + SPV_WARNING); + } +} + +void PrintDivergenceFlow(opt::IRContext* context, DivergenceAnalysis div, + uint32_t id) { + opt::analysis::DefUseManager* def_use = context->get_def_use_mgr(); + opt::CFG* cfg = context->cfg(); + while (id != 0) { + bool is_block = def_use->GetDef(id)->opcode() == SpvOpLabel; + if (is_block) { + Warn(context, nullptr) + << "block " << GetFriendlyName(context, id) << " is divergent"; + uint32_t source = div.GetDivergenceSource(id); + // Skip intermediate blocks. + while (source != 0 && def_use->GetDef(source)->opcode() == SpvOpLabel) { + id = source; + source = div.GetDivergenceSource(id); + } + if (source == 0) break; + spvtools::opt::Instruction* branch = + cfg->block(div.GetDivergenceDependenceSource(id))->terminator(); + Warn(context, branch) + << "because it depends on a conditional branch on divergent value " + << GetFriendlyName(context, source) << ""; + id = source; + } else { + Warn(context, nullptr) + << "value " << GetFriendlyName(context, id) << " is divergent"; + uint32_t source = div.GetDivergenceSource(id); + opt::Instruction* def = def_use->GetDef(id); + opt::Instruction* source_def = + source == 0 ? nullptr : def_use->GetDef(source); + // First print data -> data dependencies. + while (source != 0 && source_def->opcode() != SpvOpLabel) { + Warn(context, def_use->GetDef(id)) + << "because " << GetFriendlyName(context, id) << " uses value " + << GetFriendlyName(context, source) + << "in its definition, which is divergent"; + id = source; + def = source_def; + source = div.GetDivergenceSource(id); + source_def = def_use->GetDef(source); + } + if (source == 0) { + Warn(context, def) << "because it has a divergent definition"; + break; + } + Warn(context, def) << "because it is conditionally set in block " + << GetFriendlyName(context, source); + id = source; + } + } +} +} // namespace + +bool CheckDivergentDerivatives(opt::IRContext* context) { + DivergenceAnalysis div(*context); + for (opt::Function& func : *context->module()) { + div.Run(&func); + for (const opt::BasicBlock& bb : func) { + for (const opt::Instruction& inst : bb) { + if (InstructionHasDerivative(inst) && + div.GetDivergenceLevel(bb.id()) > + DivergenceAnalysis::DivergenceLevel::kPartiallyUniform) { + Warn(context, nullptr) + << "derivative with divergent control flow" + << " located in block " << GetFriendlyName(context, bb.id()); + PrintDivergenceFlow(context, div, bb.id()); + } + } + } + } + return true; +} + +} // namespace lints +} // namespace lint +} // namespace spvtools diff --git a/third_party/spirv-tools/source/lint/linter.cpp b/third_party/spirv-tools/source/lint/linter.cpp new file mode 100644 index 0000000000..e4ed04ea44 --- /dev/null +++ b/third_party/spirv-tools/source/lint/linter.cpp @@ -0,0 +1,60 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "spirv-tools/linter.hpp" + +#include "source/lint/lints.h" +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "spirv-tools/libspirv.h" +#include "spirv-tools/libspirv.hpp" +#include "spirv/unified1/spirv.h" + +namespace spvtools { + +struct Linter::Impl { + explicit Impl(spv_target_env env) : target_env(env) { + message_consumer = [](spv_message_level_t /*level*/, const char* /*source*/, + const spv_position_t& /*position*/, + const char* /*message*/) {}; + } + + spv_target_env target_env; // Target environment. + MessageConsumer message_consumer; // Message consumer. +}; + +Linter::Linter(spv_target_env env) : impl_(new Impl(env)) {} + +Linter::~Linter() {} + +void Linter::SetMessageConsumer(MessageConsumer consumer) { + impl_->message_consumer = std::move(consumer); +} + +const MessageConsumer& Linter::Consumer() const { + return impl_->message_consumer; +} + +bool Linter::Run(const uint32_t* binary, size_t binary_size) { + std::unique_ptr context = + BuildModule(SPV_ENV_VULKAN_1_2, Consumer(), binary, binary_size); + if (context == nullptr) return false; + + bool result = true; + result &= lint::lints::CheckDivergentDerivatives(context.get()); + + return result; +} + +} // namespace spvtools diff --git a/third_party/spirv-tools/source/lint/lints.h b/third_party/spirv-tools/source/lint/lints.h new file mode 100644 index 0000000000..a1995d2fb7 --- /dev/null +++ b/third_party/spirv-tools/source/lint/lints.h @@ -0,0 +1,34 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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_LINT_LINTS_H_ +#define SOURCE_LINT_LINTS_H_ + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace lint { + +// All of the functions in this namespace output to the error consumer in the +// |context| argument and return |true| if no errors are found. They do not +// modify the IR. +namespace lints { + +bool CheckDivergentDerivatives(opt::IRContext* context); + +} // namespace lints +} // namespace lint +} // namespace spvtools + +#endif // SOURCE_LINT_LINTS_H_ diff --git a/third_party/spirv-tools/source/operand.cpp b/third_party/spirv-tools/source/operand.cpp index c00c9b64ed..6d83e81e2f 100644 --- a/third_party/spirv-tools/source/operand.cpp +++ b/third_party/spirv-tools/source/operand.cpp @@ -578,6 +578,12 @@ std::function spvOperandCanBeForwardDeclaredFunction( std::function spvDbgInfoExtOperandCanBeForwardDeclaredFunction( spv_ext_inst_type_t ext_type, uint32_t key) { + // The Vulkan debug info extended instruction set is non-semantic so allows no + // forward references ever + if (ext_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { + return [](unsigned) { return false; }; + } + // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/532): Forward // references for debug info instructions are still in discussion. We must // update the following lines of code when we conclude the spec. diff --git a/third_party/spirv-tools/source/opt/CMakeLists.txt b/third_party/spirv-tools/source/opt/CMakeLists.txt index 0e41b20581..7d522fb5e6 100644 --- a/third_party/spirv-tools/source/opt/CMakeLists.txt +++ b/third_party/spirv-tools/source/opt/CMakeLists.txt @@ -27,8 +27,11 @@ set(SPIRV_TOOLS_OPT_SOURCES composite.h const_folding_rules.h constants.h + control_dependence.h + convert_to_sampled_image_pass.h convert_to_half_pass.h copy_prop_arrays.h + dataflow.h dead_branch_elim_pass.h dead_insert_elim_pass.h dead_variable_elimination.h @@ -36,6 +39,7 @@ set(SPIRV_TOOLS_OPT_SOURCES debug_info_manager.h def_use_manager.h desc_sroa.h + desc_sroa_util.h dominator_analysis.h dominator_tree.h eliminate_dead_constant_pass.h @@ -97,6 +101,7 @@ set(SPIRV_TOOLS_OPT_SOURCES relax_float_ops_pass.h remove_duplicates_pass.h remove_unused_interface_variables_pass.h + replace_desc_array_access_using_var_index.h replace_invalid_opc.h scalar_analysis.h scalar_analysis_nodes.h @@ -133,8 +138,11 @@ set(SPIRV_TOOLS_OPT_SOURCES composite.cpp const_folding_rules.cpp constants.cpp + control_dependence.cpp + convert_to_sampled_image_pass.cpp convert_to_half_pass.cpp copy_prop_arrays.cpp + dataflow.cpp dead_branch_elim_pass.cpp dead_insert_elim_pass.cpp dead_variable_elimination.cpp @@ -142,6 +150,7 @@ set(SPIRV_TOOLS_OPT_SOURCES debug_info_manager.cpp def_use_manager.cpp desc_sroa.cpp + desc_sroa_util.cpp dominator_analysis.cpp dominator_tree.cpp eliminate_dead_constant_pass.cpp @@ -199,6 +208,7 @@ set(SPIRV_TOOLS_OPT_SOURCES relax_float_ops_pass.cpp remove_duplicates_pass.cpp remove_unused_interface_variables_pass.cpp + replace_desc_array_access_using_var_index.cpp replace_invalid_opc.cpp scalar_analysis.cpp scalar_analysis_simplification.cpp diff --git a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp index 7cffff5700..0b54d5e85a 100644 --- a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG Inc. -// Copyright (c) 2018 Google LLC +// Copyright (c) 2018-2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ #include "source/cfa.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/opt/eliminate_dead_functions_util.h" +#include "source/opt/ir_builder.h" #include "source/opt/iterator.h" #include "source/opt/reflect.h" #include "source/spirv_constant.h" @@ -35,10 +36,10 @@ namespace { const uint32_t kTypePointerStorageClassInIdx = 0; const uint32_t kEntryPointFunctionIdInIdx = 1; const uint32_t kSelectionMergeMergeBlockIdInIdx = 0; -const uint32_t kLoopMergeMergeBlockIdInIdx = 0; const uint32_t kLoopMergeContinueBlockIdInIdx = 1; const uint32_t kCopyMemoryTargetAddrInIdx = 0; const uint32_t kCopyMemorySourceAddrInIdx = 1; +const uint32_t kLoadSourceAddrInIdx = 0; const uint32_t kDebugDeclareOperandVariableIndex = 5; const uint32_t kGlobalVariableVariableIndex = 12; @@ -96,16 +97,21 @@ bool AggressiveDCEPass::IsVarOfStorage(uint32_t varId, uint32_t storageClass) { storageClass; } -bool AggressiveDCEPass::IsLocalVar(uint32_t varId) { +bool AggressiveDCEPass::IsLocalVar(uint32_t varId, Function* func) { if (IsVarOfStorage(varId, SpvStorageClassFunction)) { return true; } - if (!private_like_local_) { + + if (!IsVarOfStorage(varId, SpvStorageClassPrivate) && + !IsVarOfStorage(varId, SpvStorageClassWorkgroup)) { return false; } - return IsVarOfStorage(varId, SpvStorageClassPrivate) || - IsVarOfStorage(varId, SpvStorageClassWorkgroup); + // For a variable in the Private or WorkGroup storage class, the variable will + // get a new instance for every call to an entry point. If the entry point + // does not have a call, then no other function can read or write to that + // instance of the variable. + return IsEntryPointWithNoCalls(func); } void AggressiveDCEPass::AddStores(Function* func, uint32_t ptrId) { @@ -145,15 +151,19 @@ bool AggressiveDCEPass::AllExtensionsSupported() const { if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } - return true; -} - -bool AggressiveDCEPass::IsDead(Instruction* inst) { - if (IsLive(inst)) return false; - if ((inst->IsBranch() || inst->opcode() == SpvOpUnreachable) && - !IsStructuredHeader(context()->get_instr_block(inst), nullptr, nullptr, - nullptr)) - return false; + // Only allow NonSemantic.Shader.DebugInfo.100, we cannot safely optimise + // around unknown extended instruction sets even if they are non-semantic + for (auto& inst : context()->module()->ext_inst_imports()) { + assert(inst.opcode() == SpvOpExtInstImport && + "Expecting an import of an extension's instruction set."); + const char* extension_name = + reinterpret_cast(&inst.GetInOperand(0).words[0]); + if (0 == std::strncmp(extension_name, "NonSemantic.", 12) && + 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100", + 32)) { + return false; + } + } return true; } @@ -173,12 +183,12 @@ bool AggressiveDCEPass::IsTargetDead(Instruction* inst) { }); return dead; } - return IsDead(tInst); + return !IsLive(tInst); } void AggressiveDCEPass::ProcessLoad(Function* func, uint32_t varId) { // Only process locals - if (!IsLocalVar(varId)) return; + if (!IsLocalVar(varId, func)) return; // Return if already processed if (live_local_vars_.find(varId) != live_local_vars_.end()) return; // Mark all stores to varId as live @@ -187,66 +197,6 @@ void AggressiveDCEPass::ProcessLoad(Function* func, uint32_t varId) { live_local_vars_.insert(varId); } -bool AggressiveDCEPass::IsStructuredHeader(BasicBlock* bp, - Instruction** mergeInst, - Instruction** branchInst, - uint32_t* mergeBlockId) { - if (!bp) return false; - Instruction* mi = bp->GetMergeInst(); - if (mi == nullptr) return false; - Instruction* bri = &*bp->tail(); - if (branchInst != nullptr) *branchInst = bri; - if (mergeInst != nullptr) *mergeInst = mi; - if (mergeBlockId != nullptr) *mergeBlockId = mi->GetSingleWordInOperand(0); - return true; -} - -void AggressiveDCEPass::ComputeBlock2HeaderMaps( - std::list& structuredOrder) { - block2headerBranch_.clear(); - header2nextHeaderBranch_.clear(); - branch2merge_.clear(); - structured_order_index_.clear(); - std::stack currentHeaderBranch; - currentHeaderBranch.push(nullptr); - uint32_t currentMergeBlockId = 0; - uint32_t index = 0; - for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); - ++bi, ++index) { - structured_order_index_[*bi] = index; - // If this block is the merge block of the current control construct, - // we are leaving the current construct so we must update state - if ((*bi)->id() == currentMergeBlockId) { - currentHeaderBranch.pop(); - Instruction* chb = currentHeaderBranch.top(); - if (chb != nullptr) - currentMergeBlockId = branch2merge_[chb]->GetSingleWordInOperand(0); - } - Instruction* mergeInst; - Instruction* branchInst; - uint32_t mergeBlockId; - bool is_header = - IsStructuredHeader(*bi, &mergeInst, &branchInst, &mergeBlockId); - // Map header block to next enclosing header. - if (is_header) header2nextHeaderBranch_[*bi] = currentHeaderBranch.top(); - // If this is a loop header, update state first so the block will map to - // itself. - if (is_header && mergeInst->opcode() == SpvOpLoopMerge) { - currentHeaderBranch.push(branchInst); - branch2merge_[branchInst] = mergeInst; - currentMergeBlockId = mergeBlockId; - } - // Map the block to the current construct. - block2headerBranch_[*bi] = currentHeaderBranch.top(); - // If this is an if header, update state so following blocks map to the if. - if (is_header && mergeInst->opcode() == SpvOpSelectionMerge) { - currentHeaderBranch.push(branchInst); - branch2merge_[branchInst] = mergeInst; - currentMergeBlockId = mergeBlockId; - } - } -} - void AggressiveDCEPass::AddBranch(uint32_t labelId, BasicBlock* bp) { std::unique_ptr newBranch( new Instruction(context(), SpvOpBranch, 0, 0, @@ -262,23 +212,18 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist( mergeInst->opcode() == SpvOpLoopMerge); BasicBlock* header = context()->get_instr_block(mergeInst); - uint32_t headerIndex = structured_order_index_[header]; const uint32_t mergeId = mergeInst->GetSingleWordInOperand(0); - BasicBlock* merge = context()->get_instr_block(mergeId); - uint32_t mergeIndex = structured_order_index_[merge]; - get_def_use_mgr()->ForEachUser( - mergeId, [headerIndex, mergeIndex, this](Instruction* user) { - if (!user->IsBranch()) return; - BasicBlock* block = context()->get_instr_block(user); - uint32_t index = structured_order_index_[block]; - if (headerIndex < index && index < mergeIndex) { - // This is a break from the loop. - AddToWorklist(user); - // Add branch's merge if there is one. - Instruction* userMerge = branch2merge_[user]; - if (userMerge != nullptr) AddToWorklist(userMerge); - } - }); + get_def_use_mgr()->ForEachUser(mergeId, [header, this](Instruction* user) { + if (!user->IsBranch()) return; + BasicBlock* block = context()->get_instr_block(user); + if (BlockIsInConstruct(header, block)) { + // This is a break from the loop. + AddToWorklist(user); + // Add branch's merge if there is one. + Instruction* userMerge = GetMergeInstruction(user); + if (userMerge != nullptr) AddToWorklist(userMerge); + } + }); if (mergeInst->opcode() != SpvOpLoopMerge) { return; @@ -292,7 +237,7 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist( if (op == SpvOpBranchConditional || op == SpvOpSwitch) { // A conditional branch or switch can only be a continue if it does not // have a merge instruction or its merge block is not the continue block. - Instruction* hdrMerge = branch2merge_[user]; + Instruction* hdrMerge = GetMergeInstruction(user); if (hdrMerge != nullptr && hdrMerge->opcode() == SpvOpSelectionMerge) { uint32_t hdrMergeId = hdrMerge->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx); @@ -304,9 +249,9 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist( // An unconditional branch can only be a continue if it is not // branching to its own merge block. BasicBlock* blk = context()->get_instr_block(user); - Instruction* hdrBranch = block2headerBranch_[blk]; + Instruction* hdrBranch = GetHeaderBranch(blk); if (hdrBranch == nullptr) return; - Instruction* hdrMerge = branch2merge_[hdrBranch]; + Instruction* hdrMerge = GetMergeInstruction(hdrBranch); if (hdrMerge->opcode() == SpvOpLoopMerge) return; uint32_t hdrMergeId = hdrMerge->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx); @@ -319,254 +264,36 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist( } bool AggressiveDCEPass::AggressiveDCE(Function* func) { - // Mark function parameters as live. - AddToWorklist(&func->DefInst()); - func->ForEachParam( - [this](const Instruction* param) { - AddToWorklist(const_cast(param)); - }, - false); - - // Compute map from block to controlling conditional branch - std::list structuredOrder; - cfg()->ComputeStructuredOrder(func, &*func->begin(), &structuredOrder); - ComputeBlock2HeaderMaps(structuredOrder); - bool modified = false; - // Add instructions with external side effects to worklist. Also add branches - // EXCEPT those immediately contained in an "if" selection construct or a loop - // or continue construct. - // TODO(greg-lunarg): Handle Frexp, Modf more optimally - call_in_func_ = false; - func_is_entry_point_ = false; - private_stores_.clear(); + std::list structured_order; + cfg()->ComputeStructuredOrder(func, &*func->begin(), &structured_order); live_local_vars_.clear(); - // Stacks to keep track of when we are inside an if- or loop-construct. - // When immediately inside an if- or loop-construct, we do not initially - // mark branches live. All other branches must be marked live. - std::stack assume_branches_live; - std::stack currentMergeBlockId; - // Push sentinel values on stack for when outside of any control flow. - assume_branches_live.push(true); - currentMergeBlockId.push(0); - for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) { - // If exiting if or loop, update stacks - if ((*bi)->id() == currentMergeBlockId.top()) { - assume_branches_live.pop(); - currentMergeBlockId.pop(); - } - for (auto ii = (*bi)->begin(); ii != (*bi)->end(); ++ii) { - SpvOp op = ii->opcode(); - switch (op) { - case SpvOpStore: { - uint32_t varId; - (void)GetPtr(&*ii, &varId); - // Mark stores as live if their variable is not function scope - // and is not private scope. Remember private stores for possible - // later inclusion. We cannot call IsLocalVar at this point because - // private_like_local_ has not been set yet. - if (IsVarOfStorage(varId, SpvStorageClassPrivate) || - IsVarOfStorage(varId, SpvStorageClassWorkgroup)) - private_stores_.push_back(&*ii); - else if (!IsVarOfStorage(varId, SpvStorageClassFunction)) - AddToWorklist(&*ii); - } break; - case SpvOpCopyMemory: - case SpvOpCopyMemorySized: { - uint32_t varId; - (void)GetPtr(ii->GetSingleWordInOperand(kCopyMemoryTargetAddrInIdx), - &varId); - if (IsVarOfStorage(varId, SpvStorageClassPrivate) || - IsVarOfStorage(varId, SpvStorageClassWorkgroup)) - private_stores_.push_back(&*ii); - else if (!IsVarOfStorage(varId, SpvStorageClassFunction)) - AddToWorklist(&*ii); - } break; - case SpvOpLoopMerge: { - assume_branches_live.push(false); - currentMergeBlockId.push( - ii->GetSingleWordInOperand(kLoopMergeMergeBlockIdInIdx)); - } break; - case SpvOpSelectionMerge: { - assume_branches_live.push(false); - currentMergeBlockId.push( - ii->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx)); - } break; - case SpvOpSwitch: - case SpvOpBranch: - case SpvOpBranchConditional: - case SpvOpUnreachable: { - if (assume_branches_live.top()) { - AddToWorklist(&*ii); - } - } break; - default: { - // Function calls, atomics, function params, function returns, etc. - // TODO(greg-lunarg): function calls live only if write to non-local - if (!ii->IsOpcodeSafeToDelete()) { - AddToWorklist(&*ii); - } - // Remember function calls - if (op == SpvOpFunctionCall) call_in_func_ = true; - } break; - } - } - } - // See if current function is an entry point - for (auto& ei : get_module()->entry_points()) { - if (ei.GetSingleWordInOperand(kEntryPointFunctionIdInIdx) == - func->result_id()) { - func_is_entry_point_ = true; - break; - } - } - // If the current function is an entry point and has no function calls, - // we can optimize private variables as locals - private_like_local_ = func_is_entry_point_ && !call_in_func_; - // If privates are not like local, add their stores to worklist - if (!private_like_local_) - for (auto& ps : private_stores_) AddToWorklist(ps); - // Perform closure on live instruction set. - while (!worklist_.empty()) { - Instruction* liveInst = worklist_.front(); - // Add all operand instructions if not already live - liveInst->ForEachInId([&liveInst, this](const uint32_t* iid) { - Instruction* inInst = get_def_use_mgr()->GetDef(*iid); - // Do not add label if an operand of a branch. This is not needed - // as part of live code discovery and can create false live code, - // for example, the branch to a header of a loop. - if (inInst->opcode() == SpvOpLabel && liveInst->IsBranch()) return; - AddToWorklist(inInst); - }); - if (liveInst->type_id() != 0) { - AddToWorklist(get_def_use_mgr()->GetDef(liveInst->type_id())); - } - // If in a structured if or loop construct, add the controlling - // conditional branch and its merge. - BasicBlock* blk = context()->get_instr_block(liveInst); - Instruction* branchInst = block2headerBranch_[blk]; - if (branchInst != nullptr) { - AddToWorklist(branchInst); - Instruction* mergeInst = branch2merge_[branchInst]; - AddToWorklist(mergeInst); - } - // If the block is a header, add the next outermost controlling - // conditional branch and its merge. - Instruction* nextBranchInst = header2nextHeaderBranch_[blk]; - if (nextBranchInst != nullptr) { - AddToWorklist(nextBranchInst); - Instruction* mergeInst = branch2merge_[nextBranchInst]; - AddToWorklist(mergeInst); - } - // If local load, add all variable's stores if variable not already live - if (liveInst->opcode() == SpvOpLoad || liveInst->IsAtomicWithLoad()) { - uint32_t varId; - (void)GetPtr(liveInst, &varId); - if (varId != 0) { - ProcessLoad(func, varId); - } - // Process memory copies like loads - } else if (liveInst->opcode() == SpvOpCopyMemory || - liveInst->opcode() == SpvOpCopyMemorySized) { - uint32_t varId; - (void)GetPtr(liveInst->GetSingleWordInOperand(kCopyMemorySourceAddrInIdx), - &varId); - if (varId != 0) { - ProcessLoad(func, varId); - } - // If DebugDeclare, process as load of variable - } else if (liveInst->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugDeclare) { - uint32_t varId = - liveInst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); - ProcessLoad(func, varId); - // If DebugValue with Deref, process as load of variable - } else if (liveInst->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugValue) { - uint32_t varId = context() - ->get_debug_info_mgr() - ->GetVariableIdOfDebugValueUsedForDeclare(liveInst); - if (varId != 0) ProcessLoad(func, varId); - // If merge, add other branches that are part of its control structure - } else if (liveInst->opcode() == SpvOpLoopMerge || - liveInst->opcode() == SpvOpSelectionMerge) { - AddBreaksAndContinuesToWorklist(liveInst); - // If function call, treat as if it loads from all pointer arguments - } else if (liveInst->opcode() == SpvOpFunctionCall) { - liveInst->ForEachInId([this, func](const uint32_t* iid) { - // Skip non-ptr args - if (!IsPtr(*iid)) return; - uint32_t varId; - (void)GetPtr(*iid, &varId); - ProcessLoad(func, varId); - }); - // If function parameter, treat as if it's result id is loaded from - } else if (liveInst->opcode() == SpvOpFunctionParameter) { - ProcessLoad(func, liveInst->result_id()); - // We treat an OpImageTexelPointer as a load of the pointer, and - // that value is manipulated to get the result. - } else if (liveInst->opcode() == SpvOpImageTexelPointer) { - uint32_t varId; - (void)GetPtr(liveInst, &varId); - if (varId != 0) { - ProcessLoad(func, varId); - } - } + InitializeWorkList(func, structured_order); + ProcessWorkList(func); + return KillDeadInstructions(func, structured_order); +} - // Add OpDecorateId instructions that apply to this instruction to the work - // list. We use the decoration manager to look through the group - // decorations to get to the OpDecorate* instructions themselves. - auto decorations = - get_decoration_mgr()->GetDecorationsFor(liveInst->result_id(), false); - for (Instruction* dec : decorations) { - // We only care about OpDecorateId instructions because the are the only - // decorations that will reference an id that will have to be kept live - // because of that use. - if (dec->opcode() != SpvOpDecorateId) { - continue; - } - if (dec->GetSingleWordInOperand(1) == - SpvDecorationHlslCounterBufferGOOGLE) { - // These decorations should not force the use id to be live. It will be - // removed if either the target or the in operand are dead. - continue; - } - AddToWorklist(dec); - } - - // Add DebugScope and DebugInlinedAt for |liveInst| to the work list. - if (liveInst->GetDebugScope().GetLexicalScope() != kNoDebugScope) { - auto* scope = get_def_use_mgr()->GetDef( - liveInst->GetDebugScope().GetLexicalScope()); - AddToWorklist(scope); - } - if (liveInst->GetDebugInlinedAt() != kNoInlinedAt) { - auto* inlined_at = - get_def_use_mgr()->GetDef(liveInst->GetDebugInlinedAt()); - AddToWorklist(inlined_at); - } - worklist_.pop(); - } - - // Kill dead instructions and remember dead blocks - for (auto bi = structuredOrder.begin(); bi != structuredOrder.end();) { - uint32_t mergeBlockId = 0; - (*bi)->ForEachInst([this, &modified, &mergeBlockId](Instruction* inst) { - if (!IsDead(inst)) return; +bool AggressiveDCEPass::KillDeadInstructions( + const Function* func, std::list& structured_order) { + bool modified = false; + for (auto bi = structured_order.begin(); bi != structured_order.end();) { + uint32_t merge_block_id = 0; + (*bi)->ForEachInst([this, &modified, &merge_block_id](Instruction* inst) { + if (IsLive(inst)) return; if (inst->opcode() == SpvOpLabel) return; // If dead instruction is selection merge, remember merge block // for new branch at end of block if (inst->opcode() == SpvOpSelectionMerge || inst->opcode() == SpvOpLoopMerge) - mergeBlockId = inst->GetSingleWordInOperand(0); + merge_block_id = inst->GetSingleWordInOperand(0); to_kill_.push_back(inst); modified = true; }); // If a structured if or loop was deleted, add a branch to its merge // block, and traverse to the merge block and continue processing there. // We know the block still exists because the label is not deleted. - if (mergeBlockId != 0) { - AddBranch(mergeBlockId, *bi); - for (++bi; (*bi)->id() != mergeBlockId; ++bi) { + if (merge_block_id != 0) { + AddBranch(merge_block_id, *bi); + for (++bi; (*bi)->id() != merge_block_id; ++bi) { } auto merge_terminator = (*bi)->terminator(); @@ -589,13 +316,252 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) { live_insts_.Set(merge_terminator->unique_id()); } } else { + Instruction* inst = (*bi)->terminator(); + if (!IsLive(inst)) { + // If the terminator is not live, this block has no live instructions, + // and it will be unreachable. + AddUnreachable(*bi); + } ++bi; } } - return modified; } +void AggressiveDCEPass::ProcessWorkList(Function* func) { + while (!worklist_.empty()) { + Instruction* live_inst = worklist_.front(); + worklist_.pop(); + AddOperandsToWorkList(live_inst); + MarkBlockAsLive(live_inst); + MarkLoadedVariablesAsLive(func, live_inst); + AddDecorationsToWorkList(live_inst); + AddDebugInstructionsToWorkList(live_inst); + } +} + +void AggressiveDCEPass::AddDebugInstructionsToWorkList( + const Instruction* inst) { + for (auto& line_inst : inst->dbg_line_insts()) { + if (line_inst.IsDebugLineInst()) { + AddOperandsToWorkList(&line_inst); + } + } + + if (inst->GetDebugScope().GetLexicalScope() != kNoDebugScope) { + auto* scope = + get_def_use_mgr()->GetDef(inst->GetDebugScope().GetLexicalScope()); + AddToWorklist(scope); + } + if (inst->GetDebugInlinedAt() != kNoInlinedAt) { + auto* inlined_at = get_def_use_mgr()->GetDef(inst->GetDebugInlinedAt()); + AddToWorklist(inlined_at); + } +} + +void AggressiveDCEPass::AddDecorationsToWorkList(const Instruction* inst) { + // Add OpDecorateId instructions that apply to this instruction to the work + // list. We use the decoration manager to look through the group + // decorations to get to the OpDecorate* instructions themselves. + auto decorations = + get_decoration_mgr()->GetDecorationsFor(inst->result_id(), false); + for (Instruction* dec : decorations) { + // We only care about OpDecorateId instructions because the are the only + // decorations that will reference an id that will have to be kept live + // because of that use. + if (dec->opcode() != SpvOpDecorateId) { + continue; + } + if (dec->GetSingleWordInOperand(1) == + SpvDecorationHlslCounterBufferGOOGLE) { + // These decorations should not force the use id to be live. It will be + // removed if either the target or the in operand are dead. + continue; + } + AddToWorklist(dec); + } +} + +void AggressiveDCEPass::MarkLoadedVariablesAsLive(Function* func, + Instruction* inst) { + std::vector live_variables = GetLoadedVariables(inst); + for (uint32_t var_id : live_variables) { + ProcessLoad(func, var_id); + } +} + +std::vector AggressiveDCEPass::GetLoadedVariables(Instruction* inst) { + if (inst->opcode() == SpvOpFunctionCall) { + return GetLoadedVariablesFromFunctionCall(inst); + } + uint32_t var_id = GetLoadedVariableFromNonFunctionCalls(inst); + if (var_id == 0) { + return {}; + } + return {var_id}; +} + +uint32_t AggressiveDCEPass::GetLoadedVariableFromNonFunctionCalls( + Instruction* inst) { + std::vector live_variables; + if (inst->IsAtomicWithLoad()) { + return GetVariableId(inst->GetSingleWordInOperand(kLoadSourceAddrInIdx)); + } + + switch (inst->opcode()) { + case SpvOpLoad: + case SpvOpImageTexelPointer: + return GetVariableId(inst->GetSingleWordInOperand(kLoadSourceAddrInIdx)); + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + return GetVariableId( + inst->GetSingleWordInOperand(kCopyMemorySourceAddrInIdx)); + default: + break; + } + + switch (inst->GetCommonDebugOpcode()) { + case CommonDebugInfoDebugDeclare: + return inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); + case CommonDebugInfoDebugValue: { + analysis::DebugInfoManager* debug_info_mgr = + context()->get_debug_info_mgr(); + return debug_info_mgr->GetVariableIdOfDebugValueUsedForDeclare(inst); + } + default: + break; + } + return 0; +} + +std::vector AggressiveDCEPass::GetLoadedVariablesFromFunctionCall( + const Instruction* inst) { + assert(inst->opcode() == SpvOpFunctionCall); + std::vector live_variables; + inst->ForEachInId([this, &live_variables](const uint32_t* operand_id) { + if (!IsPtr(*operand_id)) return; + uint32_t var_id = GetVariableId(*operand_id); + live_variables.push_back(var_id); + }); + return live_variables; +} + +uint32_t AggressiveDCEPass::GetVariableId(uint32_t ptr_id) { + assert(IsPtr(ptr_id) && + "Cannot get the variable when input is not a pointer."); + uint32_t varId = 0; + (void)GetPtr(ptr_id, &varId); + return varId; +} + +void AggressiveDCEPass::MarkBlockAsLive(Instruction* inst) { + BasicBlock* basic_block = context()->get_instr_block(inst); + if (basic_block == nullptr) { + return; + } + + // If we intend to keep this instruction, we need the block label and + // block terminator to have a valid block for the instruction. + AddToWorklist(basic_block->GetLabelInst()); + + // We need to mark the successors blocks that follow as live. If this is + // header of the merge construct, the construct may be folded, but we will + // definitely need the merge label. If it is not a construct, the terminator + // must be live, and the successor blocks will be marked as live when + // processing the terminator. + uint32_t merge_id = basic_block->MergeBlockIdIfAny(); + if (merge_id == 0) { + AddToWorklist(basic_block->terminator()); + } else { + AddToWorklist(context()->get_def_use_mgr()->GetDef(merge_id)); + } + + // Mark the structured control flow constructs that contains this block as + // live. If |inst| is an instruction in the loop header, then it is part of + // the loop, so the loop construct must be live. We exclude the label because + // it does not matter how many times it is executed. This could be extended + // to more instructions, but we will need it for now. + if (inst->opcode() != SpvOpLabel) + MarkLoopConstructAsLiveIfLoopHeader(basic_block); + + Instruction* next_branch_inst = GetBranchForNextHeader(basic_block); + if (next_branch_inst != nullptr) { + AddToWorklist(next_branch_inst); + Instruction* mergeInst = GetMergeInstruction(next_branch_inst); + AddToWorklist(mergeInst); + } + + if (inst->opcode() == SpvOpLoopMerge || + inst->opcode() == SpvOpSelectionMerge) { + AddBreaksAndContinuesToWorklist(inst); + } +} +void AggressiveDCEPass::MarkLoopConstructAsLiveIfLoopHeader( + BasicBlock* basic_block) { + // If this is the header for a loop, then loop structure needs to keep as well + // because the loop header is also part of the loop. + Instruction* merge_inst = basic_block->GetLoopMergeInst(); + if (merge_inst != nullptr) { + AddToWorklist(basic_block->terminator()); + AddToWorklist(merge_inst); + } +} + +void AggressiveDCEPass::AddOperandsToWorkList(const Instruction* inst) { + inst->ForEachInId([this](const uint32_t* iid) { + Instruction* inInst = get_def_use_mgr()->GetDef(*iid); + AddToWorklist(inInst); + }); + if (inst->type_id() != 0) { + AddToWorklist(get_def_use_mgr()->GetDef(inst->type_id())); + } +} + +void AggressiveDCEPass::InitializeWorkList( + Function* func, std::list& structured_order) { + AddToWorklist(&func->DefInst()); + MarkFunctionParameterAsLive(func); + MarkFirstBlockAsLive(func); + + // Add instructions with external side effects to the worklist. Also add + // branches that are not attached to a structured construct. + // TODO(s-perron): The handling of branch seems to be adhoc. This needs to be + // cleaned up. + for (auto& bi : structured_order) { + for (auto ii = bi->begin(); ii != bi->end(); ++ii) { + SpvOp op = ii->opcode(); + if (ii->IsBranch()) { + continue; + } + switch (op) { + case SpvOpStore: { + uint32_t var_id = 0; + (void)GetPtr(&*ii, &var_id); + if (!IsLocalVar(var_id, func)) AddToWorklist(&*ii); + } break; + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: { + uint32_t var_id = 0; + uint32_t target_addr_id = + ii->GetSingleWordInOperand(kCopyMemoryTargetAddrInIdx); + (void)GetPtr(target_addr_id, &var_id); + if (!IsLocalVar(var_id, func)) AddToWorklist(&*ii); + } break; + case SpvOpLoopMerge: + case SpvOpSelectionMerge: + case SpvOpUnreachable: + break; + default: { + // Function calls, atomics, function params, function returns, etc. + if (!ii->IsOpcodeSafeToDelete()) { + AddToWorklist(&*ii); + } + } break; + } + } + } +} + void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() { // Keep all execution modes. for (auto& exec : get_module()->execution_modes()) { @@ -603,7 +569,8 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() { } // Keep all entry points. for (auto& entry : get_module()->entry_points()) { - if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4) && + !preserve_interface_) { // In SPIR-V 1.4 and later, entry points must list all global variables // used. DCE can still remove non-input/output variables and update the // interface list. Mark the entry point as live and inputs and outputs as @@ -650,16 +617,25 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() { } // For each DebugInfo GlobalVariable keep all operands except the Variable. - // Later, if the variable is dead, we will set the operand to DebugInfoNone. + // Later, if the variable is killed with KillInst(), we will set the operand + // to DebugInfoNone. Create and save DebugInfoNone now for this possible + // later use. This is slightly unoptimal, but it avoids generating it during + // instruction killing when the module is not consistent. + bool debug_global_seen = false; for (auto& dbg : get_module()->ext_inst_debuginfo()) { - if (dbg.GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugGlobalVariable) + if (dbg.GetCommonDebugOpcode() != CommonDebugInfoDebugGlobalVariable) continue; + debug_global_seen = true; dbg.ForEachInId([this](const uint32_t* iid) { - Instruction* inInst = get_def_use_mgr()->GetDef(*iid); - if (inInst->opcode() == SpvOpVariable) return; - AddToWorklist(inInst); + Instruction* in_inst = get_def_use_mgr()->GetDef(*iid); + if (in_inst->opcode() == SpvOpVariable) return; + AddToWorklist(in_inst); }); } + if (debug_global_seen) { + auto dbg_none = context()->get_debug_info_mgr()->GetDebugInfoNone(); + AddToWorklist(dbg_none); + } } Pass::Status AggressiveDCEPass::ProcessImpl() { @@ -691,7 +667,7 @@ Pass::Status AggressiveDCEPass::ProcessImpl() { // Process all entry point functions. ProcessFunction pfn = [this](Function* fp) { return AggressiveDCE(fp); }; - modified |= context()->ProcessEntryPointCallTree(pfn); + modified |= context()->ProcessReachableCallTree(pfn); // If the decoration manager is kept live then the context will try to keep it // up to date. ADCE deals with group decorations by changing the operands in @@ -718,21 +694,20 @@ Pass::Status AggressiveDCEPass::ProcessImpl() { // Cleanup all CFG including all unreachable blocks. ProcessFunction cleanup = [this](Function* f) { return CFGCleanup(f); }; - modified |= context()->ProcessEntryPointCallTree(cleanup); + modified |= context()->ProcessReachableCallTree(cleanup); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } bool AggressiveDCEPass::EliminateDeadFunctions() { // Identify live functions first. Those that are not live - // are dead. ADCE is disabled for non-shaders so we do not check for exported - // functions here. + // are dead. std::unordered_set live_function_set; ProcessFunction mark_live = [&live_function_set](Function* fp) { live_function_set.insert(fp); return false; }; - context()->ProcessEntryPointCallTree(mark_live); + context()->ProcessReachableCallTree(mark_live); bool modified = false; for (auto funcIter = get_module()->begin(); @@ -798,7 +773,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { uint32_t counter_buffer_id = annotation->GetSingleWordInOperand(2); Instruction* counter_buffer_inst = get_def_use_mgr()->GetDef(counter_buffer_id); - if (IsDead(counter_buffer_inst)) { + if (!IsLive(counter_buffer_inst)) { context()->KillInst(annotation); modified = true; } @@ -813,7 +788,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { for (uint32_t i = 1; i < annotation->NumOperands();) { Instruction* opInst = get_def_use_mgr()->GetDef(annotation->GetSingleWordOperand(i)); - if (IsDead(opInst)) { + if (!IsLive(opInst)) { // Don't increment |i|. annotation->RemoveOperand(i); modified = true; @@ -840,7 +815,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { for (uint32_t i = 1; i < annotation->NumOperands();) { Instruction* opInst = get_def_use_mgr()->GetDef(annotation->GetSingleWordOperand(i)); - if (IsDead(opInst)) { + if (!IsLive(opInst)) { // Don't increment |i|. annotation->RemoveOperand(i + 1); annotation->RemoveOperand(i); @@ -874,14 +849,13 @@ bool AggressiveDCEPass::ProcessGlobalValues() { } for (auto& dbg : get_module()->ext_inst_debuginfo()) { - if (!IsDead(&dbg)) continue; + if (IsLive(&dbg)) continue; // Save GlobalVariable if its variable is live, otherwise null out variable // index - if (dbg.GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugGlobalVariable) { + if (dbg.GetCommonDebugOpcode() == CommonDebugInfoDebugGlobalVariable) { auto var_id = dbg.GetSingleWordOperand(kGlobalVariableVariableIndex); Instruction* var_inst = get_def_use_mgr()->GetDef(var_id); - if (!IsDead(var_inst)) continue; + if (IsLive(var_inst)) continue; context()->ForgetUses(&dbg); dbg.SetOperand( kGlobalVariableVariableIndex, @@ -896,7 +870,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { // Since ADCE is disabled for non-shaders, we don't check for export linkage // attributes here. for (auto& val : get_module()->types_values()) { - if (IsDead(&val)) { + if (!IsLive(&val)) { // Save forwarded pointer if pointer is live since closure does not mark // this live as it does not have a result id. This is a little too // conservative since it is not known if the structure type that needed @@ -904,14 +878,15 @@ bool AggressiveDCEPass::ProcessGlobalValues() { if (val.opcode() == SpvOpTypeForwardPointer) { uint32_t ptr_ty_id = val.GetSingleWordInOperand(0); Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id); - if (!IsDead(ptr_ty_inst)) continue; + if (IsLive(ptr_ty_inst)) continue; } to_kill_.push_back(&val); modified = true; } } - if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4) && + !preserve_interface_) { // Remove the dead interface variables from the entry point interface list. for (auto& entry : get_module()->entry_points()) { std::vector new_operands; @@ -922,7 +897,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { } else { auto* var = get_def_use_mgr()->GetDef(entry.GetSingleWordInOperand(i)); - if (!IsDead(var)) { + if (IsLive(var)) { new_operands.push_back(entry.GetInOperand(i)); } } @@ -937,8 +912,6 @@ bool AggressiveDCEPass::ProcessGlobalValues() { return modified; } -AggressiveDCEPass::AggressiveDCEPass() = default; - Pass::Status AggressiveDCEPass::Process() { // Initialize extensions allowlist InitExtensions(); @@ -999,8 +972,119 @@ void AggressiveDCEPass::InitExtensions() { "SPV_KHR_vulkan_memory_model", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", + "SPV_EXT_shader_image_int64", + "SPV_KHR_non_semantic_info", }); } +Instruction* AggressiveDCEPass::GetHeaderBranch(BasicBlock* blk) { + if (blk == nullptr) { + return nullptr; + } + BasicBlock* header_block = GetHeaderBlock(blk); + if (header_block == nullptr) { + return nullptr; + } + return header_block->terminator(); +} + +BasicBlock* AggressiveDCEPass::GetHeaderBlock(BasicBlock* blk) const { + if (blk == nullptr) { + return nullptr; + } + + BasicBlock* header_block = nullptr; + if (blk->IsLoopHeader()) { + header_block = blk; + } else { + uint32_t header = + context()->GetStructuredCFGAnalysis()->ContainingConstruct(blk->id()); + header_block = context()->get_instr_block(header); + } + return header_block; +} + +Instruction* AggressiveDCEPass::GetMergeInstruction(Instruction* inst) { + BasicBlock* bb = context()->get_instr_block(inst); + if (bb == nullptr) { + return nullptr; + } + return bb->GetMergeInst(); +} + +Instruction* AggressiveDCEPass::GetBranchForNextHeader(BasicBlock* blk) { + if (blk == nullptr) { + return nullptr; + } + + if (blk->IsLoopHeader()) { + uint32_t header = + context()->GetStructuredCFGAnalysis()->ContainingConstruct(blk->id()); + blk = context()->get_instr_block(header); + } + return GetHeaderBranch(blk); +} + +void AggressiveDCEPass::MarkFunctionParameterAsLive(const Function* func) { + func->ForEachParam( + [this](const Instruction* param) { + AddToWorklist(const_cast(param)); + }, + false); +} + +bool AggressiveDCEPass::BlockIsInConstruct(BasicBlock* header_block, + BasicBlock* bb) { + if (bb == nullptr || header_block == nullptr) { + return false; + } + + uint32_t current_header = bb->id(); + while (current_header != 0) { + if (current_header == header_block->id()) return true; + current_header = context()->GetStructuredCFGAnalysis()->ContainingConstruct( + current_header); + } + return false; +} + +bool AggressiveDCEPass::IsEntryPointWithNoCalls(Function* func) { + auto cached_result = entry_point_with_no_calls_cache_.find(func->result_id()); + if (cached_result != entry_point_with_no_calls_cache_.end()) { + return cached_result->second; + } + bool result = IsEntryPoint(func) && !HasCall(func); + entry_point_with_no_calls_cache_[func->result_id()] = result; + return result; +} + +bool AggressiveDCEPass::IsEntryPoint(Function* func) { + for (const Instruction& entry_point : get_module()->entry_points()) { + uint32_t entry_point_id = + entry_point.GetSingleWordInOperand(kEntryPointFunctionIdInIdx); + if (entry_point_id == func->result_id()) { + return true; + } + } + return false; +} + +bool AggressiveDCEPass::HasCall(Function* func) { + return !func->WhileEachInst( + [](Instruction* inst) { return inst->opcode() != SpvOpFunctionCall; }); +} + +void AggressiveDCEPass::MarkFirstBlockAsLive(Function* func) { + BasicBlock* first_block = &*func->begin(); + MarkBlockAsLive(first_block->GetLabelInst()); +} + +void AggressiveDCEPass::AddUnreachable(BasicBlock*& block) { + InstructionBuilder builder( + context(), block, + IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDefUse); + builder.AddUnreachable(); +} + } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h index f02e729fd5..1b3fd1e853 100644 --- a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h +++ b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h @@ -44,7 +44,9 @@ class AggressiveDCEPass : public MemPass { using GetBlocksFunction = std::function*(const BasicBlock*)>; - AggressiveDCEPass(); + AggressiveDCEPass(bool preserve_interface = false) + : preserve_interface_(preserve_interface) {} + const char* name() const override { return "eliminate-dead-code-aggressive"; } Status Process() override; @@ -55,23 +57,26 @@ class AggressiveDCEPass : public MemPass { } private: + // Preserve entry point interface if true. All variables in interface + // will be marked live and will not be eliminated. This mode is needed by + // GPU-Assisted Validation instrumentation where a change in the interface + // is not allowed. + bool preserve_interface_; + // Return true if |varId| is a variable of |storageClass|. |varId| must either // be 0 or the result of an instruction. bool IsVarOfStorage(uint32_t varId, uint32_t storageClass); - // Return true if |varId| is variable of function storage class or is - // private variable and privates can be optimized like locals (see - // privates_like_local_). - bool IsLocalVar(uint32_t varId); + // Return true if the instance of the variable |varId| can only be access in + // |func|. For example, a function scope variable, or a private variable + // where |func| is an entry point with no function calls. + bool IsLocalVar(uint32_t varId, Function* func); // Return true if |inst| is marked live. bool IsLive(const Instruction* inst) const { return live_insts_.Get(inst->unique_id()); } - // Returns true if |inst| is dead. - bool IsDead(Instruction* inst); - // Adds entry points, execution modes and workgroup size decorations to the // worklist for processing with the first function. void InitializeModuleScopeLiveInstructions(); @@ -101,18 +106,6 @@ class AggressiveDCEPass : public MemPass { // If |varId| is local, mark all stores of varId as live. void ProcessLoad(Function* func, uint32_t varId); - // If |bp| is structured header block, returns true and sets |mergeInst| to - // the merge instruction, |branchInst| to the branch and |mergeBlockId| to the - // merge block if they are not nullptr. Any of |mergeInst|, |branchInst| or - // |mergeBlockId| may be a null pointer. Returns false if |bp| is a null - // pointer. - bool IsStructuredHeader(BasicBlock* bp, Instruction** mergeInst, - Instruction** branchInst, uint32_t* mergeBlockId); - - // Initialize block2headerBranch_, header2nextHeaderBranch_, and - // branch2merge_ using |structuredOrder| to order blocks. - void ComputeBlock2HeaderMaps(std::list& structuredOrder); - // Add branch to |labelId| to end of block |bp|. void AddBranch(uint32_t labelId, BasicBlock* bp); @@ -140,14 +133,100 @@ class AggressiveDCEPass : public MemPass { Pass::Status ProcessImpl(); - // True if current function has a call instruction contained in it - bool call_in_func_; + // Adds instructions which must be kept because of they have side-effects + // that ADCE cannot model to the work list. + void InitializeWorkList(Function* func, + std::list& structured_order); - // True if current function is an entry point - bool func_is_entry_point_; + // Process each instruction in the work list by marking any instruction that + // that it depends on as live, and adding it to the work list. The work list + // will be empty at the end. + void ProcessWorkList(Function* func); - // True if current function is entry point and has no function calls. - bool private_like_local_; + // Kills any instructions in |func| that have not been marked as live. + bool KillDeadInstructions(const Function* func, + std::list& structured_order); + + // Adds the instructions that define the operands of |inst| to the work list. + void AddOperandsToWorkList(const Instruction* inst); + + // Marks all of the labels and branch that inst requires as live. + void MarkBlockAsLive(Instruction* inst); + + // Marks any variables from which |inst| may require data as live. + void MarkLoadedVariablesAsLive(Function* func, Instruction* inst); + + // Returns the id of the variable that |ptr_id| point to. |ptr_id| must be a + // value whose type is a pointer. + uint32_t GetVariableId(uint32_t ptr_id); + + // Returns all of the ids for the variables from which |inst| will load data. + std::vector GetLoadedVariables(Instruction* inst); + + // Returns all of the ids for the variables from which |inst| will load data. + // The opcode of |inst| must be OpFunctionCall. + std::vector GetLoadedVariablesFromFunctionCall( + const Instruction* inst); + + // Returns the id of the variable from which |inst| will load data. |inst| + // must not be an OpFunctionCall. Returns 0 if no data is read or the + // variable cannot be determined. Note that in logical addressing mode the + // latter is not possible for function and private storage class because there + // cannot be variable pointers pointing to those storage classes. + uint32_t GetLoadedVariableFromNonFunctionCalls(Instruction* inst); + + // Adds all decorations of |inst| to the work list. + void AddDecorationsToWorkList(const Instruction* inst); + + // Adds all debug instruction associated with |inst| to the work list. + void AddDebugInstructionsToWorkList(const Instruction* inst); + + // Marks all of the OpFunctionParameter instructions in |func| as live. + void MarkFunctionParameterAsLive(const Function* func); + + // Returns the terminator instruction in the header for the innermost + // construct that contains |blk|. Returns nullptr if no such header exists. + Instruction* GetHeaderBranch(BasicBlock* blk); + + // Returns the header for the innermost construct that contains |blk|. A loop + // header will be its own header. Returns nullptr if no such header exists. + BasicBlock* GetHeaderBlock(BasicBlock* blk) const; + + // Returns the same as |GetHeaderBlock| except if |blk| is a loop header it + // will return the header of the next enclosing construct. Returns nullptr if + // no such header exists. + Instruction* GetBranchForNextHeader(BasicBlock* blk); + + // Returns the merge instruction in the same basic block as |inst|. Returns + // nullptr if one does not exist. + Instruction* GetMergeInstruction(Instruction* inst); + + // Returns true if |bb| is in the construct with header |header_block|. + bool BlockIsInConstruct(BasicBlock* header_block, BasicBlock* bb); + + // Returns true if |func| is an entry point that does not have any function + // calls. + bool IsEntryPointWithNoCalls(Function* func); + + // Returns true if |func| is an entry point. + bool IsEntryPoint(Function* func); + + // Returns true if |func| contains a function call. + bool HasCall(Function* func); + + // Marks the first block, which is the entry block, in |func| as live. + void MarkFirstBlockAsLive(Function* func); + + // Adds an OpUnreachable instruction at the end of |block|. + void AddUnreachable(BasicBlock*& block); + + // Marks the OpLoopMerge and the terminator in |basic_block| as live if + // |basic_block| is a loop header. + void MarkLoopConstructAsLiveIfLoopHeader(BasicBlock* basic_block); + + // The cached results for |IsEntryPointWithNoCalls|. It maps the function's + // result id to the return value. + std::unordered_map entry_point_with_no_calls_cache_; // Live Instruction Worklist. An instruction is added to this list // if it might have a side effect, either directly or indirectly. @@ -156,27 +235,6 @@ class AggressiveDCEPass : public MemPass { // building up the live instructions set |live_insts_|. std::queue worklist_; - // Map from block to the branch instruction in the header of the most - // immediate controlling structured if or loop. A loop header block points - // to its own branch instruction. An if-selection block points to the branch - // of an enclosing construct's header, if one exists. - std::unordered_map block2headerBranch_; - - // Map from header block to the branch instruction in the header of the - // structured construct enclosing it. - // The liveness algorithm is designed to iteratively mark as live all - // structured constructs enclosing a live instruction. - std::unordered_map header2nextHeaderBranch_; - - // Maps basic block to their index in the structured order traversal. - std::unordered_map structured_order_index_; - - // Map from branch to its associated merge instruction, if any - std::unordered_map branch2merge_; - - // Store instructions to variables of private storage - std::vector private_stores_; - // Live Instructions utils::BitVector live_insts_; diff --git a/third_party/spirv-tools/source/opt/block_merge_pass.cpp b/third_party/spirv-tools/source/opt/block_merge_pass.cpp index 04e47f1c2e..ef7f31fe0b 100644 --- a/third_party/spirv-tools/source/opt/block_merge_pass.cpp +++ b/third_party/spirv-tools/source/opt/block_merge_pass.cpp @@ -44,7 +44,7 @@ bool BlockMergePass::MergeBlocks(Function* func) { Pass::Status BlockMergePass::Process() { // Process all entry point functions. ProcessFunction pfn = [this](Function* fp) { return MergeBlocks(fp); }; - bool modified = context()->ProcessEntryPointCallTree(pfn); + bool modified = context()->ProcessReachableCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/block_merge_util.cpp b/third_party/spirv-tools/source/opt/block_merge_util.cpp index 15e8c6ff9c..8ae8020a58 100644 --- a/third_party/spirv-tools/source/opt/block_merge_util.cpp +++ b/third_party/spirv-tools/source/opt/block_merge_util.cpp @@ -171,10 +171,17 @@ void MergeWithSuccessor(IRContext* context, Function* func, // and OpBranchConditional. auto terminator = bi->terminator(); auto& vec = terminator->dbg_line_insts(); - auto& new_vec = merge_inst->dbg_line_insts(); - new_vec.insert(new_vec.end(), vec.begin(), vec.end()); - terminator->clear_dbg_line_insts(); - + if (vec.size() > 0) { + merge_inst->ClearDbgLineInsts(); + auto& new_vec = merge_inst->dbg_line_insts(); + new_vec.insert(new_vec.end(), vec.begin(), vec.end()); + terminator->ClearDbgLineInsts(); + for (auto& l_inst : new_vec) + context->get_def_use_mgr()->AnalyzeInstDefUse(&l_inst); + } + // Clear debug scope of terminator to avoid DebugScope + // emitted between terminator and merge. + terminator->SetDebugScope(DebugScope(kNoDebugScope, kNoInlinedAt)); // Move the merge instruction to just before the terminator. merge_inst->InsertBefore(terminator); } diff --git a/third_party/spirv-tools/source/opt/ccp_pass.cpp b/third_party/spirv-tools/source/opt/ccp_pass.cpp index d84f13f5d1..8b896d504b 100644 --- a/third_party/spirv-tools/source/opt/ccp_pass.cpp +++ b/third_party/spirv-tools/source/opt/ccp_pass.cpp @@ -291,6 +291,10 @@ bool CCPPass::ReplaceValues() { } bool CCPPass::PropagateConstants(Function* fp) { + if (fp->IsDeclaration()) { + return false; + } + // Mark function parameters as varying. fp->ForEachParam([this](const Instruction* inst) { values_[inst->result_id()] = kVaryingSSAId; diff --git a/third_party/spirv-tools/source/opt/combine_access_chains.cpp b/third_party/spirv-tools/source/opt/combine_access_chains.cpp index facfc24b6c..142897a2e1 100644 --- a/third_party/spirv-tools/source/opt/combine_access_chains.cpp +++ b/third_party/spirv-tools/source/opt/combine_access_chains.cpp @@ -34,6 +34,10 @@ Pass::Status CombineAccessChains::Process() { } bool CombineAccessChains::ProcessFunction(Function& function) { + if (function.IsDeclaration()) { + return false; + } + bool modified = false; cfg()->ForEachBlockInReversePostOrder( diff --git a/third_party/spirv-tools/source/opt/compact_ids_pass.cpp b/third_party/spirv-tools/source/opt/compact_ids_pass.cpp index 67091531c5..8815b8c658 100644 --- a/third_party/spirv-tools/source/opt/compact_ids_pass.cpp +++ b/third_party/spirv-tools/source/opt/compact_ids_pass.cpp @@ -86,9 +86,12 @@ Pass::Status CompactIdsPass::Process() { }, true); - if (modified) + if (modified) { context()->module()->SetIdBound( static_cast(result_id_mapping.size() + 1)); + // There are ids in the feature manager that could now be invalid + context()->ResetFeatureManager(); + } return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/const_folding_rules.cpp b/third_party/spirv-tools/source/opt/const_folding_rules.cpp index d262a7ecab..515a3ed5df 100644 --- a/third_party/spirv-tools/source/opt/const_folding_rules.cpp +++ b/third_party/spirv-tools/source/opt/const_folding_rules.cpp @@ -1002,7 +1002,7 @@ const analysis::Constant* FoldClamp1( "Expecting a GLSLstd450 extended instruction."); // Make sure all Clamp operands are constants. - for (uint32_t i = 1; i < 3; i++) { + for (uint32_t i = 1; i < 4; i++) { if (constants[i] == nullptr) { return nullptr; } @@ -1017,7 +1017,7 @@ const analysis::Constant* FoldClamp1( context); } -// Fold a clamp instruction when |x >= min_val|. +// Fold a clamp instruction when |x <= min_val|. const analysis::Constant* FoldClamp2( IRContext* context, Instruction* inst, const std::vector& constants) { diff --git a/third_party/spirv-tools/source/opt/constants.cpp b/third_party/spirv-tools/source/opt/constants.cpp index 19ca6008da..020e248b29 100644 --- a/third_party/spirv-tools/source/opt/constants.cpp +++ b/third_party/spirv-tools/source/opt/constants.cpp @@ -217,7 +217,8 @@ Instruction* ConstantManager::BuildInstructionAndAddToModule( auto* new_inst_ptr = new_inst.get(); *pos = pos->InsertBefore(std::move(new_inst)); ++(*pos); - context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inst_ptr); + if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) + context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inst_ptr); MapConstantToInst(new_const, new_inst_ptr); return new_inst_ptr; } @@ -432,6 +433,12 @@ uint32_t ConstantManager::GetSIntConst(int32_t val) { return GetDefiningInstruction(c)->result_id(); } +uint32_t ConstantManager::GetUIntConst(uint32_t val) { + Type* uint_type = context()->get_type_mgr()->GetUIntType(); + const Constant* c = GetConstant(uint_type, {val}); + return GetDefiningInstruction(c)->result_id(); +} + std::vector Constant::GetVectorComponents( analysis::ConstantManager* const_mgr) const { std::vector components; diff --git a/third_party/spirv-tools/source/opt/constants.h b/third_party/spirv-tools/source/opt/constants.h index 95d984fcd2..52bd809ab3 100644 --- a/third_party/spirv-tools/source/opt/constants.h +++ b/third_party/spirv-tools/source/opt/constants.h @@ -642,6 +642,9 @@ class ConstantManager { // Returns the id of a 32-bit signed integer constant with value |val|. uint32_t GetSIntConst(int32_t val); + // Returns the id of a 32-bit unsigned integer constant with value |val|. + uint32_t GetUIntConst(uint32_t val); + private: // Creates a Constant instance with the given type and a vector of constant // defining words. Returns a unique pointer to the created Constant instance diff --git a/third_party/spirv-tools/source/opt/control_dependence.cpp b/third_party/spirv-tools/source/opt/control_dependence.cpp new file mode 100644 index 0000000000..f4879e0f34 --- /dev/null +++ b/third_party/spirv-tools/source/opt/control_dependence.cpp @@ -0,0 +1,156 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/control_dependence.h" + +#include +#include +#include +#include + +#include "source/opt/basic_block.h" +#include "source/opt/cfg.h" +#include "source/opt/dominator_analysis.h" +#include "source/opt/function.h" +#include "source/opt/instruction.h" +#include "spirv/unified1/spirv.h" + +// Computes the control dependence graph (CDG) using the algorithm in Cytron +// 1991, "Efficiently Computing Static Single Assignment Form and the Control +// Dependence Graph." It relies on the fact that the control dependence sources +// (blocks on which a block is control dependent) are exactly the post-dominance +// frontier for that block. The explanation and proofs are given in Section 6 of +// that paper. +// Link: https://www.cs.utexas.edu/~pingali/CS380C/2010/papers/ssaCytron.pdf +// +// The algorithm in Section 4.2 of the same paper is used to construct the +// dominance frontier. It uses the post-dominance tree, which is available in +// the IR context. + +namespace spvtools { +namespace opt { +constexpr uint32_t ControlDependenceAnalysis::kPseudoEntryBlock; + +uint32_t ControlDependence::GetConditionID(const CFG& cfg) const { + if (source_bb_id() == 0) { + // Entry dependence; return 0. + return 0; + } + const BasicBlock* source_bb = cfg.block(source_bb_id()); + const Instruction* branch = source_bb->terminator(); + assert((branch->opcode() == SpvOpBranchConditional || + branch->opcode() == SpvOpSwitch) && + "invalid control dependence; last instruction must be conditional " + "branch or switch"); + return branch->GetSingleWordInOperand(0); +} + +bool ControlDependence::operator<(const ControlDependence& other) const { + return std::tie(source_bb_id_, target_bb_id_, branch_target_bb_id_) < + std::tie(other.source_bb_id_, other.target_bb_id_, + other.branch_target_bb_id_); +} + +bool ControlDependence::operator==(const ControlDependence& other) const { + return std::tie(source_bb_id_, target_bb_id_, branch_target_bb_id_) == + std::tie(other.source_bb_id_, other.target_bb_id_, + other.branch_target_bb_id_); +} + +std::ostream& operator<<(std::ostream& os, const ControlDependence& dep) { + os << dep.source_bb_id() << "->" << dep.target_bb_id(); + if (dep.branch_target_bb_id() != dep.target_bb_id()) { + os << " through " << dep.branch_target_bb_id(); + } + return os; +} + +void ControlDependenceAnalysis::ComputePostDominanceFrontiers( + const CFG& cfg, const PostDominatorAnalysis& pdom) { + // Compute post-dominance frontiers (reverse graph). + // The dominance frontier for a block X is equal to (Equation 4) + // DF_local(X) U { B in DF_up(Z) | X = ipdom(Z) } + // (ipdom(Z) is the immediate post-dominator of Z.) + // where + // DF_local(X) = { Y | X -> Y in CFG, X does not strictly post-dominate Y } + // represents the contribution of X's predecessors to the DF, and + // DF_up(Z) = { Y | Y in DF(Z), ipdom(Z) does not strictly post-dominate Y } + // (note: ipdom(Z) = X.) + // represents the contribution of a block to its immediate post- + // dominator's DF. + // This is computed in one pass through a post-order traversal of the + // post-dominator tree. + + // Assert that there is a block other than the pseudo exit in the pdom tree, + // as we need one to get the function entry point (as the pseudo exit is not + // actually part of the function.) + assert(!cfg.IsPseudoExitBlock(pdom.GetDomTree().post_begin()->bb_)); + Function* function = pdom.GetDomTree().post_begin()->bb_->GetParent(); + uint32_t function_entry = function->entry()->id(); + // Explicitly initialize pseudo-entry block, as it doesn't depend on anything, + // so it won't be initialized in the following loop. + reverse_nodes_[kPseudoEntryBlock] = {}; + for (auto it = pdom.GetDomTree().post_cbegin(); + it != pdom.GetDomTree().post_cend(); ++it) { + ComputePostDominanceFrontierForNode(cfg, pdom, function_entry, *it); + } +} + +void ControlDependenceAnalysis::ComputePostDominanceFrontierForNode( + const CFG& cfg, const PostDominatorAnalysis& pdom, uint32_t function_entry, + const DominatorTreeNode& pdom_node) { + const uint32_t label = pdom_node.id(); + ControlDependenceList& edges = reverse_nodes_[label]; + for (uint32_t pred : cfg.preds(label)) { + if (!pdom.StrictlyDominates(label, pred)) { + edges.push_back(ControlDependence(pred, label)); + } + } + if (label == function_entry) { + // Add edge from pseudo-entry to entry. + // In CDG construction, an edge is added from entry to exit, so only the + // exit node can post-dominate entry. + edges.push_back(ControlDependence(kPseudoEntryBlock, label)); + } + for (DominatorTreeNode* child : pdom_node) { + // Note: iterate dependences by value, as we need a copy. + for (const ControlDependence& dep : reverse_nodes_[child->id()]) { + // Special-case pseudo-entry, as above. + if (dep.source_bb_id() == kPseudoEntryBlock || + !pdom.StrictlyDominates(label, dep.source_bb_id())) { + edges.push_back(ControlDependence(dep.source_bb_id(), label, + dep.branch_target_bb_id())); + } + } + } +} + +void ControlDependenceAnalysis::ComputeControlDependenceGraph( + const CFG& cfg, const PostDominatorAnalysis& pdom) { + ComputePostDominanceFrontiers(cfg, pdom); + ComputeForwardGraphFromReverse(); +} + +void ControlDependenceAnalysis::ComputeForwardGraphFromReverse() { + for (const auto& entry : reverse_nodes_) { + // Ensure an entry is created for each node. + forward_nodes_[entry.first]; + for (const ControlDependence& dep : entry.second) { + forward_nodes_[dep.source_bb_id()].push_back(dep); + } + } +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/control_dependence.h b/third_party/spirv-tools/source/opt/control_dependence.h new file mode 100644 index 0000000000..993f379364 --- /dev/null +++ b/third_party/spirv-tools/source/opt/control_dependence.h @@ -0,0 +1,197 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_CONTROL_DEPENDENCE_H_ +#define SOURCE_OPT_CONTROL_DEPENDENCE_H_ + +#include +#include +#include +#include +#include +#include + +#include "source/opt/cfg.h" +#include "source/opt/dominator_analysis.h" + +namespace spvtools { +namespace opt { + +class ControlDependence { + public: + // The label of the source of this dependence, i.e. the block on which the + // target is dependent on. + // A |source_bb_id| of 0 represents an "entry" dependence, meaning that the + // execution of |target_bb_id| is only dependent on entry to the function. + uint32_t source_bb_id() const { return source_bb_id_; } + // The label of the target of this dependence, i.e. the block which is + // dependent on the source. + uint32_t target_bb_id() const { return target_bb_id_; } + // The label of the target of the *branch* for this dependence. + // Equal to the ID of the entry block for entry dependences. + // + // For example, for the partial CFG pictured below: + // 1 ---> 2 ---> 4 ---> 6 + // \ \ ^ + // \-> 3 \-> 5 -----/ + // Block 6 is control dependent on block 1, but this dependence comes from the + // branch 1 -> 2, so in this case the branch target ID would be 2. + uint32_t branch_target_bb_id() const { return branch_target_bb_id_; } + + // Create a direct control dependence from BB ID |source| to |target|. + ControlDependence(uint32_t source, uint32_t target) + : source_bb_id_(source), + target_bb_id_(target), + branch_target_bb_id_(target) {} + // Create a control dependence from BB ID |source| to |target| through the + // branch from |source| to |branch_target|. + ControlDependence(uint32_t source, uint32_t target, uint32_t branch_target) + : source_bb_id_(source), + target_bb_id_(target), + branch_target_bb_id_(branch_target) {} + + // Gets the ID of the conditional value for the branch corresponding to this + // control dependence. This is the first input operand for both + // OpConditionalBranch and OpSwitch. + // Returns 0 for entry dependences. + uint32_t GetConditionID(const CFG& cfg) const; + + bool operator==(const ControlDependence& other) const; + bool operator!=(const ControlDependence& other) const { + return !(*this == other); + } + + // Comparison operators, ordered lexicographically. Total ordering. + bool operator<(const ControlDependence& other) const; + bool operator>(const ControlDependence& other) const { return other < *this; } + bool operator<=(const ControlDependence& other) const { + return !(*this > other); + } + bool operator>=(const ControlDependence& other) const { + return !(*this < other); + } + + private: + uint32_t source_bb_id_; + uint32_t target_bb_id_; + uint32_t branch_target_bb_id_; +}; + +// Prints |dep| to |os| in a human-readable way. For example, +// 1->2 (target_bb_id = branch_target_bb_id = 2) +// 3->4 through 5 (target_bb_id = 4, branch_target_bb_id = 5) +std::ostream& operator<<(std::ostream& os, const ControlDependence& dep); + +// Represents the control dependence graph. A basic block is control dependent +// on another if the result of that block (e.g. the condition of a conditional +// branch) influences whether it is executed or not. More formally, a block A is +// control dependent on B iff: +// 1. there exists a path from A to the exit node that does *not* go through B +// (i.e., A does not postdominate B), and +// 2. there exists a path B -> b_1 -> ... -> b_n -> A such that A post-dominates +// all nodes b_i. +class ControlDependenceAnalysis { + public: + // Map basic block labels to control dependencies/dependents. + // Not guaranteed to be in any particular order. + using ControlDependenceList = std::vector; + using ControlDependenceListMap = + std::unordered_map; + + // 0, the label number for the pseudo entry block. + // All control dependences on the pseudo entry block are of type kEntry, and + // vice versa. + static constexpr uint32_t kPseudoEntryBlock = 0; + + // Build the control dependence graph for the given control flow graph |cfg| + // and corresponding post-dominator analysis |pdom|. + void ComputeControlDependenceGraph(const CFG& cfg, + const PostDominatorAnalysis& pdom); + + // Get the list of the nodes that depend on a block. + // Return value is not guaranteed to be in any particular order. + const ControlDependenceList& GetDependenceTargets(uint32_t block) const { + return forward_nodes_.at(block); + } + + // Get the list of the nodes on which a block depends on. + // Return value is not guaranteed to be in any particular order. + const ControlDependenceList& GetDependenceSources(uint32_t block) const { + return reverse_nodes_.at(block); + } + + // Runs the function |f| on each block label in the CDG. If any iteration + // returns false, immediately stops iteration and returns false. Otherwise + // returns true. Nodes are iterated in some undefined order, including the + // pseudo-entry block. + bool WhileEachBlockLabel(std::function f) const { + for (const auto& entry : forward_nodes_) { + if (!f(entry.first)) { + return false; + } + } + return true; + } + + // Runs the function |f| on each block label in the CDG. Nodes are iterated in + // some undefined order, including the pseudo-entry block. + void ForEachBlockLabel(std::function f) const { + WhileEachBlockLabel([&f](uint32_t label) { + f(label); + return true; + }); + } + + // Returns true if the block |id| exists in the control dependence graph. + // This can be false even if the block exists in the function when it is part + // of an infinite loop, since it is not part of the post-dominator tree. + bool HasBlock(uint32_t id) const { return forward_nodes_.count(id) > 0; } + + // Returns true if block |a| is dependent on block |b|. + bool IsDependent(uint32_t a, uint32_t b) const { + if (!HasBlock(a)) return false; + // BBs tend to have more dependents (targets) than they are dependent on + // (sources), so search sources. + const ControlDependenceList& a_sources = GetDependenceSources(a); + return std::find_if(a_sources.begin(), a_sources.end(), + [b](const ControlDependence& dep) { + return dep.source_bb_id() == b; + }) != a_sources.end(); + } + + private: + // Computes the post-dominance frontiers (i.e. the reverse CDG) for each node + // in the post-dominator tree. Only modifies reverse_nodes_; forward_nodes_ is + // not modified. + void ComputePostDominanceFrontiers(const CFG& cfg, + const PostDominatorAnalysis& pdom); + // Computes the post-dominance frontier for a specific node |pdom_node| in the + // post-dominator tree. Result is placed in reverse_nodes_[pdom_node.id()]. + void ComputePostDominanceFrontierForNode(const CFG& cfg, + const PostDominatorAnalysis& pdom, + uint32_t function_entry, + const DominatorTreeNode& pdom_node); + + // Computes the forward graph (forward_nodes_) from the reverse graph + // (reverse_nodes_). + void ComputeForwardGraphFromReverse(); + + ControlDependenceListMap forward_nodes_; + ControlDependenceListMap reverse_nodes_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_CONTROL_DEPENDENCE_H_ diff --git a/third_party/spirv-tools/source/opt/convert_to_half_pass.cpp b/third_party/spirv-tools/source/opt/convert_to_half_pass.cpp index 6b3b540aa4..b127eabe96 100644 --- a/third_party/spirv-tools/source/opt/convert_to_half_pass.cpp +++ b/third_party/spirv-tools/source/opt/convert_to_half_pass.cpp @@ -177,18 +177,21 @@ bool ConvertToHalfPass::GenHalfArith(Instruction* inst) { return modified; } -bool ConvertToHalfPass::ProcessPhi(Instruction* inst) { - // Add float16 converts of any float32 operands and change type - // of phi to float16 equivalent. Operand converts need to be added to - // preceeding blocks. +bool ConvertToHalfPass::ProcessPhi(Instruction* inst, uint32_t from_width, + uint32_t to_width) { + // Add converts of any float operands to to_width if they are of from_width. + // If converting to 16, change type of phi to float16 equivalent and remember + // result id. Converts need to be added to preceeding blocks. uint32_t ocnt = 0; uint32_t* prev_idp; - inst->ForEachInId([&ocnt, &prev_idp, this](uint32_t* idp) { + bool modified = false; + inst->ForEachInId([&ocnt, &prev_idp, &from_width, &to_width, &modified, + this](uint32_t* idp) { if (ocnt % 2 == 0) { prev_idp = idp; } else { Instruction* val_inst = get_def_use_mgr()->GetDef(*prev_idp); - if (IsFloat(val_inst, 32)) { + if (IsFloat(val_inst, from_width)) { BasicBlock* bp = context()->get_instr_block(*idp); auto insert_before = bp->tail(); if (insert_before != bp->begin()) { @@ -197,15 +200,19 @@ bool ConvertToHalfPass::ProcessPhi(Instruction* inst) { insert_before->opcode() != SpvOpLoopMerge) ++insert_before; } - GenConvert(prev_idp, 16, &*insert_before); + GenConvert(prev_idp, to_width, &*insert_before); + modified = true; } } ++ocnt; }); - inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16)); - get_def_use_mgr()->AnalyzeInstUse(inst); - converted_ids_.insert(inst->result_id()); - return true; + if (to_width == 16u) { + inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16u)); + converted_ids_.insert(inst->result_id()); + modified = true; + } + if (modified) get_def_use_mgr()->AnalyzeInstUse(inst); + return modified; } bool ConvertToHalfPass::ProcessConvert(Instruction* inst) { @@ -242,9 +249,10 @@ bool ConvertToHalfPass::ProcessImageRef(Instruction* inst) { } bool ConvertToHalfPass::ProcessDefault(Instruction* inst) { - bool modified = false; // If non-relaxed instruction has changed operands, need to convert // them back to float32 + if (inst->opcode() == SpvOpPhi) return ProcessPhi(inst, 16u, 32u); + bool modified = false; inst->ForEachInId([&inst, &modified, this](uint32_t* idp) { if (converted_ids_.count(*idp) == 0) return; uint32_t old_id = *idp; @@ -262,7 +270,7 @@ bool ConvertToHalfPass::GenHalfInst(Instruction* inst) { if (IsArithmetic(inst) && inst_relaxed) modified = GenHalfArith(inst); else if (inst->opcode() == SpvOpPhi && inst_relaxed) - modified = ProcessPhi(inst); + modified = ProcessPhi(inst, 32u, 16u); else if (inst->opcode() == SpvOpFConvert) modified = ProcessConvert(inst); else if (image_ops_.count(inst->opcode()) != 0) @@ -340,7 +348,7 @@ Pass::Status ConvertToHalfPass::ProcessImpl() { Pass::ProcessFunction pfn = [this](Function* fp) { return ProcessFunction(fp); }; - bool modified = context()->ProcessEntryPointCallTree(pfn); + bool modified = context()->ProcessReachableCallTree(pfn); // If modified, make sure module has Float16 capability if (modified) context()->AddCapability(SpvCapabilityFloat16); // Remove all RelaxedPrecision decorations from instructions and globals diff --git a/third_party/spirv-tools/source/opt/convert_to_half_pass.h b/third_party/spirv-tools/source/opt/convert_to_half_pass.h index b647dd4a31..c6e84d1b74 100644 --- a/third_party/spirv-tools/source/opt/convert_to_half_pass.h +++ b/third_party/spirv-tools/source/opt/convert_to_half_pass.h @@ -93,7 +93,7 @@ class ConvertToHalfPass : public Pass { bool GenHalfArith(Instruction* inst); // Gen code for relaxed phi |inst| - bool ProcessPhi(Instruction* inst); + bool ProcessPhi(Instruction* inst, uint32_t from_width, uint32_t to_width); // Gen code for relaxed convert |inst| bool ProcessConvert(Instruction* inst); diff --git a/third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp b/third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp new file mode 100644 index 0000000000..e84d3578a8 --- /dev/null +++ b/third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp @@ -0,0 +1,437 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/convert_to_sampled_image_pass.h" + +#include +#include +#include + +#include "source/opt/ir_builder.h" +#include "source/util/make_unique.h" +#include "source/util/parse_number.h" + +namespace spvtools { +namespace opt { + +using VectorOfDescriptorSetAndBindingPairs = + std::vector; +using DescriptorSetBindingToInstruction = + ConvertToSampledImagePass::DescriptorSetBindingToInstruction; + +namespace { + +using utils::ParseNumber; + +// Returns true if the given char is ':', '\0' or considered as blank space +// (i.e.: '\n', '\r', '\v', '\t', '\f' and ' '). +bool IsSeparator(char ch) { + return std::strchr(":\0", ch) || std::isspace(ch) != 0; +} + +// Reads characters starting from |str| until it meets a separator. Parses a +// number from the characters and stores it into |number|. Returns the pointer +// to the separator if it succeeds. Otherwise, returns nullptr. +const char* ParseNumberUntilSeparator(const char* str, uint32_t* number) { + const char* number_begin = str; + while (!IsSeparator(*str)) str++; + const char* number_end = str; + std::string number_in_str(number_begin, number_end - number_begin); + if (!utils::ParseNumber(number_in_str.c_str(), number)) { + // The descriptor set is not a valid uint32 number. + return nullptr; + } + return str; +} + +// Returns id of the image type used for the sampled image type of +// |sampled_image|. +uint32_t GetImageTypeOfSampledImage(analysis::TypeManager* type_mgr, + Instruction* sampled_image) { + auto* sampled_image_type = + type_mgr->GetType(sampled_image->type_id())->AsSampledImage(); + return type_mgr->GetTypeInstruction(sampled_image_type->image_type()); +} + +// Finds the instruction whose id is |inst_id|. Follows the operand of +// OpCopyObject recursively if the opcode of the instruction is OpCopyObject +// and returns the first instruction that does not have OpCopyObject as opcode. +Instruction* GetNonCopyObjectDef(analysis::DefUseManager* def_use_mgr, + uint32_t inst_id) { + Instruction* inst = def_use_mgr->GetDef(inst_id); + while (inst->opcode() == SpvOpCopyObject) { + inst_id = inst->GetSingleWordInOperand(0u); + inst = def_use_mgr->GetDef(inst_id); + } + return inst; +} + +} // namespace + +bool ConvertToSampledImagePass::GetDescriptorSetBinding( + const Instruction& inst, + DescriptorSetAndBinding* descriptor_set_binding) const { + auto* decoration_manager = context()->get_decoration_mgr(); + bool found_descriptor_set_to_convert = false; + bool found_binding_to_convert = false; + for (auto decorate : + decoration_manager->GetDecorationsFor(inst.result_id(), false)) { + uint32_t decoration = decorate->GetSingleWordInOperand(1u); + if (decoration == SpvDecorationDescriptorSet) { + if (found_descriptor_set_to_convert) { + assert(false && "A resource has two OpDecorate for the descriptor set"); + return false; + } + descriptor_set_binding->descriptor_set = + decorate->GetSingleWordInOperand(2u); + found_descriptor_set_to_convert = true; + } else if (decoration == SpvDecorationBinding) { + if (found_binding_to_convert) { + assert(false && "A resource has two OpDecorate for the binding"); + return false; + } + descriptor_set_binding->binding = decorate->GetSingleWordInOperand(2u); + found_binding_to_convert = true; + } + } + return found_descriptor_set_to_convert && found_binding_to_convert; +} + +bool ConvertToSampledImagePass::ShouldResourceBeConverted( + const DescriptorSetAndBinding& descriptor_set_binding) const { + return descriptor_set_binding_pairs_.find(descriptor_set_binding) != + descriptor_set_binding_pairs_.end(); +} + +const analysis::Type* ConvertToSampledImagePass::GetVariableType( + const Instruction& variable) const { + if (variable.opcode() != SpvOpVariable) return nullptr; + auto* type = context()->get_type_mgr()->GetType(variable.type_id()); + auto* pointer_type = type->AsPointer(); + if (!pointer_type) return nullptr; + + return pointer_type->pointee_type(); +} + +SpvStorageClass ConvertToSampledImagePass::GetStorageClass( + const Instruction& variable) const { + assert(variable.opcode() == SpvOpVariable); + auto* type = context()->get_type_mgr()->GetType(variable.type_id()); + auto* pointer_type = type->AsPointer(); + if (!pointer_type) return SpvStorageClassMax; + + return pointer_type->storage_class(); +} + +bool ConvertToSampledImagePass::CollectResourcesToConvert( + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler, + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image) + const { + for (auto& inst : context()->types_values()) { + const auto* variable_type = GetVariableType(inst); + if (variable_type == nullptr) continue; + + DescriptorSetAndBinding descriptor_set_binding; + if (!GetDescriptorSetBinding(inst, &descriptor_set_binding)) continue; + + if (!ShouldResourceBeConverted(descriptor_set_binding)) { + continue; + } + + if (variable_type->AsImage()) { + if (!descriptor_set_binding_pair_to_image + ->insert({descriptor_set_binding, &inst}) + .second) { + return false; + } + } else if (variable_type->AsSampler()) { + if (!descriptor_set_binding_pair_to_sampler + ->insert({descriptor_set_binding, &inst}) + .second) { + return false; + } + } + } + return true; +} + +Pass::Status ConvertToSampledImagePass::Process() { + Status status = Status::SuccessWithoutChange; + + DescriptorSetBindingToInstruction descriptor_set_binding_pair_to_sampler, + descriptor_set_binding_pair_to_image; + if (!CollectResourcesToConvert(&descriptor_set_binding_pair_to_sampler, + &descriptor_set_binding_pair_to_image)) { + return Status::Failure; + } + + for (auto& image : descriptor_set_binding_pair_to_image) { + status = CombineStatus( + status, UpdateImageVariableToSampledImage(image.second, image.first)); + if (status == Status::Failure) { + return status; + } + } + + for (const auto& sampler : descriptor_set_binding_pair_to_sampler) { + // Converting only a Sampler to Sampled Image is not allowed. It must have a + // corresponding image to combine the sampler with. + auto image_itr = descriptor_set_binding_pair_to_image.find(sampler.first); + if (image_itr == descriptor_set_binding_pair_to_image.end() || + image_itr->second == nullptr) { + return Status::Failure; + } + + status = CombineStatus( + status, CheckUsesOfSamplerVariable(sampler.second, image_itr->second)); + if (status == Status::Failure) { + return status; + } + } + + return status; +} + +void ConvertToSampledImagePass::FindUses(const Instruction* inst, + std::vector* uses, + uint32_t user_opcode) const { + auto* def_use_mgr = context()->get_def_use_mgr(); + def_use_mgr->ForEachUser(inst, [uses, user_opcode, this](Instruction* user) { + if (user->opcode() == user_opcode) { + uses->push_back(user); + } else if (user->opcode() == SpvOpCopyObject) { + FindUses(user, uses, user_opcode); + } + }); +} + +void ConvertToSampledImagePass::FindUsesOfImage( + const Instruction* image, std::vector* uses) const { + auto* def_use_mgr = context()->get_def_use_mgr(); + def_use_mgr->ForEachUser(image, [uses, this](Instruction* user) { + switch (user->opcode()) { + case SpvOpImageFetch: + case SpvOpImageRead: + case SpvOpImageWrite: + case SpvOpImageQueryFormat: + case SpvOpImageQueryOrder: + case SpvOpImageQuerySizeLod: + case SpvOpImageQuerySize: + case SpvOpImageQueryLevels: + case SpvOpImageQuerySamples: + case SpvOpImageSparseFetch: + uses->push_back(user); + default: + break; + } + if (user->opcode() == SpvOpCopyObject) { + FindUsesOfImage(user, uses); + } + }); +} + +Instruction* ConvertToSampledImagePass::CreateImageExtraction( + Instruction* sampled_image) { + InstructionBuilder builder( + context(), sampled_image->NextNode(), + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + return builder.AddUnaryOp( + GetImageTypeOfSampledImage(context()->get_type_mgr(), sampled_image), + SpvOpImage, sampled_image->result_id()); +} + +uint32_t ConvertToSampledImagePass::GetSampledImageTypeForImage( + Instruction* image_variable) { + const auto* variable_type = GetVariableType(*image_variable); + if (variable_type == nullptr) return 0; + const auto* image_type = variable_type->AsImage(); + if (image_type == nullptr) return 0; + + analysis::Image image_type_for_sampled_image(*image_type); + analysis::SampledImage sampled_image_type(&image_type_for_sampled_image); + return context()->get_type_mgr()->GetTypeInstruction(&sampled_image_type); +} + +Instruction* ConvertToSampledImagePass::UpdateImageUses( + Instruction* sampled_image_load) { + std::vector uses_of_load; + FindUsesOfImage(sampled_image_load, &uses_of_load); + if (uses_of_load.empty()) return nullptr; + + auto* extracted_image = CreateImageExtraction(sampled_image_load); + for (auto* user : uses_of_load) { + user->SetInOperand(0, {extracted_image->result_id()}); + context()->get_def_use_mgr()->AnalyzeInstUse(user); + } + return extracted_image; +} + +bool ConvertToSampledImagePass:: + IsSamplerOfSampledImageDecoratedByDescriptorSetBinding( + Instruction* sampled_image_inst, + const DescriptorSetAndBinding& descriptor_set_binding) { + auto* def_use_mgr = context()->get_def_use_mgr(); + uint32_t sampler_id = sampled_image_inst->GetSingleWordInOperand(1u); + auto* sampler_load = def_use_mgr->GetDef(sampler_id); + if (sampler_load->opcode() != SpvOpLoad) return false; + auto* sampler = def_use_mgr->GetDef(sampler_load->GetSingleWordInOperand(0u)); + DescriptorSetAndBinding sampler_descriptor_set_binding; + return GetDescriptorSetBinding(*sampler, &sampler_descriptor_set_binding) && + sampler_descriptor_set_binding == descriptor_set_binding; +} + +void ConvertToSampledImagePass::UpdateSampledImageUses( + Instruction* image_load, Instruction* image_extraction, + const DescriptorSetAndBinding& image_descriptor_set_binding) { + std::vector sampled_image_users; + FindUses(image_load, &sampled_image_users, SpvOpSampledImage); + + auto* def_use_mgr = context()->get_def_use_mgr(); + for (auto* sampled_image_inst : sampled_image_users) { + if (IsSamplerOfSampledImageDecoratedByDescriptorSetBinding( + sampled_image_inst, image_descriptor_set_binding)) { + context()->ReplaceAllUsesWith(sampled_image_inst->result_id(), + image_load->result_id()); + def_use_mgr->AnalyzeInstUse(image_load); + context()->KillInst(sampled_image_inst); + } else { + if (!image_extraction) + image_extraction = CreateImageExtraction(image_load); + sampled_image_inst->SetInOperand(0, {image_extraction->result_id()}); + def_use_mgr->AnalyzeInstUse(sampled_image_inst); + } + } +} + +void ConvertToSampledImagePass::MoveInstructionNextToType(Instruction* inst, + uint32_t type_id) { + auto* type_inst = context()->get_def_use_mgr()->GetDef(type_id); + inst->SetResultType(type_id); + inst->RemoveFromList(); + inst->InsertAfter(type_inst); +} + +bool ConvertToSampledImagePass::ConvertImageVariableToSampledImage( + Instruction* image_variable, uint32_t sampled_image_type_id) { + auto* sampled_image_type = + context()->get_type_mgr()->GetType(sampled_image_type_id); + if (sampled_image_type == nullptr) return false; + auto storage_class = GetStorageClass(*image_variable); + if (storage_class == SpvStorageClassMax) return false; + analysis::Pointer sampled_image_pointer(sampled_image_type, storage_class); + + // Make sure |image_variable| is behind its type i.e., avoid the forward + // reference. + uint32_t type_id = + context()->get_type_mgr()->GetTypeInstruction(&sampled_image_pointer); + MoveInstructionNextToType(image_variable, type_id); + return true; +} + +Pass::Status ConvertToSampledImagePass::UpdateImageVariableToSampledImage( + Instruction* image_variable, + const DescriptorSetAndBinding& descriptor_set_binding) { + std::vector image_variable_loads; + FindUses(image_variable, &image_variable_loads, SpvOpLoad); + if (image_variable_loads.empty()) return Status::SuccessWithoutChange; + + const uint32_t sampled_image_type_id = + GetSampledImageTypeForImage(image_variable); + if (!sampled_image_type_id) return Status::Failure; + + for (auto* load : image_variable_loads) { + load->SetResultType(sampled_image_type_id); + auto* image_extraction = UpdateImageUses(load); + UpdateSampledImageUses(load, image_extraction, descriptor_set_binding); + } + + return ConvertImageVariableToSampledImage(image_variable, + sampled_image_type_id) + ? Status::SuccessWithChange + : Status::Failure; +} + +bool ConvertToSampledImagePass::DoesSampledImageReferenceImage( + Instruction* sampled_image_inst, Instruction* image_variable) { + if (sampled_image_inst->opcode() != SpvOpSampledImage) return false; + auto* def_use_mgr = context()->get_def_use_mgr(); + auto* image_load = GetNonCopyObjectDef( + def_use_mgr, sampled_image_inst->GetSingleWordInOperand(0u)); + if (image_load->opcode() != SpvOpLoad) return false; + auto* image = + GetNonCopyObjectDef(def_use_mgr, image_load->GetSingleWordInOperand(0u)); + return image->opcode() == SpvOpVariable && + image->result_id() == image_variable->result_id(); +} + +Pass::Status ConvertToSampledImagePass::CheckUsesOfSamplerVariable( + const Instruction* sampler_variable, + Instruction* image_to_be_combined_with) { + if (image_to_be_combined_with == nullptr) return Status::Failure; + + std::vector sampler_variable_loads; + FindUses(sampler_variable, &sampler_variable_loads, SpvOpLoad); + for (auto* load : sampler_variable_loads) { + std::vector sampled_image_users; + FindUses(load, &sampled_image_users, SpvOpSampledImage); + for (auto* sampled_image_inst : sampled_image_users) { + if (!DoesSampledImageReferenceImage(sampled_image_inst, + image_to_be_combined_with)) { + return Status::Failure; + } + } + } + return Status::SuccessWithoutChange; +} + +std::unique_ptr +ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString( + const char* str) { + if (!str) return nullptr; + + auto descriptor_set_binding_pairs = + MakeUnique(); + + while (std::isspace(*str)) str++; // skip leading spaces. + + // The parsing loop, break when points to the end. + while (*str) { + // Parse the descriptor set. + uint32_t descriptor_set = 0; + str = ParseNumberUntilSeparator(str, &descriptor_set); + if (str == nullptr) return nullptr; + + // Find the ':', spaces between the descriptor set and the ':' are not + // allowed. + if (*str++ != ':') { + // ':' not found + return nullptr; + } + + // Parse the binding. + uint32_t binding = 0; + str = ParseNumberUntilSeparator(str, &binding); + if (str == nullptr) return nullptr; + + descriptor_set_binding_pairs->push_back({descriptor_set, binding}); + + // Skip trailing spaces. + while (std::isspace(*str)) str++; + } + + return descriptor_set_binding_pairs; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.h b/third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.h new file mode 100644 index 0000000000..d3938af7dc --- /dev/null +++ b/third_party/spirv-tools/source/opt/convert_to_sampled_image_pass.h @@ -0,0 +1,207 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ +#define SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ + +#include +#include +#include + +#include "source/opt/pass.h" +#include "source/opt/types.h" + +namespace spvtools { +namespace opt { + +// A struct for a pair of descriptor set and binding. +struct DescriptorSetAndBinding { + uint32_t descriptor_set; + uint32_t binding; + + bool operator==(const DescriptorSetAndBinding& descriptor_set_binding) const { + return descriptor_set_binding.descriptor_set == descriptor_set && + descriptor_set_binding.binding == binding; + } +}; + +// See optimizer.hpp for documentation. +class ConvertToSampledImagePass : public Pass { + public: + // Hashing functor for the pair of descriptor set and binding. + struct DescriptorSetAndBindingHash { + size_t operator()( + const DescriptorSetAndBinding& descriptor_set_binding) const { + return std::hash()(descriptor_set_binding.descriptor_set) ^ + std::hash()(descriptor_set_binding.binding); + } + }; + + using SetOfDescriptorSetAndBindingPairs = + std::unordered_set; + using DescriptorSetBindingToInstruction = + std::unordered_map; + + explicit ConvertToSampledImagePass( + const std::vector& descriptor_set_binding_pairs) + : descriptor_set_binding_pairs_(descriptor_set_binding_pairs.begin(), + descriptor_set_binding_pairs.end()) {} + + const char* name() const override { return "convert-to-sampled-image"; } + Status Process() override; + + // Parses the given null-terminated C string to get a vector of descriptor set + // and binding pairs. Returns a unique pointer to the vector of descriptor set + // and binding pairs built from the given |str| on success. Returns a nullptr + // if the given string is not valid for building the vector of pairs. + // A valid string for building the vector of pairs should follow the rule + // below: + // + // ": : ..." + // Example: + // "3:5 2:1 0:4" + // + // Entries are separated with blank spaces (i.e.:' ', '\n', '\r', '\t', + // '\f', '\v'). Each entry corresponds to a descriptor set and binding pair. + // Multiple spaces between, before or after entries are allowed. However, + // spaces are not allowed within a descriptor set or binding. + // + // In each entry, the descriptor set and binding are separated by ':'. + // Missing ':' in any entry is invalid. And it is invalid to have blank + // spaces in between the descriptor set and ':' or ':' and the binding. + // + // : the descriptor set. + // The text must represent a valid uint32_t number. + // + // : the binding. + // The text must represent a valid uint32_t number. + static std::unique_ptr> + ParseDescriptorSetBindingPairsString(const char* str); + + private: + // Collects resources to convert to sampled image and saves them in + // |descriptor_set_binding_pair_to_sampler| if the resource is a sampler and + // saves them in |descriptor_set_binding_pair_to_image| if the resource is an + // image. Returns false if two samplers or two images have the same descriptor + // set and binding. Otherwise, returns true. + bool CollectResourcesToConvert( + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler, + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image) + const; + + // Finds an OpDecorate with DescriptorSet decorating |inst| and another + // OpDecorate with Binding decorating |inst|. Stores the descriptor set and + // binding in |descriptor_set_binding|. Returns whether it successfully finds + // the descriptor set and binding or not. + bool GetDescriptorSetBinding( + const Instruction& inst, + DescriptorSetAndBinding* descriptor_set_binding) const; + + // Returns whether |descriptor_set_binding| is a pair of a descriptor set + // and a binding that we have to convert resources with it to a sampled image + // or not. + bool ShouldResourceBeConverted( + const DescriptorSetAndBinding& descriptor_set_binding) const; + + // Returns the pointee type of the type of variable |variable|. If |variable| + // is not an OpVariable instruction, just returns nullptr. + const analysis::Type* GetVariableType(const Instruction& variable) const; + + // Returns the storage class of |variable|. + SpvStorageClass GetStorageClass(const Instruction& variable) const; + + // Finds |inst|'s users whose opcode is |user_opcode| or users of OpCopyObject + // instructions of |inst| whose opcode is |user_opcode| and puts them in + // |uses|. + void FindUses(const Instruction* inst, std::vector* uses, + uint32_t user_opcode) const; + + // Finds OpImage* instructions using |image| or OpCopyObject instructions that + // copy |image| and puts them in |uses|. + void FindUsesOfImage(const Instruction* image, + std::vector* uses) const; + + // Creates an OpImage instruction that extracts the image from the sampled + // image |sampled_image|. + Instruction* CreateImageExtraction(Instruction* sampled_image); + + // Converts |image_variable| whose type is an image pointer to sampled image + // type. Updates users of |image_variable| accordingly. If some instructions + // e.g., OpImageRead use |image_variable| as an Image operand, creates an + // image extracted from the sampled image using OpImage and replace the Image + // operands of the users with the extracted image. If some OpSampledImage + // instructions use |image_variable| and sampler whose descriptor set and + // binding are the same with |image_variable|, just combines |image_variable| + // and the sampler to a sampled image. + Pass::Status UpdateImageVariableToSampledImage( + Instruction* image_variable, + const DescriptorSetAndBinding& descriptor_set_binding); + + // Returns the id of type sampled image type whose image type is the one of + // |image_variable|. + uint32_t GetSampledImageTypeForImage(Instruction* image_variable); + + // Moves |inst| next to the OpType* instruction with |type_id|. + void MoveInstructionNextToType(Instruction* inst, uint32_t type_id); + + // Converts |image_variable| whose type is an image pointer to sampled image + // with the type id |sampled_image_type_id|. Returns whether it successfully + // converts the type of |image_variable| or not. + bool ConvertImageVariableToSampledImage(Instruction* image_variable, + uint32_t sampled_image_type_id); + + // Replaces |sampled_image_load| instruction used by OpImage* with the image + // extracted from |sampled_image_load|. Returns the extracted image or nullptr + // if it does not have uses. + Instruction* UpdateImageUses(Instruction* sampled_image_load); + + // Returns true if the sampler of |sampled_image_inst| is decorated by a + // descriptor set and a binding |descriptor_set_binding|. + bool IsSamplerOfSampledImageDecoratedByDescriptorSetBinding( + Instruction* sampled_image_inst, + const DescriptorSetAndBinding& descriptor_set_binding); + + // Replaces OpSampledImage instructions using |image_load| with |image_load| + // if the sampler of the OpSampledImage instruction has descriptor set and + // binding |image_descriptor_set_binding|. Otherwise, replaces |image_load| + // with |image_extraction|. + void UpdateSampledImageUses( + Instruction* image_load, Instruction* image_extraction, + const DescriptorSetAndBinding& image_descriptor_set_binding); + + // Checks the uses of |sampler_variable|. When a sampler is used by + // OpSampledImage instruction, the corresponding image must be + // |image_to_be_combined_with| that should be already converted to a sampled + // image by UpdateImageVariableToSampledImage() method. + Pass::Status CheckUsesOfSamplerVariable( + const Instruction* sampler_variable, + Instruction* image_to_be_combined_with); + + // Returns true if Image operand of |sampled_image_inst| is the image of + // |image_variable|. + bool DoesSampledImageReferenceImage(Instruction* sampled_image_inst, + Instruction* image_variable); + + // A set of pairs of descriptor set and binding. If an image and/or a sampler + // have a pair of descriptor set and binding that is an element of + // |descriptor_set_binding_pairs_|, they/it will be converted to a sampled + // image by this pass. + const SetOfDescriptorSetAndBindingPairs descriptor_set_binding_pairs_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp b/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp index 67a97b6af6..62ed5e77ab 100644 --- a/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp +++ b/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp @@ -29,10 +29,10 @@ const uint32_t kCompositeExtractObjectInOperand = 0; const uint32_t kTypePointerStorageClassInIdx = 0; const uint32_t kTypePointerPointeeInIdx = 1; -bool IsOpenCL100DebugDeclareOrValue(Instruction* di) { - auto dbg_opcode = di->GetOpenCL100DebugOpcode(); - return dbg_opcode == OpenCLDebugInfo100DebugDeclare || - dbg_opcode == OpenCLDebugInfo100DebugValue; +bool IsDebugDeclareOrValue(Instruction* di) { + auto dbg_opcode = di->GetCommonDebugOpcode(); + return dbg_opcode == CommonDebugInfoDebugDeclare || + dbg_opcode == CommonDebugInfoDebugValue; } } // namespace @@ -40,6 +40,10 @@ bool IsOpenCL100DebugDeclareOrValue(Instruction* di) { Pass::Status CopyPropagateArrays::Process() { bool modified = false; for (Function& function : *get_module()) { + if (function.IsDeclaration()) { + continue; + } + BasicBlock* entry_bb = &*function.begin(); for (auto var_inst = entry_bb->begin(); var_inst->opcode() == SpvOpVariable; @@ -194,7 +198,7 @@ bool CopyPropagateArrays::HasValidReferencesOnly(Instruction* ptr_inst, return ptr_inst->opcode() == SpvOpVariable && store_inst->GetSingleWordInOperand(kStorePointerInOperand) == ptr_inst->result_id(); - } else if (IsOpenCL100DebugDeclareOrValue(use)) { + } else if (IsDebugDeclareOrValue(use)) { return true; } // Some other instruction. Be conservative. @@ -500,7 +504,7 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst, const_mgr, type](Instruction* use, uint32_t) { - if (IsOpenCL100DebugDeclareOrValue(use)) return true; + if (IsDebugDeclareOrValue(use)) return true; switch (use->opcode()) { case SpvOpLoad: { @@ -592,9 +596,9 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, Instruction* use = pair.first; uint32_t index = pair.second; - if (use->IsOpenCL100DebugInstr()) { - switch (use->GetOpenCL100DebugOpcode()) { - case OpenCLDebugInfo100DebugDeclare: { + if (use->IsCommonDebugInstr()) { + switch (use->GetCommonDebugOpcode()) { + case CommonDebugInfoDebugDeclare: { if (new_ptr_inst->opcode() == SpvOpVariable || new_ptr_inst->opcode() == SpvOpFunctionParameter) { context()->ForgetUses(use); @@ -608,9 +612,8 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, context()->ForgetUses(use); // Change DebugDeclare to DebugValue. - use->SetOperand( - index - 2, - {static_cast(OpenCLDebugInfo100DebugValue)}); + use->SetOperand(index - 2, + {static_cast(CommonDebugInfoDebugValue)}); use->SetOperand(index, {new_ptr_inst->result_id()}); // Add Deref operation. @@ -625,7 +628,7 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, } break; } - case OpenCLDebugInfo100DebugValue: + case CommonDebugInfoDebugValue: context()->ForgetUses(use); use->SetOperand(index, {new_ptr_inst->result_id()}); context()->AnalyzeUses(use); diff --git a/third_party/spirv-tools/source/opt/dataflow.cpp b/third_party/spirv-tools/source/opt/dataflow.cpp new file mode 100644 index 0000000000..c91fad08e7 --- /dev/null +++ b/third_party/spirv-tools/source/opt/dataflow.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/dataflow.h" + +#include +#include + +namespace spvtools { +namespace opt { + +bool DataFlowAnalysis::Enqueue(Instruction* inst) { + bool& is_enqueued = on_worklist_[inst]; + if (is_enqueued) return false; + is_enqueued = true; + worklist_.push(inst); + return true; +} + +DataFlowAnalysis::VisitResult DataFlowAnalysis::RunOnce( + Function* function, bool is_first_iteration) { + InitializeWorklist(function, is_first_iteration); + VisitResult ret = VisitResult::kResultFixed; + while (!worklist_.empty()) { + Instruction* top = worklist_.front(); + worklist_.pop(); + on_worklist_[top] = false; + VisitResult result = Visit(top); + if (result == VisitResult::kResultChanged) { + EnqueueSuccessors(top); + ret = VisitResult::kResultChanged; + } + } + return ret; +} + +void DataFlowAnalysis::Run(Function* function) { + VisitResult result = RunOnce(function, true); + while (result == VisitResult::kResultChanged) { + result = RunOnce(function, false); + } +} + +void ForwardDataFlowAnalysis::InitializeWorklist(Function* function, + bool /*is_first_iteration*/) { + context().cfg()->ForEachBlockInReversePostOrder( + function->entry().get(), [this](BasicBlock* bb) { + if (label_position_ == LabelPosition::kLabelsOnly) { + Enqueue(bb->GetLabelInst()); + return; + } + if (label_position_ == LabelPosition::kLabelsAtBeginning) { + Enqueue(bb->GetLabelInst()); + } + for (Instruction& inst : *bb) { + Enqueue(&inst); + } + if (label_position_ == LabelPosition::kLabelsAtEnd) { + Enqueue(bb->GetLabelInst()); + } + }); +} + +void ForwardDataFlowAnalysis::EnqueueUsers(Instruction* inst) { + context().get_def_use_mgr()->ForEachUser( + inst, [this](Instruction* user) { Enqueue(user); }); +} + +void ForwardDataFlowAnalysis::EnqueueBlockSuccessors(Instruction* inst) { + if (inst->opcode() != SpvOpLabel) return; + context() + .cfg() + ->block(inst->result_id()) + ->ForEachSuccessorLabel([this](uint32_t* label) { + Enqueue(context().cfg()->block(*label)->GetLabelInst()); + }); +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/dataflow.h b/third_party/spirv-tools/source/opt/dataflow.h new file mode 100644 index 0000000000..be07415db5 --- /dev/null +++ b/third_party/spirv-tools/source/opt/dataflow.h @@ -0,0 +1,148 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_DATAFLOW_H_ +#define SOURCE_OPT_DATAFLOW_H_ + +#include +#include +#include + +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +// Generic data-flow analysis. +// Maintains a worklist of instructions to process and processes them in a +// specified order. See also ForwardDataFlowAnalysis, which is specialized for +// forward data-flow analysis. +class DataFlowAnalysis { + public: + // The result of a |Visit| operation on an instruction. + // This is used to determine when analysis has reached a fixpoint. + enum class VisitResult { + // The analysis result for this instruction has changed. + // This means that any instructions that depend on it (its successors) must + // be recomputed. + kResultChanged, + // The analysis result for this instruction has not changed. + // When all visit operations return |kResultFixed|, the analysis has reached + // a fixpoint (converged). + kResultFixed, + }; + + virtual ~DataFlowAnalysis() {} + + // Run this analysis on a given function. + // For analyses which work interprocedurally, |function| may be ignored. + void Run(Function* function); + + protected: + DataFlowAnalysis(IRContext& context) : context_(context) {} + + // Initialize the worklist for a given function. + // |is_first_iteration| is true on the first call to |Run| and false + // afterwards. All subsequent runs are only necessary to check if the analysis + // has converged; if |EnqueueSuccessors| is complete, |InitializeWorklist| + // should do nothing after the first iteration. + virtual void InitializeWorklist(Function* function, + bool is_first_iteration) = 0; + + // Enqueues the successors (instructions which use the analysis result) of + // |inst|. This is not required to be complete, but convergence is faster when + // it is. This is called whenever |Visit| returns |kResultChanged|. + virtual void EnqueueSuccessors(Instruction* inst) = 0; + + // Visits the given instruction, recomputing the analysis result. This is + // called once per instruction queued in |InitializeWorklist| and afterward + // when a predecessor is changed, through |EnqueueSuccessors|. + virtual VisitResult Visit(Instruction* inst) = 0; + + // Enqueues the given instruction to be visited. Ignored if already in the + // worklist. + bool Enqueue(Instruction* inst); + + IRContext& context() { return context_; } + + private: + // Runs one pass, calling |InitializeWorklist| and then iterating through the + // worklist until all fixed. + VisitResult RunOnce(Function* function, bool is_first_iteration); + + IRContext& context_; + std::unordered_map on_worklist_; + // The worklist, which contains the list of instructions to be visited. + // + // The choice of data structure was influenced by the data in "Iterative + // Data-flow Analysis, Revisited" (Cooper et al, 2002). + // https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.125.1549&rep=rep1&type=pdf + // The paper shows that the overall performance benefit of a priority queue + // over a regular queue or stack is relatively small (or negative). + // + // A queue has the advantage that nodes are visited in the same order they are + // enqueued, which relieves the analysis from inserting nodes "backwards", for + // example in worklist initialization. Also, as the paper claims that sorting + // successors does not improve runtime, we can use a single queue which is + // modified during iteration. + std::queue worklist_; +}; + +// A generic data flow analysis, specialized for forward analysis. +class ForwardDataFlowAnalysis : public DataFlowAnalysis { + public: + // Indicates where labels should be in the worklist RPO ordering. + enum class LabelPosition { + // Labels should be placed at the beginning of their blocks. + kLabelsAtBeginning, + // Labels should be placed at the end of their blocks. + kLabelsAtEnd, + // Labels should not be in the worklist. + kNoLabels, + // Only labels should be placed in the worklist. + kLabelsOnly, + }; + + ForwardDataFlowAnalysis(IRContext& context, LabelPosition label_position) + : DataFlowAnalysis(context), label_position_(label_position) {} + + protected: + // Initializes the worklist in reverse postorder, regardless of + // |is_first_iteration|. Labels are placed according to the label position + // specified in the constructor. + void InitializeWorklist(Function* function, bool is_first_iteration) override; + + // Enqueues the users and block successors of the given instruction. + // See |EnqueueUsers| and |EnqueueBlockSuccessors|. + void EnqueueSuccessors(Instruction* inst) override { + EnqueueUsers(inst); + EnqueueBlockSuccessors(inst); + } + + // Enqueues the users of the given instruction. + void EnqueueUsers(Instruction* inst); + + // Enqueues the labels of the successors of the block corresponding to the + // given label instruction. Does nothing for other instructions. + void EnqueueBlockSuccessors(Instruction* inst); + + private: + LabelPosition label_position_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_DATAFLOW_H_ diff --git a/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp b/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp index 0054f57647..356dbcb34a 100644 --- a/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp @@ -346,6 +346,7 @@ bool DeadBranchElimPass::FixPhiNodesInLiveBlocks( if (operands.size() == 4) { // First input data operands is at index 2. uint32_t replId = operands[2u].words[0]; + context()->KillNamesAndDecorates(inst->result_id()); context()->ReplaceAllUsesWith(inst->result_id(), replId); iter = context()->KillInst(&*inst); } else { @@ -419,6 +420,10 @@ bool DeadBranchElimPass::EraseDeadBlocks( } bool DeadBranchElimPass::EliminateDeadBranches(Function* func) { + if (func->IsDeclaration()) { + return false; + } + bool modified = false; std::unordered_set live_blocks; modified |= MarkLiveBlocks(func, &live_blocks); diff --git a/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp b/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp index 46f4f12480..d877f0f96a 100644 --- a/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp @@ -196,7 +196,7 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(Function* func) { } const uint32_t id = ii->result_id(); get_def_use_mgr()->ForEachUser(id, [&ii, this](Instruction* user) { - if (user->IsOpenCL100DebugInstr()) return; + if (user->IsCommonDebugInstr()) return; switch (user->opcode()) { case SpvOpCompositeInsert: case SpvOpPhi: @@ -256,7 +256,7 @@ Pass::Status DeadInsertElimPass::Process() { ProcessFunction pfn = [this](Function* fp) { return EliminateDeadInserts(fp); }; - bool modified = context()->ProcessEntryPointCallTree(pfn); + bool modified = context()->ProcessReachableCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/debug_info_manager.cpp b/third_party/spirv-tools/source/opt/debug_info_manager.cpp index e782641f22..060e0d9312 100644 --- a/third_party/spirv-tools/source/opt/debug_info_manager.cpp +++ b/third_party/spirv-tools/source/opt/debug_info_manager.cpp @@ -18,12 +18,15 @@ #include "source/opt/ir_context.h" -// Constants for OpenCL.DebugInfo.100 extension instructions. +// Constants for OpenCL.DebugInfo.100 & NonSemantic.Shader.DebugInfo.100 +// extension instructions. static const uint32_t kOpLineOperandLineIndex = 1; static const uint32_t kLineOperandIndexDebugFunction = 7; static const uint32_t kLineOperandIndexDebugLexicalBlock = 5; static const uint32_t kDebugFunctionOperandFunctionIndex = 13; +static const uint32_t kDebugFunctionDefinitionOperandDebugFunctionIndex = 4; +static const uint32_t kDebugFunctionDefinitionOperandOpFunctionIndex = 5; static const uint32_t kDebugFunctionOperandParentIndex = 9; static const uint32_t kDebugTypeCompositeOperandParentIndex = 9; static const uint32_t kDebugLexicalBlockOperandParentIndex = 7; @@ -46,8 +49,8 @@ namespace { void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) { assert(dbg_inlined_at); - assert(dbg_inlined_at->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInlinedAt); + assert(dbg_inlined_at->GetCommonDebugOpcode() == + CommonDebugInfoDebugInlinedAt); if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) { dbg_inlined_at->AddOperand( {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inlined_operand}}); @@ -59,8 +62,8 @@ void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) { uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) { assert(dbg_inlined_at); - assert(dbg_inlined_at->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInlinedAt); + assert(dbg_inlined_at->GetCommonDebugOpcode() == + CommonDebugInfoDebugInlinedAt); if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) return kNoInlinedAt; return dbg_inlined_at->GetSingleWordOperand( @@ -68,8 +71,7 @@ uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) { } bool IsEmptyDebugExpression(Instruction* instr) { - return instr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugExpression && + return (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression) && instr->NumOperands() == kDebugExpressOperandOperationIndex; } @@ -79,43 +81,63 @@ DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) { AnalyzeDebugInsts(*c->module()); } +uint32_t DebugInfoManager::GetDbgSetImportId() { + uint32_t setId = + context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo(); + if (setId == 0) { + setId = + context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo(); + } + return setId; +} + Instruction* DebugInfoManager::GetDbgInst(uint32_t id) { auto dbg_inst_it = id_to_dbg_inst_.find(id); return dbg_inst_it == id_to_dbg_inst_.end() ? nullptr : dbg_inst_it->second; } void DebugInfoManager::RegisterDbgInst(Instruction* inst) { - assert( - inst->NumInOperands() != 0 && - context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() == - inst->GetInOperand(0).words[0] && - "Given instruction is not a debug instruction"); + assert(inst->NumInOperands() != 0 && + (GetDbgSetImportId() == inst->GetInOperand(0).words[0]) && + "Given instruction is not a debug instruction"); id_to_dbg_inst_[inst->result_id()] = inst; } void DebugInfoManager::RegisterDbgFunction(Instruction* inst) { - assert(inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction && - "inst is not a DebugFunction"); - auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex); - // Do not register function that has been optimized away - auto fn_inst = GetDbgInst(fn_id); - if (fn_inst != nullptr) { - assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInfoNone); - return; + if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) { + auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex); + // Do not register function that has been optimized away. + auto fn_inst = GetDbgInst(fn_id); + if (fn_inst != nullptr) { + assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() == + OpenCLDebugInfo100DebugInfoNone); + return; + } + assert( + fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() && + "Register DebugFunction for a function that already has DebugFunction"); + fn_id_to_dbg_fn_[fn_id] = inst; + } else if (inst->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugFunctionDefinition) { + auto fn_id = inst->GetSingleWordOperand( + kDebugFunctionDefinitionOperandOpFunctionIndex); + auto fn_inst = GetDbgInst(inst->GetSingleWordOperand( + kDebugFunctionDefinitionOperandDebugFunctionIndex)); + assert(fn_inst && fn_inst->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugFunction); + assert(fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() && + "Register DebugFunctionDefinition for a function that already has " + "DebugFunctionDefinition"); + fn_id_to_dbg_fn_[fn_id] = fn_inst; + } else { + assert(false && "inst is not a DebugFunction"); } - assert( - fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() && - "Register DebugFunction for a function that already has DebugFunction"); - fn_id_to_dbg_fn_[fn_id] = inst; } void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id, Instruction* dbg_declare) { - assert(dbg_declare->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugDeclare || - dbg_declare->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugValue); + assert(dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare || + dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugValue); auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_id); if (dbg_decl_itr == var_id_to_dbg_decl_.end()) { var_id_to_dbg_decl_[var_id] = {dbg_declare}; @@ -124,29 +146,57 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id, } } +// Create new constant directly into global value area, bypassing the +// Constant manager. This is used when the DefUse or Constant managers +// are invalid and cannot be regenerated due to the module being in an +// inconsistant state e.g. in the middle of significant modification +// such as inlining. Invalidate Constant and DefUse managers if used. +uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) { + uint32_t id = context->TakeNextId(); + std::unique_ptr new_const(new Instruction( + context, SpvOpConstant, context->get_type_mgr()->GetUIntTypeId(), id, + { + {spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, + {const_value}}, + })); + context->module()->AddGlobalValue(std::move(new_const)); + context->InvalidateAnalyses(IRContext::kAnalysisConstants); + context->InvalidateAnalyses(IRContext::kAnalysisDefUse); + return id; +} + uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line, const DebugScope& scope) { - if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() == - 0) - return kNoInlinedAt; + uint32_t setId = GetDbgSetImportId(); + + if (setId == 0) return kNoInlinedAt; + + spv_operand_type_t line_number_type = + spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER; + + // In NonSemantic.Shader.DebugInfo.100, all constants are IDs of OpConstant, + // not literals. + if (setId == + context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) + line_number_type = spv_operand_type_t::SPV_OPERAND_TYPE_ID; uint32_t line_number = 0; if (line == nullptr) { auto* lexical_scope_inst = GetDbgInst(scope.GetLexicalScope()); if (lexical_scope_inst == nullptr) return kNoInlinedAt; - OpenCLDebugInfo100Instructions debug_opcode = - lexical_scope_inst->GetOpenCL100DebugOpcode(); + CommonDebugInfoInstructions debug_opcode = + lexical_scope_inst->GetCommonDebugOpcode(); switch (debug_opcode) { - case OpenCLDebugInfo100DebugFunction: + case CommonDebugInfoDebugFunction: line_number = lexical_scope_inst->GetSingleWordOperand( kLineOperandIndexDebugFunction); break; - case OpenCLDebugInfo100DebugLexicalBlock: + case CommonDebugInfoDebugLexicalBlock: line_number = lexical_scope_inst->GetSingleWordOperand( kLineOperandIndexDebugLexicalBlock); break; - case OpenCLDebugInfo100DebugTypeComposite: - case OpenCLDebugInfo100DebugCompilationUnit: + case CommonDebugInfoDebugTypeComposite: + case CommonDebugInfoDebugCompilationUnit: assert(false && "DebugTypeComposite and DebugCompilationUnit are lexical " "scopes, but we inline functions into a function or a block " @@ -161,6 +211,21 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line, } } else { line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex); + + // If we need the line number as an ID, generate that constant now. + // If Constant or DefUse managers are invalid, generate constant + // directly into the global value section of the module; do not + // use Constant manager which may attempt to invoke building of the + // DefUse manager which cannot be done during inlining. The extra + // constants that may be generated here is likely not significant + // and will likely be cleaned up in later passes. + if (line_number_type == spv_operand_type_t::SPV_OPERAND_TYPE_ID) { + if (!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse) || + !context()->AreAnalysesValid(IRContext::Analysis::kAnalysisConstants)) + line_number = AddNewConstInGlobals(context(), line_number); + else + line_number = context()->get_constant_mgr()->GetUIntConst(line_number); + } } uint32_t result_id = context()->TakeNextId(); @@ -168,13 +233,10 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line, context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), result_id, { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {setId}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugInlinedAt)}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}}, + {static_cast(CommonDebugInfoDebugInlinedAt)}}, + {line_number_type, {line_number}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}}, })); // |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt @@ -257,19 +319,34 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() { if (deref_operation_ != nullptr) return deref_operation_; uint32_t result_id = context()->TakeNextId(); - std::unique_ptr deref_operation(new Instruction( - context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), - result_id, - { - {SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, - {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugOperation)}}, - {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, - {static_cast(OpenCLDebugInfo100Deref)}}, - })); + std::unique_ptr deref_operation; + + if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) { + deref_operation = std::unique_ptr(new Instruction( + context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), + result_id, + { + {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast(OpenCLDebugInfo100DebugOperation)}}, + {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, + {static_cast(OpenCLDebugInfo100Deref)}}, + })); + } else { + uint32_t deref_id = context()->get_constant_mgr()->GetUIntConst( + NonSemanticShaderDebugInfo100Deref); + + deref_operation = std::unique_ptr( + new Instruction(context(), SpvOpExtInst, + context()->get_type_mgr()->GetVoidTypeId(), result_id, + { + {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast( + NonSemanticShaderDebugInfo100DebugOperation)}}, + {SPV_OPERAND_TYPE_ID, {deref_id}}, + })); + } // Add to the front of |ext_inst_debuginfo_|. deref_operation_ = @@ -283,8 +360,7 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() { } Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) { - assert(dbg_expr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugExpression); + assert(dbg_expr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression); std::unique_ptr deref_expr(dbg_expr->Clone(context())); deref_expr->SetResultId(context()->TakeNextId()); deref_expr->InsertOperand( @@ -306,12 +382,9 @@ Instruction* DebugInfoManager::GetDebugInfoNone() { context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), result_id, { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugInfoNone)}}, + {static_cast(CommonDebugInfoDebugInfoNone)}}, })); // Add to the front of |ext_inst_debuginfo_|. @@ -333,12 +406,9 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() { context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), result_id, { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugExpression)}}, + {static_cast(CommonDebugInfoDebugExpression)}}, })); // Add to the front of |ext_inst_debuginfo_|. @@ -355,8 +425,7 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() { Instruction* DebugInfoManager::GetDebugInlinedAt(uint32_t dbg_inlined_at_id) { auto* inlined_at = GetDbgInst(dbg_inlined_at_id); if (inlined_at == nullptr) return nullptr; - if (inlined_at->GetOpenCL100DebugOpcode() != - OpenCLDebugInfo100DebugInlinedAt) { + if (inlined_at->GetCommonDebugOpcode() != CommonDebugInfoDebugInlinedAt) { return nullptr; } return inlined_at; @@ -403,23 +472,23 @@ bool DebugInfoManager::KillDebugDeclares(uint32_t variable_id) { uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) { auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope); assert(dbg_scope_itr != id_to_dbg_inst_.end()); - OpenCLDebugInfo100Instructions debug_opcode = - dbg_scope_itr->second->GetOpenCL100DebugOpcode(); + CommonDebugInfoInstructions debug_opcode = + dbg_scope_itr->second->GetCommonDebugOpcode(); uint32_t parent_scope = kNoDebugScope; switch (debug_opcode) { - case OpenCLDebugInfo100DebugFunction: + case CommonDebugInfoDebugFunction: parent_scope = dbg_scope_itr->second->GetSingleWordOperand( kDebugFunctionOperandParentIndex); break; - case OpenCLDebugInfo100DebugLexicalBlock: + case CommonDebugInfoDebugLexicalBlock: parent_scope = dbg_scope_itr->second->GetSingleWordOperand( kDebugLexicalBlockOperandParentIndex); break; - case OpenCLDebugInfo100DebugTypeComposite: + case CommonDebugInfoDebugTypeComposite: parent_scope = dbg_scope_itr->second->GetSingleWordOperand( kDebugTypeCompositeOperandParentIndex); break; - case OpenCLDebugInfo100DebugCompilationUnit: + case CommonDebugInfoDebugCompilationUnit: // DebugCompilationUnit does not have a parent scope. break; default: @@ -513,8 +582,7 @@ Instruction* DebugInfoManager::AddDebugValueForDecl( std::unique_ptr dbg_val(dbg_decl->Clone(context())); dbg_val->SetResultId(context()->TakeNextId()); - dbg_val->SetInOperand(kExtInstInstructionInIdx, - {OpenCLDebugInfo100DebugValue}); + dbg_val->SetInOperand(kExtInstInstructionInIdx, {CommonDebugInfoDebugValue}); dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id}); dbg_val->SetOperand(kDebugValueOperandExpressionIndex, {GetEmptyDebugExpression()->result_id()}); @@ -532,9 +600,20 @@ Instruction* DebugInfoManager::AddDebugValueForDecl( return added_dbg_val; } +uint32_t DebugInfoManager::GetVulkanDebugOperation(Instruction* inst) { + assert(inst->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugOperation && + "inst must be Vulkan DebugOperation"); + return context() + ->get_constant_mgr() + ->GetConstantFromInst(context()->get_def_use_mgr()->GetDef( + inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex))) + ->GetU32(); +} + uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare( Instruction* inst) { - if (inst->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugValue) return 0; + if (inst->GetCommonDebugOpcode() != CommonDebugInfoDebugValue) return 0; auto* expr = GetDbgInst(inst->GetSingleWordOperand(kDebugValueOperandExpressionIndex)); @@ -544,9 +623,19 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare( auto* operation = GetDbgInst( expr->GetSingleWordOperand(kDebugExpressOperandOperationIndex)); if (operation == nullptr) return 0; - if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) != - OpenCLDebugInfo100Deref) { - return 0; + + // OpenCL.DebugInfo.100 contains a literal for the operation, Vulkan uses an + // OpConstant. + if (inst->IsOpenCL100DebugInstr()) { + if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) != + OpenCLDebugInfo100Deref) { + return 0; + } + } else { + uint32_t operation_const = GetVulkanDebugOperation(operation); + if (operation_const != NonSemanticShaderDebugInfo100Deref) { + return 0; + } } uint32_t var_id = @@ -567,8 +656,8 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare( } bool DebugInfoManager::IsDebugDeclare(Instruction* instr) { - if (!instr->IsOpenCL100DebugInstr()) return false; - return instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare || + if (!instr->IsCommonDebugInstr()) return false; + return instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare || GetVariableIdOfDebugValueUsedForDeclare(instr) != 0; } @@ -615,14 +704,13 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { users.insert(inst); } - if (!inst->IsOpenCL100DebugInstr()) return; + if (!inst->IsCommonDebugInstr()) return; RegisterDbgInst(inst); - if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) { - assert(GetDebugFunction(inst->GetSingleWordOperand( - kDebugFunctionOperandFunctionIndex)) == nullptr && - "Two DebugFunction instruction exists for a single OpFunction."); + if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction || + inst->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugFunctionDefinition) { RegisterDbgFunction(inst); } @@ -633,8 +721,17 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { deref_operation_ = inst; } + if (deref_operation_ == nullptr && + inst->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugOperation) { + uint32_t operation_const = GetVulkanDebugOperation(inst); + if (operation_const == NonSemanticShaderDebugInfo100Deref) { + deref_operation_ = inst; + } + } + if (debug_info_none_inst_ == nullptr && - inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) { + inst->GetCommonDebugOpcode() == CommonDebugInfoDebugInfoNone) { debug_info_none_inst_ = inst; } @@ -642,7 +739,7 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { empty_debug_expr_inst_ = inst; } - if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) { + if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) { uint32_t var_id = inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); RegisterDbgDeclare(var_id, inst); @@ -655,8 +752,8 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { void DebugInfoManager::ConvertDebugGlobalToLocalVariable( Instruction* dbg_global_var, Instruction* local_var) { - if (dbg_global_var->GetOpenCL100DebugOpcode() != - OpenCLDebugInfo100DebugGlobalVariable) { + if (dbg_global_var->GetCommonDebugOpcode() != + CommonDebugInfoDebugGlobalVariable) { return; } assert(local_var->opcode() == SpvOpVariable || @@ -664,7 +761,7 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable( // Convert |dbg_global_var| to DebugLocalVariable dbg_global_var->SetInOperand(kExtInstInstructionInIdx, - {OpenCLDebugInfo100DebugLocalVariable}); + {CommonDebugInfoDebugLocalVariable}); auto flags = dbg_global_var->GetSingleWordOperand( kDebugGlobalVariableOperandFlagsIndex); for (uint32_t i = dbg_global_var->NumInOperands() - 1; @@ -680,20 +777,20 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable( context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), context()->TakeNextId(), { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugDeclare)}}, + {static_cast(CommonDebugInfoDebugDeclare)}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {dbg_global_var->result_id()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {local_var->result_id()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetEmptyDebugExpression()->result_id()}}, })); - auto* added_dbg_decl = - local_var->NextNode()->InsertBefore(std::move(new_dbg_decl)); + // Must insert after all OpVariables in block + Instruction* insert_before = local_var; + while (insert_before->opcode() == SpvOpVariable) + insert_before = insert_before->NextNode(); + auto* added_dbg_decl = insert_before->InsertBefore(std::move(new_dbg_decl)); if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_decl); if (context()->AreAnalysesValid( @@ -713,7 +810,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) { // list. if (empty_debug_expr_inst_ != nullptr && empty_debug_expr_inst_->PreviousNode() != nullptr && - empty_debug_expr_inst_->PreviousNode()->IsOpenCL100DebugInstr()) { + empty_debug_expr_inst_->PreviousNode()->IsCommonDebugInstr()) { empty_debug_expr_inst_->InsertBefore( &*context()->module()->ext_inst_debuginfo_begin()); } @@ -722,7 +819,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) { // list. if (debug_info_none_inst_ != nullptr && debug_info_none_inst_->PreviousNode() != nullptr && - debug_info_none_inst_->PreviousNode()->IsOpenCL100DebugInstr()) { + debug_info_none_inst_->PreviousNode()->IsCommonDebugInstr()) { debug_info_none_inst_->InsertBefore( &*context()->module()->ext_inst_debuginfo_begin()); } @@ -740,7 +837,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { inlinedat_id_to_users_itr->second.erase(instr); } - if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) { + if (instr == nullptr || !instr->IsCommonDebugInstr()) { return; } @@ -751,9 +848,15 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { instr->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex); fn_id_to_dbg_fn_.erase(fn_id); } + if (instr->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugFunction) { + auto fn_id = instr->GetSingleWordOperand( + kDebugFunctionDefinitionOperandOpFunctionIndex); + fn_id_to_dbg_fn_.erase(fn_id); + } - if (instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare || - instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) { + if (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare || + instr->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) { auto var_or_value_id = instr->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_or_value_id); @@ -767,6 +870,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin(); dbg_instr_itr != context()->module()->ext_inst_debuginfo_end(); ++dbg_instr_itr) { + // OpenCL.DebugInfo.100 contains the operation as a literal operand, in + // Vulkan it's referenced as an OpConstant. if (instr != &*dbg_instr_itr && dbg_instr_itr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation && @@ -775,6 +880,14 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { OpenCLDebugInfo100Deref) { deref_operation_ = &*dbg_instr_itr; break; + } else if (instr != &*dbg_instr_itr && + dbg_instr_itr->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugOperation) { + uint32_t operation_const = GetVulkanDebugOperation(&*dbg_instr_itr); + if (operation_const == NonSemanticShaderDebugInfo100Deref) { + deref_operation_ = &*dbg_instr_itr; + break; + } } } } @@ -784,9 +897,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin(); dbg_instr_itr != context()->module()->ext_inst_debuginfo_end(); ++dbg_instr_itr) { - if (instr != &*dbg_instr_itr && - dbg_instr_itr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInfoNone) { + if (instr != &*dbg_instr_itr && dbg_instr_itr->GetCommonDebugOpcode() == + CommonDebugInfoDebugInfoNone) { debug_info_none_inst_ = &*dbg_instr_itr; break; } diff --git a/third_party/spirv-tools/source/opt/debug_info_manager.h b/third_party/spirv-tools/source/opt/debug_info_manager.h index 776e9baab5..df34b30f40 100644 --- a/third_party/spirv-tools/source/opt/debug_info_manager.h +++ b/third_party/spirv-tools/source/opt/debug_info_manager.h @@ -67,8 +67,8 @@ class DebugInlinedAtContext { std::unordered_map callee_inlined_at2chain_; }; -// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 extension -// instructions. +// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 and +// NonSemantic.Shader.DebugInfo.100 extension instructions. class DebugInfoManager { public: // Constructs a debug information manager from the given |context|. @@ -85,7 +85,7 @@ class DebugInfoManager { return !(lhs == rhs); } - // Analyzes OpenCL.DebugInfo.100 instruction |dbg_inst|. + // Analyzes DebugInfo instruction |dbg_inst|. void AnalyzeDebugInst(Instruction* dbg_inst); // Creates new DebugInlinedAt and returns its id. Its line operand is the @@ -164,6 +164,9 @@ class DebugInfoManager { // Erases |instr| from data structures of this class. void ClearDebugInfo(Instruction* instr); + // Return the opcode for the Vulkan DebugOperation inst + uint32_t GetVulkanDebugOperation(Instruction* inst); + // Returns the id of Value operand if |inst| is DebugValue who has Deref // operation and its Value operand is a result id of OpVariable with // Function storage class. Otherwise, returns 0. @@ -190,10 +193,13 @@ class DebugInfoManager { private: IRContext* context() { return context_; } - // Analyzes OpenCL.DebugInfo.100 instructions in the given |module| and + // Analyzes DebugInfo instructions in the given |module| and // populates data structures in this class. void AnalyzeDebugInsts(Module& module); + // Get the DebugInfo ExtInstImport Id, or 0 if no DebugInfo is available. + uint32_t GetDbgSetImportId(); + // Returns the debug instruction whose id is |id|. Returns |nullptr| if one // does not exists. Instruction* GetDbgInst(uint32_t id); @@ -230,7 +236,7 @@ class DebugInfoManager { IRContext* context_; - // Mapping from ids of OpenCL.DebugInfo.100 extension instructions + // Mapping from ids of DebugInfo extension instructions. // to their Instruction instances. std::unordered_map id_to_dbg_inst_; diff --git a/third_party/spirv-tools/source/opt/decoration_manager.cpp b/third_party/spirv-tools/source/opt/decoration_manager.cpp index 4bf026efd8..2146c359d6 100644 --- a/third_party/spirv-tools/source/opt/decoration_manager.cpp +++ b/third_party/spirv-tools/source/opt/decoration_manager.cpp @@ -490,6 +490,14 @@ void DecorationManager::ForEachDecoration( }); } +bool DecorationManager::HasDecoration(uint32_t id, uint32_t decoration) { + bool has_decoration = false; + ForEachDecoration(id, decoration, [&has_decoration](const Instruction&) { + has_decoration = true; + }); + return has_decoration; +} + bool DecorationManager::FindDecoration( uint32_t id, uint32_t decoration, std::function f) { diff --git a/third_party/spirv-tools/source/opt/decoration_manager.h b/third_party/spirv-tools/source/opt/decoration_manager.h index b753e6be1d..fe78f2ce68 100644 --- a/third_party/spirv-tools/source/opt/decoration_manager.h +++ b/third_party/spirv-tools/source/opt/decoration_manager.h @@ -90,6 +90,10 @@ class DecorationManager { bool AreDecorationsTheSame(const Instruction* inst1, const Instruction* inst2, bool ignore_target) const; + // Returns whether a decoration instruction for |id| with decoration + // |decoration| exists or not. + bool HasDecoration(uint32_t id, uint32_t decoration); + // |f| is run on each decoration instruction for |id| with decoration // |decoration|. Processed are all decorations which target |id| either // directly or indirectly by Decoration Groups. diff --git a/third_party/spirv-tools/source/opt/def_use_manager.cpp b/third_party/spirv-tools/source/opt/def_use_manager.cpp index 0ec98cae10..394b9fa174 100644 --- a/third_party/spirv-tools/source/opt/def_use_manager.cpp +++ b/third_party/spirv-tools/source/opt/def_use_manager.cpp @@ -58,7 +58,7 @@ void DefUseManager::AnalyzeInstUse(Instruction* inst) { case SPV_OPERAND_TYPE_SCOPE_ID: { uint32_t use_id = inst->GetSingleWordOperand(i); Instruction* def = GetDef(use_id); - assert(def && "Definition is not registered."); + if (!def) assert(false && "Definition is not registered."); id_to_users_.insert(UserEntry(def, inst)); used_ids->push_back(use_id); } break; @@ -71,6 +71,9 @@ void DefUseManager::AnalyzeInstUse(Instruction* inst) { void DefUseManager::AnalyzeInstDefUse(Instruction* inst) { AnalyzeInstDef(inst); AnalyzeInstUse(inst); + // Analyze lines last otherwise they will be cleared when inst is + // cleared by preceding two calls + for (auto& l_inst : inst->dbg_line_insts()) AnalyzeInstDefUse(&l_inst); } void DefUseManager::UpdateDefUse(Instruction* inst) { @@ -224,9 +227,11 @@ void DefUseManager::AnalyzeDefUse(Module* module) { if (!module) return; // Analyze all the defs before any uses to catch forward references. module->ForEachInst( - std::bind(&DefUseManager::AnalyzeInstDef, this, std::placeholders::_1)); + std::bind(&DefUseManager::AnalyzeInstDef, this, std::placeholders::_1), + true); module->ForEachInst( - std::bind(&DefUseManager::AnalyzeInstUse, this, std::placeholders::_1)); + std::bind(&DefUseManager::AnalyzeInstUse, this, std::placeholders::_1), + true); } void DefUseManager::ClearInst(Instruction* inst) { @@ -261,6 +266,16 @@ void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) { bool operator==(const DefUseManager& lhs, const DefUseManager& rhs) { if (lhs.id_to_def_ != rhs.id_to_def_) { + for (auto p : lhs.id_to_def_) { + if (rhs.id_to_def_.find(p.first) == rhs.id_to_def_.end()) { + return false; + } + } + for (auto p : rhs.id_to_def_) { + if (lhs.id_to_def_.find(p.first) == lhs.id_to_def_.end()) { + return false; + } + } return false; } diff --git a/third_party/spirv-tools/source/opt/desc_sroa.cpp b/third_party/spirv-tools/source/opt/desc_sroa.cpp index 5e950069da..bcbdde94ca 100644 --- a/third_party/spirv-tools/source/opt/desc_sroa.cpp +++ b/third_party/spirv-tools/source/opt/desc_sroa.cpp @@ -14,10 +14,19 @@ #include "source/opt/desc_sroa.h" +#include "source/opt/desc_sroa_util.h" #include "source/util/string_utils.h" namespace spvtools { namespace opt { +namespace { + +bool IsDecorationBinding(Instruction* inst) { + if (inst->opcode() != SpvOpDecorate) return false; + return inst->GetSingleWordInOperand(1u) == SpvDecorationBinding; +} + +} // namespace Pass::Status DescriptorScalarReplacement::Process() { bool modified = false; @@ -25,7 +34,7 @@ Pass::Status DescriptorScalarReplacement::Process() { std::vector vars_to_kill; for (Instruction& var : context()->types_values()) { - if (IsCandidate(&var)) { + if (descsroautil::IsDescriptorArray(context(), &var)) { modified = true; if (!ReplaceCandidate(&var)) { return Status::Failure; @@ -41,72 +50,6 @@ Pass::Status DescriptorScalarReplacement::Process() { return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); } -bool DescriptorScalarReplacement::IsCandidate(Instruction* var) { - if (var->opcode() != SpvOpVariable) { - return false; - } - - uint32_t ptr_type_id = var->type_id(); - Instruction* ptr_type_inst = - context()->get_def_use_mgr()->GetDef(ptr_type_id); - if (ptr_type_inst->opcode() != SpvOpTypePointer) { - return false; - } - - uint32_t var_type_id = ptr_type_inst->GetSingleWordInOperand(1); - Instruction* var_type_inst = - context()->get_def_use_mgr()->GetDef(var_type_id); - if (var_type_inst->opcode() != SpvOpTypeArray && - var_type_inst->opcode() != SpvOpTypeStruct) { - return false; - } - - // All structures with descriptor assignments must be replaced by variables, - // one for each of their members - with the exceptions of buffers. - if (IsTypeOfStructuredBuffer(var_type_inst)) { - return false; - } - - bool has_desc_set_decoration = false; - context()->get_decoration_mgr()->ForEachDecoration( - var->result_id(), SpvDecorationDescriptorSet, - [&has_desc_set_decoration](const Instruction&) { - has_desc_set_decoration = true; - }); - if (!has_desc_set_decoration) { - return false; - } - - bool has_binding_decoration = false; - context()->get_decoration_mgr()->ForEachDecoration( - var->result_id(), SpvDecorationBinding, - [&has_binding_decoration](const Instruction&) { - has_binding_decoration = true; - }); - if (!has_binding_decoration) { - return false; - } - - return true; -} - -bool DescriptorScalarReplacement::IsTypeOfStructuredBuffer( - const Instruction* type) const { - if (type->opcode() != SpvOpTypeStruct) { - return false; - } - - // All buffers have offset decorations for members of their structure types. - // This is how we distinguish it from a structure of descriptors. - bool has_offset_decoration = false; - context()->get_decoration_mgr()->ForEachDecoration( - type->result_id(), SpvDecorationOffset, - [&has_offset_decoration](const Instruction&) { - has_offset_decoration = true; - }); - return has_offset_decoration; -} - bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) { std::vector access_chain_work_list; std::vector load_work_list; @@ -162,16 +105,15 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var, return false; } - uint32_t idx_id = use->GetSingleWordInOperand(1); - const analysis::Constant* idx_const = - context()->get_constant_mgr()->FindDeclaredConstant(idx_id); - if (idx_const == nullptr) { + const analysis::Constant* const_index = + descsroautil::GetAccessChainIndexAsConst(context(), use); + if (const_index == nullptr) { context()->EmitErrorMessage("Variable cannot be replaced: invalid index", use); return false; } - uint32_t idx = idx_const->GetU32(); + uint32_t idx = const_index->GetU32(); uint32_t replacement_var = GetReplacementVariable(var, idx); if (use->NumInOperands() == 2) { @@ -208,39 +150,12 @@ uint32_t DescriptorScalarReplacement::GetReplacementVariable(Instruction* var, uint32_t idx) { auto replacement_vars = replacement_variables_.find(var); if (replacement_vars == replacement_variables_.end()) { - uint32_t ptr_type_id = var->type_id(); - Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id); - assert(ptr_type_inst->opcode() == SpvOpTypePointer && - "Variable should be a pointer to an array or structure."); - uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1); - Instruction* pointee_type_inst = get_def_use_mgr()->GetDef(pointee_type_id); - const bool is_array = pointee_type_inst->opcode() == SpvOpTypeArray; - const bool is_struct = pointee_type_inst->opcode() == SpvOpTypeStruct; - assert((is_array || is_struct) && - "Variable should be a pointer to an array or structure."); - - // For arrays, each array element should be replaced with a new replacement - // variable - if (is_array) { - uint32_t array_len_id = pointee_type_inst->GetSingleWordInOperand(1); - const analysis::Constant* array_len_const = - context()->get_constant_mgr()->FindDeclaredConstant(array_len_id); - assert(array_len_const != nullptr && "Array length must be a constant."); - uint32_t array_len = array_len_const->GetU32(); - - replacement_vars = replacement_variables_ - .insert({var, std::vector(array_len, 0)}) - .first; - } - // For structures, each member should be replaced with a new replacement - // variable - if (is_struct) { - const uint32_t num_members = pointee_type_inst->NumInOperands(); - replacement_vars = - replacement_variables_ - .insert({var, std::vector(num_members, 0)}) - .first; - } + uint32_t number_of_elements = + descsroautil::GetNumberOfElementsForArrayOrStruct(context(), var); + replacement_vars = + replacement_variables_ + .insert({var, std::vector(number_of_elements, 0)}) + .first; } if (replacement_vars->second[idx] == 0) { @@ -250,6 +165,74 @@ uint32_t DescriptorScalarReplacement::GetReplacementVariable(Instruction* var, return replacement_vars->second[idx]; } +void DescriptorScalarReplacement::CopyDecorationsForNewVariable( + Instruction* old_var, uint32_t index, uint32_t new_var_id, + uint32_t new_var_ptr_type_id, const bool is_old_var_array, + const bool is_old_var_struct, Instruction* old_var_type) { + // Handle OpDecorate instructions. + for (auto old_decoration : + get_decoration_mgr()->GetDecorationsFor(old_var->result_id(), true)) { + uint32_t new_binding = 0; + if (IsDecorationBinding(old_decoration)) { + new_binding = GetNewBindingForElement( + old_decoration->GetSingleWordInOperand(2), index, new_var_ptr_type_id, + is_old_var_array, is_old_var_struct, old_var_type); + } + CreateNewDecorationForNewVariable(old_decoration, new_var_id, new_binding); + } + + // Handle OpMemberDecorate instructions. + for (auto old_decoration : get_decoration_mgr()->GetDecorationsFor( + old_var_type->result_id(), true)) { + assert(old_decoration->opcode() == SpvOpMemberDecorate); + if (old_decoration->GetSingleWordInOperand(1u) != index) continue; + CreateNewDecorationForMemberDecorate(old_decoration, new_var_id); + } +} + +uint32_t DescriptorScalarReplacement::GetNewBindingForElement( + uint32_t old_binding, uint32_t index, uint32_t new_var_ptr_type_id, + const bool is_old_var_array, const bool is_old_var_struct, + Instruction* old_var_type) { + if (is_old_var_array) { + return old_binding + index * GetNumBindingsUsedByType(new_var_ptr_type_id); + } + if (is_old_var_struct) { + // The binding offset that should be added is the sum of binding + // numbers used by previous members of the current struct. + uint32_t new_binding = old_binding; + for (uint32_t i = 0; i < index; ++i) { + new_binding += + GetNumBindingsUsedByType(old_var_type->GetSingleWordInOperand(i)); + } + return new_binding; + } + return old_binding; +} + +void DescriptorScalarReplacement::CreateNewDecorationForNewVariable( + Instruction* old_decoration, uint32_t new_var_id, uint32_t new_binding) { + assert(old_decoration->opcode() == SpvOpDecorate); + std::unique_ptr new_decoration(old_decoration->Clone(context())); + new_decoration->SetInOperand(0, {new_var_id}); + + if (IsDecorationBinding(new_decoration.get())) { + new_decoration->SetInOperand(2, {new_binding}); + } + context()->AddAnnotationInst(std::move(new_decoration)); +} + +void DescriptorScalarReplacement::CreateNewDecorationForMemberDecorate( + Instruction* old_member_decoration, uint32_t new_var_id) { + std::vector operands( + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {new_var_id}}}); + auto new_decorate_operand_begin = old_member_decoration->begin() + 2u; + auto new_decorate_operand_end = old_member_decoration->end(); + operands.insert(operands.end(), new_decorate_operand_begin, + new_decorate_operand_end); + get_decoration_mgr()->AddDecoration(SpvOpDecorate, std::move(operands)); +} + uint32_t DescriptorScalarReplacement::CreateReplacementVariable( Instruction* var, uint32_t idx) { // The storage class for the new variable is the same as the original. @@ -285,33 +268,8 @@ uint32_t DescriptorScalarReplacement::CreateReplacementVariable( {static_cast(storage_class)}}})); context()->AddGlobalValue(std::move(variable)); - // Copy all of the decorations to the new variable. The only difference is - // the Binding decoration needs to be adjusted. - for (auto old_decoration : - get_decoration_mgr()->GetDecorationsFor(var->result_id(), true)) { - assert(old_decoration->opcode() == SpvOpDecorate); - std::unique_ptr new_decoration( - old_decoration->Clone(context())); - new_decoration->SetInOperand(0, {id}); - - uint32_t decoration = new_decoration->GetSingleWordInOperand(1u); - if (decoration == SpvDecorationBinding) { - uint32_t new_binding = new_decoration->GetSingleWordInOperand(2); - if (is_array) { - new_binding += idx * GetNumBindingsUsedByType(ptr_element_type_id); - } - if (is_struct) { - // The binding offset that should be added is the sum of binding numbers - // used by previous members of the current struct. - for (uint32_t i = 0; i < idx; ++i) { - new_binding += GetNumBindingsUsedByType( - pointee_type_inst->GetSingleWordInOperand(i)); - } - } - new_decoration->SetInOperand(2, {new_binding}); - } - context()->AddAnnotationInst(std::move(new_decoration)); - } + CopyDecorationsForNewVariable(var, idx, id, ptr_element_type_id, is_array, + is_struct, pointee_type_inst); // Create a new OpName for the replacement variable. std::vector> names_to_add; @@ -377,7 +335,7 @@ uint32_t DescriptorScalarReplacement::GetNumBindingsUsedByType( // The number of bindings consumed by a structure is the sum of the bindings // used by its members. if (type_inst->opcode() == SpvOpTypeStruct && - !IsTypeOfStructuredBuffer(type_inst)) { + !descsroautil::IsTypeOfStructuredBuffer(context(), type_inst)) { uint32_t sum = 0; for (uint32_t i = 0; i < type_inst->NumInOperands(); i++) sum += GetNumBindingsUsedByType(type_inst->GetSingleWordInOperand(i)); diff --git a/third_party/spirv-tools/source/opt/desc_sroa.h b/third_party/spirv-tools/source/opt/desc_sroa.h index cd72fd3019..fea062559c 100644 --- a/third_party/spirv-tools/source/opt/desc_sroa.h +++ b/third_party/spirv-tools/source/opt/desc_sroa.h @@ -46,10 +46,6 @@ class DescriptorScalarReplacement : public Pass { } private: - // Returns true if |var| is an OpVariable instruction that represents a - // descriptor array. These are the variables that we want to replace. - bool IsCandidate(Instruction* var); - // Replaces all references to |var| by new variables, one for each element of // the array |var|. The binding for the new variables corresponding to // element i will be the binding of |var| plus i. Returns true if successful. @@ -93,10 +89,45 @@ class DescriptorScalarReplacement : public Pass { // bindings used by its members. uint32_t GetNumBindingsUsedByType(uint32_t type_id); - // Returns true if |type| is a type that could be used for a structured buffer - // as opposed to a type that would be used for a structure of resource - // descriptors. - bool IsTypeOfStructuredBuffer(const Instruction* type) const; + // Copy all of the decorations of variable |old_var| and make them as + // decorations for the new variable whose id is |new_var_id|. The new variable + // is supposed to replace |index|th element of |old_var|. + // |new_var_ptr_type_id| is the id of the pointer to the type of the new + // variable. |is_old_var_array| is true if |old_var| has an array type. + // |is_old_var_struct| is true if |old_var| has a structure type. + // |old_var_type| is the pointee type of |old_var|. + void CopyDecorationsForNewVariable(Instruction* old_var, uint32_t index, + uint32_t new_var_id, + uint32_t new_var_ptr_type_id, + const bool is_old_var_array, + const bool is_old_var_struct, + Instruction* old_var_type); + + // Get the new binding number for a new variable that will be replaced with an + // |index|th element of an old variable. The old variable has |old_binding| + // as its binding number. |ptr_elem_type_id| the id of the pointer to the + // element type. |is_old_var_array| is true if the old variable has an array + // type. |is_old_var_struct| is true if the old variable has a structure type. + // |old_var_type| is the pointee type of the old variable. + uint32_t GetNewBindingForElement(uint32_t old_binding, uint32_t index, + uint32_t ptr_elem_type_id, + const bool is_old_var_array, + const bool is_old_var_struct, + Instruction* old_var_type); + + // Create a new OpDecorate instruction by cloning |old_decoration|. The new + // OpDecorate instruction will be used for a variable whose id is + // |new_var_ptr_type_id|. If |old_decoration| is a decoration for a binding, + // the new OpDecorate instruction will have |new_binding| as its binding. + void CreateNewDecorationForNewVariable(Instruction* old_decoration, + uint32_t new_var_id, + uint32_t new_binding); + + // Create a new OpDecorate instruction whose operand is the same as an + // OpMemberDecorate instruction |old_member_decoration| except Target operand. + // The Target operand of the new OpDecorate instruction will be |new_var_id|. + void CreateNewDecorationForMemberDecorate(Instruction* old_decoration, + uint32_t new_var_id); // A map from an OpVariable instruction to the set of variables that will be // used to replace it. The entry |replacement_variables_[var][i]| is the id of diff --git a/third_party/spirv-tools/source/opt/desc_sroa_util.cpp b/third_party/spirv-tools/source/opt/desc_sroa_util.cpp new file mode 100644 index 0000000000..1954e2cc36 --- /dev/null +++ b/third_party/spirv-tools/source/opt/desc_sroa_util.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/desc_sroa_util.h" + +namespace spvtools { +namespace opt { +namespace { + +const uint32_t kOpAccessChainInOperandIndexes = 1; + +// Returns the length of array type |type|. +uint32_t GetLengthOfArrayType(IRContext* context, Instruction* type) { + assert(type->opcode() == SpvOpTypeArray && "type must be array"); + uint32_t length_id = type->GetSingleWordInOperand(1); + const analysis::Constant* length_const = + context->get_constant_mgr()->FindDeclaredConstant(length_id); + assert(length_const != nullptr); + return length_const->GetU32(); +} + +} // namespace + +namespace descsroautil { + +bool IsDescriptorArray(IRContext* context, Instruction* var) { + if (var->opcode() != SpvOpVariable) { + return false; + } + + uint32_t ptr_type_id = var->type_id(); + Instruction* ptr_type_inst = context->get_def_use_mgr()->GetDef(ptr_type_id); + if (ptr_type_inst->opcode() != SpvOpTypePointer) { + return false; + } + + uint32_t var_type_id = ptr_type_inst->GetSingleWordInOperand(1); + Instruction* var_type_inst = context->get_def_use_mgr()->GetDef(var_type_id); + if (var_type_inst->opcode() != SpvOpTypeArray && + var_type_inst->opcode() != SpvOpTypeStruct) { + return false; + } + + // All structures with descriptor assignments must be replaced by variables, + // one for each of their members - with the exceptions of buffers. + if (IsTypeOfStructuredBuffer(context, var_type_inst)) { + return false; + } + + if (!context->get_decoration_mgr()->HasDecoration( + var->result_id(), SpvDecorationDescriptorSet)) { + return false; + } + + return context->get_decoration_mgr()->HasDecoration(var->result_id(), + SpvDecorationBinding); +} + +bool IsTypeOfStructuredBuffer(IRContext* context, const Instruction* type) { + if (type->opcode() != SpvOpTypeStruct) { + return false; + } + + // All buffers have offset decorations for members of their structure types. + // This is how we distinguish it from a structure of descriptors. + return context->get_decoration_mgr()->HasDecoration(type->result_id(), + SpvDecorationOffset); +} + +const analysis::Constant* GetAccessChainIndexAsConst( + IRContext* context, Instruction* access_chain) { + if (access_chain->NumInOperands() <= 1) { + return nullptr; + } + uint32_t idx_id = GetFirstIndexOfAccessChain(access_chain); + const analysis::Constant* idx_const = + context->get_constant_mgr()->FindDeclaredConstant(idx_id); + return idx_const; +} + +uint32_t GetFirstIndexOfAccessChain(Instruction* access_chain) { + assert(access_chain->NumInOperands() > 1 && + "OpAccessChain does not have Indexes operand"); + return access_chain->GetSingleWordInOperand(kOpAccessChainInOperandIndexes); +} + +uint32_t GetNumberOfElementsForArrayOrStruct(IRContext* context, + Instruction* var) { + uint32_t ptr_type_id = var->type_id(); + Instruction* ptr_type_inst = context->get_def_use_mgr()->GetDef(ptr_type_id); + assert(ptr_type_inst->opcode() == SpvOpTypePointer && + "Variable should be a pointer to an array or structure."); + uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1); + Instruction* pointee_type_inst = + context->get_def_use_mgr()->GetDef(pointee_type_id); + if (pointee_type_inst->opcode() == SpvOpTypeArray) { + return GetLengthOfArrayType(context, pointee_type_inst); + } + assert(pointee_type_inst->opcode() == SpvOpTypeStruct && + "Variable should be a pointer to an array or structure."); + return pointee_type_inst->NumInOperands(); +} + +} // namespace descsroautil +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/desc_sroa_util.h b/third_party/spirv-tools/source/opt/desc_sroa_util.h new file mode 100644 index 0000000000..2f45c0c2f4 --- /dev/null +++ b/third_party/spirv-tools/source/opt/desc_sroa_util.h @@ -0,0 +1,54 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_DESC_SROA_UTIL_H_ +#define SOURCE_OPT_DESC_SROA_UTIL_H_ + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +// Provides functions for the descriptor array SROA. +namespace descsroautil { + +// Returns true if |var| is an OpVariable instruction that represents a +// descriptor array. +bool IsDescriptorArray(IRContext* context, Instruction* var); + +// Returns true if |type| is a type that could be used for a structured buffer +// as opposed to a type that would be used for a structure of resource +// descriptors. +bool IsTypeOfStructuredBuffer(IRContext* context, const Instruction* type); + +// Returns the first index of the OpAccessChain instruction |access_chain| as +// a constant. Returns nullptr if it is not a constant. +const analysis::Constant* GetAccessChainIndexAsConst(IRContext* context, + Instruction* access_chain); + +// Returns the number of elements of an OpVariable instruction |var| whose type +// must be a pointer to an array or a struct. +uint32_t GetNumberOfElementsForArrayOrStruct(IRContext* context, + Instruction* var); + +// Returns the first Indexes operand id of the OpAccessChain or +// OpInBoundsAccessChain instruction |access_chain|. The access chain must have +// at least 1 index. +uint32_t GetFirstIndexOfAccessChain(Instruction* access_chain); + +} // namespace descsroautil +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_DESC_SROA_UTIL_H_ diff --git a/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp b/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp index 173df6209a..a24ba8f41c 100644 --- a/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp +++ b/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp @@ -20,6 +20,7 @@ namespace { const uint32_t kRemovedMember = 0xFFFFFFFF; const uint32_t kSpecConstOpOpcodeIdx = 0; +constexpr uint32_t kArrayElementTypeIdx = 0; } // namespace namespace spvtools { @@ -64,6 +65,10 @@ void EliminateDeadMembersPass::FindLiveMembers() { MarkPointeeTypeAsFullUsed(inst.type_id()); break; default: + // Ignore structured buffers as layout(offset) qualifiers cannot be + // applied to structure fields + if (inst.IsVulkanStorageBufferVariable()) + MarkPointeeTypeAsFullUsed(inst.type_id()); break; } } @@ -136,18 +141,22 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForStore( void EliminateDeadMembersPass::MarkTypeAsFullyUsed(uint32_t type_id) { Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); assert(type_inst != nullptr); - if (type_inst->opcode() != SpvOpTypeStruct) { - return; - } - // Mark every member of the current struct as used. - for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) { - used_members_[type_id].insert(i); - } - - // Mark any sub struct as fully used. - for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) { - MarkTypeAsFullyUsed(type_inst->GetSingleWordInOperand(i)); + switch (type_inst->opcode()) { + case SpvOpTypeStruct: + // Mark every member and its type as fully used. + for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) { + used_members_[type_id].insert(i); + MarkTypeAsFullyUsed(type_inst->GetSingleWordInOperand(i)); + } + break; + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + MarkTypeAsFullyUsed( + type_inst->GetSingleWordInOperand(kArrayElementTypeIdx)); + break; + default: + break; } } diff --git a/third_party/spirv-tools/source/opt/feature_manager.cpp b/third_party/spirv-tools/source/opt/feature_manager.cpp index ad70c1e4f1..39a4a3486e 100644 --- a/third_party/spirv-tools/source/opt/feature_manager.cpp +++ b/third_party/spirv-tools/source/opt/feature_manager.cpp @@ -80,6 +80,8 @@ void FeatureManager::AddExtInstImportIds(Module* module) { extinst_importid_GLSLstd450_ = module->GetExtInstImportId("GLSL.std.450"); extinst_importid_OpenCL100DebugInfo_ = module->GetExtInstImportId("OpenCL.DebugInfo.100"); + extinst_importid_Shader100DebugInfo_ = + module->GetExtInstImportId("NonSemantic.Shader.DebugInfo.100"); } bool operator==(const FeatureManager& a, const FeatureManager& b) { @@ -107,6 +109,11 @@ bool operator==(const FeatureManager& a, const FeatureManager& b) { return false; } + if (a.extinst_importid_Shader100DebugInfo_ != + b.extinst_importid_Shader100DebugInfo_) { + return false; + } + return true; } } // namespace opt diff --git a/third_party/spirv-tools/source/opt/feature_manager.h b/third_party/spirv-tools/source/opt/feature_manager.h index 66d1cbac33..68c8e9a230 100644 --- a/third_party/spirv-tools/source/opt/feature_manager.h +++ b/third_party/spirv-tools/source/opt/feature_manager.h @@ -55,6 +55,10 @@ class FeatureManager { return extinst_importid_OpenCL100DebugInfo_; } + uint32_t GetExtInstImportId_Shader100DebugInfo() const { + return extinst_importid_Shader100DebugInfo_; + } + friend bool operator==(const FeatureManager& a, const FeatureManager& b); friend bool operator!=(const FeatureManager& a, const FeatureManager& b) { return !(a == b); @@ -92,6 +96,10 @@ class FeatureManager { // Common OpenCL100DebugInfo external instruction import ids, cached // for performance. uint32_t extinst_importid_OpenCL100DebugInfo_ = 0; + + // Common NonSemanticShader100DebugInfo external instruction import ids, + // cached for performance. + uint32_t extinst_importid_Shader100DebugInfo_ = 0; }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/folding_rules.cpp b/third_party/spirv-tools/source/opt/folding_rules.cpp index e3e926c3a5..4904f1862e 100644 --- a/third_party/spirv-tools/source/opt/folding_rules.cpp +++ b/third_party/spirv-tools/source/opt/folding_rules.cpp @@ -14,6 +14,7 @@ #include "source/opt/folding_rules.h" +#include #include #include #include @@ -523,7 +524,8 @@ uint32_t PerformFloatingPointOperation(analysis::ConstantManager* const_mgr, float fval = val.getAsFloat(); \ if (!IsValidResult(fval)) return 0; \ words = val.GetWords(); \ - } static_assert(true, "require extra semicolon") + } \ + static_assert(true, "require extra semicolon") switch (opcode) { case SpvOpFMul: FOLD_OP(*); @@ -558,24 +560,19 @@ uint32_t PerformIntegerOperation(analysis::ConstantManager* const_mgr, uint32_t width = type->AsInteger()->width(); assert(width == 32 || width == 64); std::vector words; -#define FOLD_OP(op) \ - if (width == 64) { \ - if (type->IsSigned()) { \ - int64_t val = input1->GetS64() op input2->GetS64(); \ - words = ExtractInts(static_cast(val)); \ - } else { \ - uint64_t val = input1->GetU64() op input2->GetU64(); \ - words = ExtractInts(val); \ - } \ - } else { \ - if (type->IsSigned()) { \ - int32_t val = input1->GetS32() op input2->GetS32(); \ - words.push_back(static_cast(val)); \ - } else { \ - uint32_t val = input1->GetU32() op input2->GetU32(); \ - words.push_back(val); \ - } \ - } static_assert(true, "require extra semicalon") + // Regardless of the sign of the constant, folding is performed on an unsigned + // interpretation of the constant data. This avoids signed integer overflow + // while folding, and works because sign is irrelevant for the IAdd, ISub and + // IMul instructions. +#define FOLD_OP(op) \ + if (width == 64) { \ + uint64_t val = input1->GetU64() op input2->GetU64(); \ + words = ExtractInts(val); \ + } else { \ + uint32_t val = input1->GetU32() op input2->GetU32(); \ + words.push_back(val); \ + } \ + static_assert(true, "require extra semicolon") switch (opcode) { case SpvOpIMul: FOLD_OP(*); @@ -967,30 +964,21 @@ FoldingRule MergeDivMulArithmetic() { // Fold divides of a constant and a negation. // Cases: // (-x) / 2 = x / -2 -// 2 / (-x) = 2 / -x +// 2 / (-x) = -2 / x FoldingRule MergeDivNegateArithmetic() { return [](IRContext* context, Instruction* inst, const std::vector& constants) { - assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv || - inst->opcode() == SpvOpUDiv); + assert(inst->opcode() == SpvOpFDiv); analysis::ConstantManager* const_mgr = context->get_constant_mgr(); - const analysis::Type* type = - context->get_type_mgr()->GetType(inst->type_id()); - bool uses_float = HasFloatingPoint(type); - if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; - - uint32_t width = ElementWidth(type); - if (width != 32 && width != 64) return false; + if (!inst->IsFloatingPointFoldingAllowed()) return false; const analysis::Constant* const_input1 = ConstInput(constants); if (!const_input1) return false; Instruction* other_inst = NonConstInput(context, constants[0], inst); - if (uses_float && !other_inst->IsFloatingPointFoldingAllowed()) - return false; + if (!other_inst->IsFloatingPointFoldingAllowed()) return false; bool first_is_variable = constants[0] == nullptr; - if (other_inst->opcode() == SpvOpFNegate || - other_inst->opcode() == SpvOpSNegate) { + if (other_inst->opcode() == SpvOpFNegate) { uint32_t neg_id = NegateConstant(const_mgr, const_input1); if (first_is_variable) { @@ -1468,90 +1456,121 @@ FoldingRule IntMultipleBy1() { }; } -FoldingRule CompositeConstructFeedingExtract() { - return [](IRContext* context, Instruction* inst, - const std::vector&) { - // If the input to an OpCompositeExtract is an OpCompositeConstruct, - // then we can simply use the appropriate element in the construction. - assert(inst->opcode() == SpvOpCompositeExtract && - "Wrong opcode. Should be OpCompositeExtract."); - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - analysis::TypeManager* type_mgr = context->get_type_mgr(); +// Returns the number of elements that the |index|th in operand in |inst| +// contributes to the result of |inst|. |inst| must be an +// OpCompositeConstructInstruction. +uint32_t GetNumOfElementsContributedByOperand(IRContext* context, + const Instruction* inst, + uint32_t index) { + assert(inst->opcode() == SpvOpCompositeConstruct); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + analysis::TypeManager* type_mgr = context->get_type_mgr(); - // If there are no index operands, then this rule cannot do anything. - if (inst->NumInOperands() <= 1) { - return false; - } + analysis::Vector* result_type = + type_mgr->GetType(inst->type_id())->AsVector(); + if (result_type == nullptr) { + // If the result of the OpCompositeConstruct is not a vector then every + // operands corresponds to a single element in the result. + return 1; + } - uint32_t cid = inst->GetSingleWordInOperand(kExtractCompositeIdInIdx); - Instruction* cinst = def_use_mgr->GetDef(cid); + // If the result type is a vector then the operands are either scalars or + // vectors. If it is a scalar, then it corresponds to a single element. If it + // is a vector, then each element in the vector will be an element in the + // result. + uint32_t id = inst->GetSingleWordInOperand(index); + Instruction* def = def_use_mgr->GetDef(id); + analysis::Vector* type = type_mgr->GetType(def->type_id())->AsVector(); + if (type == nullptr) { + return 1; + } + return type->element_count(); +} - if (cinst->opcode() != SpvOpCompositeConstruct) { - return false; - } +// Returns the in-operands for an OpCompositeExtract instruction that are needed +// to extract the |result_index|th element in the result of |inst| without using +// the result of |inst|. Returns the empty vector if |result_index| is +// out-of-bounds. |inst| must be an |OpCompositeConstruct| instruction. +std::vector GetExtractOperandsForElementOfCompositeConstruct( + IRContext* context, const Instruction* inst, uint32_t result_index) { + assert(inst->opcode() == SpvOpCompositeConstruct); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + analysis::TypeManager* type_mgr = context->get_type_mgr(); - std::vector operands; - analysis::Type* composite_type = type_mgr->GetType(cinst->type_id()); - if (composite_type->AsVector() == nullptr) { - // Get the element being extracted from the OpCompositeConstruct - // Since it is not a vector, it is simple to extract the single element. - uint32_t element_index = inst->GetSingleWordInOperand(1); - uint32_t element_id = cinst->GetSingleWordInOperand(element_index); - operands.push_back({SPV_OPERAND_TYPE_ID, {element_id}}); + analysis::Type* result_type = type_mgr->GetType(inst->type_id()); + if (result_type->AsVector() == nullptr) { + uint32_t id = inst->GetSingleWordInOperand(result_index); + return {Operand(SPV_OPERAND_TYPE_ID, {id})}; + } - // Add the remaining indices for extraction. - for (uint32_t i = 2; i < inst->NumInOperands(); ++i) { - operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, - {inst->GetSingleWordInOperand(i)}}); - } - - } else { - // With vectors we have to handle the case where it is concatenating - // vectors. - assert(inst->NumInOperands() == 2 && - "Expecting a vector of scalar values."); - - uint32_t element_index = inst->GetSingleWordInOperand(1); - for (uint32_t construct_index = 0; - construct_index < cinst->NumInOperands(); ++construct_index) { - uint32_t element_id = cinst->GetSingleWordInOperand(construct_index); - Instruction* element_def = def_use_mgr->GetDef(element_id); - analysis::Vector* element_type = - type_mgr->GetType(element_def->type_id())->AsVector(); - if (element_type) { - uint32_t vector_size = element_type->element_count(); - if (vector_size <= element_index) { - // The element we want comes after this vector. - element_index -= vector_size; - } else { - // We want an element of this vector. - operands.push_back({SPV_OPERAND_TYPE_ID, {element_id}}); - operands.push_back( - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {element_index}}); - break; - } - } else { - if (element_index == 0) { - // This is a scalar, and we this is the element we are extracting. - operands.push_back({SPV_OPERAND_TYPE_ID, {element_id}}); - break; - } else { - // Skip over this scalar value. - --element_index; - } - } + // If the result type is a vector, then vector operands are concatenated. + uint32_t total_element_count = 0; + for (uint32_t idx = 0; idx < inst->NumInOperands(); ++idx) { + uint32_t element_count = + GetNumOfElementsContributedByOperand(context, inst, idx); + total_element_count += element_count; + if (result_index < total_element_count) { + std::vector operands; + uint32_t id = inst->GetSingleWordInOperand(idx); + Instruction* operand_def = def_use_mgr->GetDef(id); + analysis::Type* operand_type = type_mgr->GetType(operand_def->type_id()); + + operands.push_back({SPV_OPERAND_TYPE_ID, {id}}); + if (operand_type->AsVector()) { + uint32_t start_index_of_id = total_element_count - element_count; + uint32_t index_into_id = result_index - start_index_of_id; + operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index_into_id}}); } + return operands; } + } + return {}; +} +bool CompositeConstructFeedingExtract( + IRContext* context, Instruction* inst, + const std::vector&) { + // If the input to an OpCompositeExtract is an OpCompositeConstruct, + // then we can simply use the appropriate element in the construction. + assert(inst->opcode() == SpvOpCompositeExtract && + "Wrong opcode. Should be OpCompositeExtract."); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + + // If there are no index operands, then this rule cannot do anything. + if (inst->NumInOperands() <= 1) { + return false; + } + + uint32_t cid = inst->GetSingleWordInOperand(kExtractCompositeIdInIdx); + Instruction* cinst = def_use_mgr->GetDef(cid); + + if (cinst->opcode() != SpvOpCompositeConstruct) { + return false; + } + + uint32_t index_into_result = inst->GetSingleWordInOperand(1); + std::vector operands = + GetExtractOperandsForElementOfCompositeConstruct(context, cinst, + index_into_result); + + if (operands.empty()) { + return false; + } + + // Add the remaining indices for extraction. + for (uint32_t i = 2; i < inst->NumInOperands(); ++i) { + operands.push_back( + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {inst->GetSingleWordInOperand(i)}}); + } + + if (operands.size() == 1) { // If there were no extra indices, then we have the final object. No need - // to extract even more. - if (operands.size() == 1) { - inst->SetOpcode(SpvOpCopyObject); - } + // to extract any more. + inst->SetOpcode(SpvOpCopyObject); + } - inst->SetInOperands(std::move(operands)); - return true; - }; + inst->SetInOperands(std::move(operands)); + return true; } // If the OpCompositeConstruct is simply putting back together elements that @@ -2510,7 +2529,7 @@ void FoldingRules::AddFoldingRules() { rules_[SpvOpCompositeConstruct].push_back(CompositeExtractFeedingConstruct); rules_[SpvOpCompositeExtract].push_back(InsertFeedingExtract()); - rules_[SpvOpCompositeExtract].push_back(CompositeConstructFeedingExtract()); + rules_[SpvOpCompositeExtract].push_back(CompositeConstructFeedingExtract); rules_[SpvOpCompositeExtract].push_back(VectorShuffleFeedingExtract()); rules_[SpvOpCompositeExtract].push_back(FMixFeedingExtract()); @@ -2562,8 +2581,6 @@ void FoldingRules::AddFoldingRules() { rules_[SpvOpPhi].push_back(RedundantPhi()); - rules_[SpvOpSDiv].push_back(MergeDivNegateArithmetic()); - rules_[SpvOpSNegate].push_back(MergeNegateArithmetic()); rules_[SpvOpSNegate].push_back(MergeNegateMulDivArithmetic()); rules_[SpvOpSNegate].push_back(MergeNegateAddSubArithmetic()); @@ -2572,8 +2589,6 @@ void FoldingRules::AddFoldingRules() { rules_[SpvOpStore].push_back(StoringUndef()); - rules_[SpvOpUDiv].push_back(MergeDivNegateArithmetic()); - rules_[SpvOpVectorShuffle].push_back(VectorShuffleFeedingShuffle()); rules_[SpvOpImageSampleImplicitLod].push_back(UpdateImageOperands()); diff --git a/third_party/spirv-tools/source/opt/function.h b/third_party/spirv-tools/source/opt/function.h index 9e1c72746e..917bf58435 100644 --- a/third_party/spirv-tools/source/opt/function.h +++ b/third_party/spirv-tools/source/opt/function.h @@ -177,6 +177,9 @@ class Function { // debuggers. void Dump() const; + // Returns true is a function declaration and not a function definition. + bool IsDeclaration() { return begin() == end(); } + private: // The OpFunction instruction that begins the definition of this function. std::unique_ptr def_inst_; diff --git a/third_party/spirv-tools/source/opt/if_conversion.cpp b/third_party/spirv-tools/source/opt/if_conversion.cpp index 4284069a8b..492066177f 100644 --- a/third_party/spirv-tools/source/opt/if_conversion.cpp +++ b/third_party/spirv-tools/source/opt/if_conversion.cpp @@ -129,6 +129,7 @@ Pass::Status IfConversion::Process() { Instruction* select = builder.AddSelect(phi->type_id(), condition, true_value->result_id(), false_value->result_id()); + context()->get_def_use_mgr()->AnalyzeInstDefUse(select); select->UpdateDebugInfoFrom(phi); context()->ReplaceAllUsesWith(phi->result_id(), select->result_id()); to_kill.push_back(phi); diff --git a/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp b/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp index f24f744d05..bef45017f2 100644 --- a/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp +++ b/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp @@ -65,7 +65,7 @@ Pass::Status InlineExhaustivePass::ProcessImpl() { status = CombineStatus(status, InlineExhaustive(fp)); return false; }; - context()->ProcessEntryPointCallTree(pfn); + context()->ProcessReachableCallTree(pfn); return status; } diff --git a/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp b/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp index 6ccaf90870..fe9c67993f 100644 --- a/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp +++ b/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp @@ -105,7 +105,7 @@ Pass::Status InlineOpaquePass::ProcessImpl() { status = CombineStatus(status, InlineOpaque(fp)); return false; }; - context()->ProcessEntryPointCallTree(pfn); + context()->ProcessReachableCallTree(pfn); return status; } diff --git a/third_party/spirv-tools/source/opt/inline_pass.cpp b/third_party/spirv-tools/source/opt/inline_pass.cpp index 8159ebf787..2cc31258e3 100644 --- a/third_party/spirv-tools/source/opt/inline_pass.cpp +++ b/third_party/spirv-tools/source/opt/inline_pass.cpp @@ -92,7 +92,7 @@ void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}})); if (line_inst != nullptr) { - newStore->dbg_line_insts().push_back(*line_inst); + newStore->AddDebugLine(line_inst); } newStore->SetDebugScope(dbg_scope); (*block_ptr)->AddInstruction(std::move(newStore)); @@ -106,7 +106,7 @@ void InlinePass::AddLoad(uint32_t type_id, uint32_t resultId, uint32_t ptr_id, new Instruction(context(), SpvOpLoad, type_id, resultId, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}}})); if (line_inst != nullptr) { - newLoad->dbg_line_insts().push_back(*line_inst); + newLoad->AddDebugLine(line_inst); } newLoad->SetDebugScope(dbg_scope); (*block_ptr)->AddInstruction(std::move(newLoad)); @@ -158,8 +158,8 @@ bool InlinePass::CloneAndMapLocals( auto callee_block_itr = calleeFn->begin(); auto callee_var_itr = callee_block_itr->begin(); while (callee_var_itr->opcode() == SpvOp::SpvOpVariable || - callee_var_itr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugDeclare) { + callee_var_itr->GetCommonDebugOpcode() == + CommonDebugInfoDebugDeclare) { if (callee_var_itr->opcode() != SpvOp::SpvOpVariable) { ++callee_var_itr; continue; @@ -300,8 +300,7 @@ InstructionList::iterator InlinePass::AddStoresForVariableInitializers( UptrVectorIterator callee_first_block_itr) { auto callee_itr = callee_first_block_itr->begin(); while (callee_itr->opcode() == SpvOp::SpvOpVariable || - callee_itr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugDeclare) { + callee_itr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) { if (callee_itr->opcode() == SpvOp::SpvOpVariable && callee_itr->NumInOperands() == 2) { assert(callee2caller.count(callee_itr->result_id()) && @@ -315,8 +314,7 @@ InstructionList::iterator InlinePass::AddStoresForVariableInitializers( context()->get_debug_info_mgr()->BuildDebugScope( callee_itr->GetDebugScope(), inlined_at_ctx)); } - if (callee_itr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugDeclare) { + if (callee_itr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) { InlineSingleInstruction( callee2caller, new_blk_ptr->get(), &*callee_itr, context()->get_debug_info_mgr()->BuildDebugInlinedAtChain( @@ -405,6 +403,14 @@ bool InlinePass::InlineEntryBlock( callee2caller, inlined_at_ctx, new_blk_ptr, callee_first_block); while (callee_inst_itr != callee_first_block->end()) { + // Don't inline function definition links, the calling function is not a + // definition. + if (callee_inst_itr->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugFunctionDefinition) { + ++callee_inst_itr; + continue; + } + if (!InlineSingleInstruction( callee2caller, new_blk_ptr->get(), &*callee_inst_itr, context()->get_debug_info_mgr()->BuildDebugInlinedAtChain( @@ -435,6 +441,11 @@ std::unique_ptr InlinePass::InlineBasicBlocks( auto tail_inst_itr = callee_block_itr->end(); for (auto inst_itr = callee_block_itr->begin(); inst_itr != tail_inst_itr; ++inst_itr) { + // Don't inline function definition links, the calling function is not a + // definition + if (inst_itr->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugFunctionDefinition) + continue; if (!InlineSingleInstruction( callee2caller, new_blk_ptr.get(), &*inst_itr, context()->get_debug_info_mgr()->BuildDebugInlinedAtChain( diff --git a/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp index 06acc7ea55..e2336d3601 100644 --- a/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp +++ b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp @@ -130,13 +130,48 @@ void InstBuffAddrCheckPass::GenCheckCode( context()->KillInst(ref_inst); } +uint32_t InstBuffAddrCheckPass::GetTypeAlignment(uint32_t type_id) { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + switch (type_inst->opcode()) { + case SpvOpTypeFloat: + case SpvOpTypeInt: + case SpvOpTypeVector: + return GetTypeLength(type_id); + case SpvOpTypeMatrix: + return GetTypeAlignment(type_inst->GetSingleWordInOperand(0)); + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + return GetTypeAlignment(type_inst->GetSingleWordInOperand(0)); + case SpvOpTypeStruct: { + uint32_t max = 0; + type_inst->ForEachInId([&max, this](const uint32_t* iid) { + uint32_t alignment = GetTypeAlignment(*iid); + max = (alignment > max) ? alignment : max; + }); + return max; + } + case SpvOpTypePointer: + assert(type_inst->GetSingleWordInOperand(0) == + SpvStorageClassPhysicalStorageBufferEXT && + "unexpected pointer type"); + return 8u; + default: + assert(false && "unexpected type"); + return 0; + } +} + uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) { Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); switch (type_inst->opcode()) { case SpvOpTypeFloat: case SpvOpTypeInt: return type_inst->GetSingleWordInOperand(0) / 8u; - case SpvOpTypeVector: + case SpvOpTypeVector: { + uint32_t raw_cnt = type_inst->GetSingleWordInOperand(1); + uint32_t adj_cnt = (raw_cnt == 3u) ? 4u : raw_cnt; + return adj_cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0)); + } case SpvOpTypeMatrix: return type_inst->GetSingleWordInOperand(1) * GetTypeLength(type_inst->GetSingleWordInOperand(0)); @@ -145,8 +180,29 @@ uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) { SpvStorageClassPhysicalStorageBufferEXT && "unexpected pointer type"); return 8u; + case SpvOpTypeArray: { + uint32_t const_id = type_inst->GetSingleWordInOperand(1); + Instruction* const_inst = get_def_use_mgr()->GetDef(const_id); + uint32_t cnt = const_inst->GetSingleWordInOperand(0); + return cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0)); + } + case SpvOpTypeStruct: { + uint32_t len = 0; + type_inst->ForEachInId([&len, this](const uint32_t* iid) { + // Align struct length + uint32_t alignment = GetTypeAlignment(*iid); + uint32_t mod = len % alignment; + uint32_t diff = (mod != 0) ? alignment - mod : 0; + len += diff; + // Increment struct length by component length + uint32_t comp_len = GetTypeLength(*iid); + len += comp_len; + }); + return len; + } + case SpvOpTypeRuntimeArray: default: - assert(false && "unexpected buffer reference type"); + assert(false && "unexpected type"); return 0; } } diff --git a/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h index ec7bb6846f..a82322395a 100644 --- a/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h +++ b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h @@ -28,7 +28,9 @@ namespace opt { // external design of this class may change as the layer evolves. class InstBuffAddrCheckPass : public InstrumentPass { public: - // Preferred interface + // For test harness only + InstBuffAddrCheckPass() : InstrumentPass(7, 23, kInstValidationIdBuffAddr) {} + // For all other interfaces InstBuffAddrCheckPass(uint32_t desc_set, uint32_t shader_id) : InstrumentPass(desc_set, shader_id, kInstValidationIdBuffAddr) {} @@ -40,8 +42,12 @@ class InstBuffAddrCheckPass : public InstrumentPass { const char* name() const override { return "inst-bindless-check-pass"; } private: - // Return byte length of type |type_id|. Must be int, float, vector, matrix - // or physical pointer. + // Return byte alignment of type |type_id|. Must be int, float, vector, + // matrix, struct, array or physical pointer. Uses std430 alignment. + uint32_t GetTypeAlignment(uint32_t type_id); + + // Return byte length of type |type_id|. Must be int, float, vector, matrix, + // struct, array or physical pointer. Uses std430 alignment and sizes. uint32_t GetTypeLength(uint32_t type_id); // Add |type_id| param to |input_func| and add id to |param_vec|. diff --git a/third_party/spirv-tools/source/opt/instruction.cpp b/third_party/spirv-tools/source/opt/instruction.cpp index 1054a20393..2461e41e96 100644 --- a/third_party/spirv-tools/source/opt/instruction.cpp +++ b/third_party/spirv-tools/source/opt/instruction.cpp @@ -30,9 +30,11 @@ namespace { const uint32_t kTypeImageDimIndex = 1; const uint32_t kLoadBaseIndex = 0; const uint32_t kPointerTypeStorageClassIndex = 0; +const uint32_t kVariableStorageClassIndex = 0; const uint32_t kTypeImageSampledIndex = 5; -// Constants for OpenCL.DebugInfo.100 extension instructions. +// Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100 +// extension instructions. const uint32_t kExtInstSetIdInIdx = 0; const uint32_t kExtInstInstructionInIdx = 1; const uint32_t kDebugScopeNumWords = 7; @@ -64,15 +66,14 @@ Instruction::Instruction(IRContext* c, SpvOp op) Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst, std::vector&& dbg_line) - : context_(c), + : utils::IntrusiveNodeBase(), + context_(c), opcode_(static_cast(inst.opcode)), has_type_id_(inst.type_id != 0), has_result_id_(inst.result_id != 0), unique_id_(c->TakeNextUniqueId()), dbg_line_insts_(std::move(dbg_line)), dbg_scope_(kNoDebugScope, kNoInlinedAt) { - assert((!IsDebugLineInst(opcode_) || dbg_line.empty()) && - "Op(No)Line attaching to Op(No)Line found"); for (uint32_t i = 0; i < inst.num_operands; ++i) { const auto& current_payload = inst.operands[i]; std::vector words( @@ -80,11 +81,14 @@ Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst, inst.words + current_payload.offset + current_payload.num_words); operands_.emplace_back(current_payload.type, std::move(words)); } + assert((!IsLineInst() || dbg_line.empty()) && + "Op(No)Line attaching to Op(No)Line found"); } Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst, const DebugScope& dbg_scope) - : context_(c), + : utils::IntrusiveNodeBase(), + context_(c), opcode_(static_cast(inst.opcode)), has_type_id_(inst.type_id != 0), has_result_id_(inst.result_id != 0), @@ -122,6 +126,7 @@ Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id, Instruction::Instruction(Instruction&& that) : utils::IntrusiveNodeBase(), + context_(that.context_), opcode_(that.opcode_), has_type_id_(that.has_type_id_), has_result_id_(that.has_result_id_), @@ -135,6 +140,7 @@ Instruction::Instruction(Instruction&& that) } Instruction& Instruction::operator=(Instruction&& that) { + context_ = that.context_; opcode_ = that.opcode_; has_type_id_ = that.has_type_id_; has_result_id_ = that.has_result_id_; @@ -153,6 +159,10 @@ Instruction* Instruction::Clone(IRContext* c) const { clone->unique_id_ = c->TakeNextUniqueId(); clone->operands_ = operands_; clone->dbg_line_insts_ = dbg_line_insts_; + for (auto& i : clone->dbg_line_insts_) { + i.unique_id_ = c->TakeNextUniqueId(); + if (i.IsDebugLineInst()) i.SetResultId(c->TakeNextId()); + } clone->dbg_scope_ = dbg_scope_; return clone; } @@ -394,6 +404,21 @@ bool Instruction::IsVulkanStorageBuffer() const { return false; } +bool Instruction::IsVulkanStorageBufferVariable() const { + if (opcode() != SpvOpVariable) { + return false; + } + + uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex); + if (storage_class == SpvStorageClassStorageBuffer || + storage_class == SpvStorageClassUniform) { + Instruction* var_type = context()->get_def_use_mgr()->GetDef(type_id()); + return var_type != nullptr && var_type->IsVulkanStorageBuffer(); + } + + return false; +} + bool Instruction::IsVulkanUniformBuffer() const { if (opcode() != SpvOpTypePointer) { return false; @@ -506,7 +531,7 @@ void Instruction::UpdateLexicalScope(uint32_t scope) { for (auto& i : dbg_line_insts_) { i.dbg_scope_.SetLexicalScope(scope); } - if (!IsDebugLineInst(opcode()) && + if (!IsLineInst() && context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) { context()->get_debug_info_mgr()->AnalyzeDebugInst(this); } @@ -517,24 +542,61 @@ void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) { for (auto& i : dbg_line_insts_) { i.dbg_scope_.SetInlinedAt(new_inlined_at); } - if (!IsDebugLineInst(opcode()) && + if (!IsLineInst() && context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) { context()->get_debug_info_mgr()->AnalyzeDebugInst(this); } } +void Instruction::ClearDbgLineInsts() { + if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) { + auto def_use_mgr = context()->get_def_use_mgr(); + for (auto& l_inst : dbg_line_insts_) def_use_mgr->ClearInst(&l_inst); + } + clear_dbg_line_insts(); +} + void Instruction::UpdateDebugInfoFrom(const Instruction* from) { if (from == nullptr) return; - clear_dbg_line_insts(); + ClearDbgLineInsts(); if (!from->dbg_line_insts().empty()) - dbg_line_insts().push_back(from->dbg_line_insts().back()); + AddDebugLine(&from->dbg_line_insts().back()); SetDebugScope(from->GetDebugScope()); - if (!IsDebugLineInst(opcode()) && + if (!IsLineInst() && context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) { context()->get_debug_info_mgr()->AnalyzeDebugInst(this); } } +void Instruction::AddDebugLine(const Instruction* inst) { + dbg_line_insts_.push_back(*inst); + dbg_line_insts_.back().unique_id_ = context()->TakeNextUniqueId(); + if (inst->IsDebugLineInst()) + dbg_line_insts_.back().SetResultId(context_->TakeNextId()); + if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) + context()->get_def_use_mgr()->AnalyzeInstDefUse(&dbg_line_insts_.back()); +} + +bool Instruction::IsDebugLineInst() const { + NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode(); + return ((ext_opt == NonSemanticShaderDebugInfo100DebugLine) || + (ext_opt == NonSemanticShaderDebugInfo100DebugNoLine)); +} + +bool Instruction::IsLineInst() const { return IsLine() || IsNoLine(); } + +bool Instruction::IsLine() const { + if (opcode() == SpvOpLine) return true; + NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode(); + return ext_opt == NonSemanticShaderDebugInfo100DebugLine; +} + +bool Instruction::IsNoLine() const { + if (opcode() == SpvOpNoLine) return true; + NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode(); + return ext_opt == NonSemanticShaderDebugInfo100DebugNoLine; +} + Instruction* Instruction::InsertBefore(std::unique_ptr&& inst) { inst.get()->InsertBefore(this); return inst.release(); @@ -618,6 +680,49 @@ OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const { GetSingleWordInOperand(kExtInstInstructionInIdx)); } +NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode() + const { + if (opcode() != SpvOpExtInst) { + return NonSemanticShaderDebugInfo100InstructionsMax; + } + + if (!context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) { + return NonSemanticShaderDebugInfo100InstructionsMax; + } + + if (GetSingleWordInOperand(kExtInstSetIdInIdx) != + context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) { + return NonSemanticShaderDebugInfo100InstructionsMax; + } + + return NonSemanticShaderDebugInfo100Instructions( + GetSingleWordInOperand(kExtInstInstructionInIdx)); +} + +CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const { + if (opcode() != SpvOpExtInst) { + return CommonDebugInfoInstructionsMax; + } + + const uint32_t opencl_set_id = + context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo(); + const uint32_t shader_set_id = + context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo(); + + if (!opencl_set_id && !shader_set_id) { + return CommonDebugInfoInstructionsMax; + } + + const uint32_t used_set_id = GetSingleWordInOperand(kExtInstSetIdInIdx); + + if (used_set_id != opencl_set_id && used_set_id != shader_set_id) { + return CommonDebugInfoInstructionsMax; + } + + return CommonDebugInfoInstructions( + GetSingleWordInOperand(kExtInstInstructionInIdx)); +} + bool Instruction::IsValidBaseImage() const { uint32_t tid = type_id(); if (tid == 0) { @@ -940,10 +1045,10 @@ void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id, uint32_t ext_set, std::vector* binary) const { uint32_t num_words = kDebugScopeNumWords; - OpenCLDebugInfo100Instructions dbg_opcode = OpenCLDebugInfo100DebugScope; + CommonDebugInfoInstructions dbg_opcode = CommonDebugInfoDebugScope; if (GetLexicalScope() == kNoDebugScope) { num_words = kDebugNoScopeNumWords; - dbg_opcode = OpenCLDebugInfo100DebugNoScope; + dbg_opcode = CommonDebugInfoDebugNoScope; } else if (GetInlinedAt() == kNoInlinedAt) { num_words = kDebugScopeNumWordsWithoutInlinedAt; } diff --git a/third_party/spirv-tools/source/opt/instruction.h b/third_party/spirv-tools/source/opt/instruction.h index 3e557dd7bf..ce568f6626 100644 --- a/third_party/spirv-tools/source/opt/instruction.h +++ b/third_party/spirv-tools/source/opt/instruction.h @@ -22,7 +22,9 @@ #include #include +#include "NonSemanticShaderDebugInfo100.h" #include "OpenCLDebugInfo100.h" +#include "source/common_debug_info.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/latest_version_spirv_header.h" #include "source/opcode.h" @@ -250,11 +252,6 @@ class Instruction : public utils::IntrusiveNodeBase { // Clear line-related debug instructions attached to this instruction. void clear_dbg_line_insts() { dbg_line_insts_.clear(); } - // Set line-related debug instructions. - void set_dbg_line_insts(const std::vector& lines) { - dbg_line_insts_ = lines; - } - // Same semantics as in the base class except the list the InstructionList // containing |pos| will now assume ownership of |this|. // inline void MoveBefore(Instruction* pos); @@ -304,8 +301,21 @@ class Instruction : public utils::IntrusiveNodeBase { // Sets DebugScope. inline void SetDebugScope(const DebugScope& scope); inline const DebugScope& GetDebugScope() const { return dbg_scope_; } + // Add debug line inst. Renew result id if Debug[No]Line + void AddDebugLine(const Instruction* inst); // Updates DebugInlinedAt of DebugScope and OpLine. void UpdateDebugInlinedAt(uint32_t new_inlined_at); + // Clear line-related debug instructions attached to this instruction + // along with def-use entries. + void ClearDbgLineInsts(); + // Return true if Shader100:Debug[No]Line + bool IsDebugLineInst() const; + // Return true if Op[No]Line or Shader100:Debug[No]Line + bool IsLineInst() const; + // Return true if OpLine or Shader100:DebugLine + bool IsLine() const; + // Return true if OpNoLine or Shader100:DebugNoLine + bool IsNoLine() const; inline uint32_t GetDebugInlinedAt() const { return dbg_scope_.GetInlinedAt(); } @@ -454,6 +464,10 @@ class Instruction : public utils::IntrusiveNodeBase { // storage buffer. bool IsVulkanStorageBuffer() const; + // Returns true if the instruction defines a variable in StorageBuffer or + // Uniform storage class with a pointer type that points to a storage buffer. + bool IsVulkanStorageBufferVariable() const; + // Returns true if the instruction defines a pointer type that points to a // uniform buffer. bool IsVulkanUniformBuffer() const; @@ -550,11 +564,30 @@ class Instruction : public utils::IntrusiveNodeBase { // OpenCLDebugInfo100InstructionsMax. OpenCLDebugInfo100Instructions GetOpenCL100DebugOpcode() const; + // Returns debug opcode of an NonSemantic.Shader.DebugInfo.100 instruction. If + // it is not an NonSemantic.Shader.DebugInfo.100 instruction, just return + // NonSemanticShaderDebugInfo100InstructionsMax. + NonSemanticShaderDebugInfo100Instructions GetShader100DebugOpcode() const; + + // Returns debug opcode of an OpenCL.100.DebugInfo or + // NonSemantic.Shader.DebugInfo.100 instruction. Since these overlap, we + // return the OpenCLDebugInfo code + CommonDebugInfoInstructions GetCommonDebugOpcode() const; + // Returns true if it is an OpenCL.DebugInfo.100 instruction. bool IsOpenCL100DebugInstr() const { return GetOpenCL100DebugOpcode() != OpenCLDebugInfo100InstructionsMax; } + // Returns true if it is an NonSemantic.Shader.DebugInfo.100 instruction. + bool IsShader100DebugInstr() const { + return GetShader100DebugOpcode() != + NonSemanticShaderDebugInfo100InstructionsMax; + } + bool IsCommonDebugInstr() const { + return GetCommonDebugOpcode() != CommonDebugInfoInstructionsMax; + } + // Returns true if this instructions a non-semantic instruction. bool IsNonSemanticInstruction() const; @@ -588,9 +621,9 @@ class Instruction : public utils::IntrusiveNodeBase { uint32_t unique_id_; // Unique instruction id // All logical operands, including result type id and result id. OperandList operands_; - // Opline and OpNoLine instructions preceding this instruction. Note that for - // Instructions representing OpLine or OpNonLine itself, this field should be - // empty. + // Op[No]Line or Debug[No]Line instructions preceding this instruction. Note + // that for Instructions representing Op[No]Line or Debug[No]Line themselves, + // this field should be empty. std::vector dbg_line_insts_; // DebugScope that wraps this instruction. diff --git a/third_party/spirv-tools/source/opt/ir_builder.h b/third_party/spirv-tools/source/opt/ir_builder.h index fe5feff569..4433cf0d15 100644 --- a/third_party/spirv-tools/source/opt/ir_builder.h +++ b/third_party/spirv-tools/source/opt/ir_builder.h @@ -359,8 +359,9 @@ class InstructionBuilder { return AddInstruction(std::move(select)); } - // Adds a signed int32 constant to the binary. - // The |value| parameter is the constant value to be added. + // Returns a pointer to the definition of a signed 32-bit integer constant + // with the given value. Returns |nullptr| if the constant does not exist and + // cannot be created. Instruction* GetSintConstant(int32_t value) { return GetIntConstant(value, true); } @@ -381,21 +382,24 @@ class InstructionBuilder { GetContext()->TakeNextId(), ops)); return AddInstruction(std::move(construct)); } - // Adds an unsigned int32 constant to the binary. - // The |value| parameter is the constant value to be added. + + // Returns a pointer to the definition of an unsigned 32-bit integer constant + // with the given value. Returns |nullptr| if the constant does not exist and + // cannot be created. Instruction* GetUintConstant(uint32_t value) { return GetIntConstant(value, false); } uint32_t GetUintConstantId(uint32_t value) { Instruction* uint_inst = GetUintConstant(value); - return uint_inst->result_id(); + return (uint_inst != nullptr ? uint_inst->result_id() : 0); } // Adds either a signed or unsigned 32 bit integer constant to the binary - // depedning on the |sign|. If |sign| is true then the value is added as a + // depending on the |sign|. If |sign| is true then the value is added as a // signed constant otherwise as an unsigned constant. If |sign| is false the - // value must not be a negative number. + // value must not be a negative number. Returns false if the constant does + // not exists and could be be created. template Instruction* GetIntConstant(T value, bool sign) { // Assert that we are not trying to store a negative number in an unsigned @@ -411,6 +415,10 @@ class InstructionBuilder { uint32_t type_id = GetContext()->get_type_mgr()->GetTypeInstruction(&int_type); + if (type_id == 0) { + return nullptr; + } + // Get the memory managed type so that it is safe to be stored by // GetConstant. analysis::Type* rebuilt_type = diff --git a/third_party/spirv-tools/source/opt/ir_context.cpp b/third_party/spirv-tools/source/opt/ir_context.cpp index 74f387867b..612a831add 100644 --- a/third_party/spirv-tools/source/opt/ir_context.cpp +++ b/third_party/spirv-tools/source/opt/ir_context.cpp @@ -30,7 +30,8 @@ static const int kSpvDecorateBuiltinInIdx = 2; static const int kEntryPointInterfaceInIdx = 3; static const int kEntryPointFunctionIdInIdx = 1; -// Constants for OpenCL.DebugInfo.100 extension instructions. +// Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100 +// extension instructions. static const uint32_t kDebugFunctionOperandFunctionIndex = 13; static const uint32_t kDebugGlobalVariableOperandVariableIndex = 11; @@ -170,7 +171,9 @@ Instruction* IRContext::KillInst(Instruction* inst) { KillOperandFromDebugInstructions(inst); if (AreAnalysesValid(kAnalysisDefUse)) { - get_def_use_mgr()->ClearInst(inst); + analysis::DefUseManager* def_use_mgr = get_def_use_mgr(); + def_use_mgr->ClearInst(inst); + for (auto& l_inst : inst->dbg_line_insts()) def_use_mgr->ClearInst(&l_inst); } if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) { instr_to_block_.erase(inst); @@ -217,6 +220,8 @@ Instruction* IRContext::KillInst(Instruction* inst) { void IRContext::CollectNonSemanticTree( Instruction* inst, std::unordered_set* to_kill) { if (!inst->HasResultId()) return; + // Debug[No]Line result id is not used, so we are done + if (inst->IsDebugLineInst()) return; std::vector work_list; std::unordered_set seen; work_list.push_back(inst); @@ -437,8 +442,7 @@ void IRContext::KillOperandFromDebugInstructions(Instruction* inst) { if (opcode == SpvOpVariable || IsConstantInst(opcode)) { for (auto it = module()->ext_inst_debuginfo_begin(); it != module()->ext_inst_debuginfo_end(); ++it) { - if (it->GetOpenCL100DebugOpcode() != - OpenCLDebugInfo100DebugGlobalVariable) + if (it->GetCommonDebugOpcode() != CommonDebugInfoDebugGlobalVariable) continue; auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex); if (operand.words[0] == id) { @@ -930,7 +934,7 @@ void IRContext::EmitErrorMessage(std::string message, Instruction* inst) { while (line_inst != nullptr) { // Stop at the beginning of the basic block. if (!line_inst->dbg_line_insts().empty()) { line_inst = &line_inst->dbg_line_insts().back(); - if (line_inst->opcode() == SpvOpNoLine) { + if (line_inst->IsNoLine()) { line_inst = nullptr; } break; diff --git a/third_party/spirv-tools/source/opt/ir_context.h b/third_party/spirv-tools/source/opt/ir_context.h index f5f38a648e..658534760d 100644 --- a/third_party/spirv-tools/source/opt/ir_context.h +++ b/third_party/spirv-tools/source/opt/ir_context.h @@ -98,6 +98,7 @@ class IRContext { module_(new Module()), consumer_(std::move(c)), def_use_mgr_(nullptr), + feature_mgr_(nullptr), valid_analyses_(kAnalysisNone), constant_mgr_(nullptr), type_mgr_(nullptr), @@ -116,6 +117,7 @@ class IRContext { module_(std::move(m)), consumer_(std::move(c)), def_use_mgr_(nullptr), + feature_mgr_(nullptr), valid_analyses_(kAnalysisNone), type_mgr_(nullptr), id_to_name_(nullptr), @@ -190,8 +192,8 @@ class IRContext { inline IteratorRange debugs3() const; // Iterators for debug info instructions (excluding OpLine & OpNoLine) - // contained in this module. These are OpExtInst for OpenCL.DebugInfo.100 - // or DebugInfo extension placed between section 9 and 10. + // contained in this module. These are OpExtInst for DebugInfo extension + // placed between section 9 and 10. inline Module::inst_iterator ext_inst_debuginfo_begin(); inline Module::inst_iterator ext_inst_debuginfo_end(); inline IteratorRange ext_inst_debuginfo(); @@ -769,6 +771,8 @@ class IRContext { // The instruction decoration manager for |module_|. std::unique_ptr decoration_mgr_; + + // The feature manager for |module_|. std::unique_ptr feature_mgr_; // A map from instructions to the basic block they belong to. This mapping is diff --git a/third_party/spirv-tools/source/opt/ir_loader.cpp b/third_party/spirv-tools/source/opt/ir_loader.cpp index e443ebb5f3..a82b530e6c 100644 --- a/third_party/spirv-tools/source/opt/ir_loader.cpp +++ b/third_party/spirv-tools/source/opt/ir_loader.cpp @@ -19,6 +19,7 @@ #include "DebugInfo.h" #include "OpenCLDebugInfo100.h" #include "source/ext_inst.h" +#include "source/opt/ir_context.h" #include "source/opt/log.h" #include "source/opt/reflect.h" #include "source/util/make_unique.h" @@ -37,26 +38,40 @@ IrLoader::IrLoader(const MessageConsumer& consumer, Module* m) inst_index_(0), last_dbg_scope_(kNoDebugScope, kNoInlinedAt) {} +bool IsLineInst(const spv_parsed_instruction_t* inst) { + const auto opcode = static_cast(inst->opcode); + if (IsOpLineInst(opcode)) return true; + if (opcode != SpvOpExtInst) return false; + if (inst->ext_inst_type != SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) + return false; + const uint32_t ext_inst_index = inst->words[kExtInstSetIndex]; + const NonSemanticShaderDebugInfo100Instructions ext_inst_key = + NonSemanticShaderDebugInfo100Instructions(ext_inst_index); + return ext_inst_key == NonSemanticShaderDebugInfo100DebugLine || + ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine; +} + bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { ++inst_index_; - const auto opcode = static_cast(inst->opcode); - if (IsDebugLineInst(opcode)) { + if (IsLineInst(inst)) { module()->SetContainsDebugInfo(); last_line_inst_.reset(); - dbg_line_info_.push_back( - Instruction(module()->context(), *inst, last_dbg_scope_)); + dbg_line_info_.emplace_back(module()->context(), *inst, last_dbg_scope_); return true; } // If it is a DebugScope or DebugNoScope of debug extension, we do not // create a new instruction, but simply keep the information in // struct DebugScope. + const auto opcode = static_cast(inst->opcode); if (opcode == SpvOpExtInst && spvExtInstIsDebugInfo(inst->ext_inst_type)) { const uint32_t ext_inst_index = inst->words[kExtInstSetIndex]; - if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { - const OpenCLDebugInfo100Instructions ext_inst_key = - OpenCLDebugInfo100Instructions(ext_inst_index); - if (ext_inst_key == OpenCLDebugInfo100DebugScope) { + if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || + inst->ext_inst_type == + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { + const CommonDebugInfoInstructions ext_inst_key = + CommonDebugInfoInstructions(ext_inst_index); + if (ext_inst_key == CommonDebugInfoDebugScope) { uint32_t inlined_at = 0; if (inst->num_words > kInlinedAtIndex) inlined_at = inst->words[kInlinedAtIndex]; @@ -65,7 +80,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { module()->SetContainsDebugInfo(); return true; } - if (ext_inst_key == OpenCLDebugInfo100DebugNoScope) { + if (ext_inst_key == CommonDebugInfoDebugNoScope) { last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); module()->SetContainsDebugInfo(); return true; @@ -94,14 +109,20 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { new Instruction(module()->context(), *inst, std::move(dbg_line_info_))); if (!spv_inst->dbg_line_insts().empty()) { if (extra_line_tracking_ && - (spv_inst->dbg_line_insts().back().opcode() != SpvOpNoLine)) { + (!spv_inst->dbg_line_insts().back().IsNoLine())) { last_line_inst_ = std::unique_ptr( spv_inst->dbg_line_insts().back().Clone(module()->context())); + if (last_line_inst_->IsDebugLineInst()) + last_line_inst_->SetResultId(module()->context()->TakeNextId()); } dbg_line_info_.clear(); } else if (last_line_inst_ != nullptr) { last_line_inst_->SetDebugScope(last_dbg_scope_); spv_inst->dbg_line_insts().push_back(*last_line_inst_); + last_line_inst_ = std::unique_ptr( + spv_inst->dbg_line_insts().back().Clone(module()->context())); + if (last_line_inst_->IsDebugLineInst()) + last_line_inst_->SetResultId(module()->context()->TakeNextId()); } const char* src = source_.c_str(); @@ -230,6 +251,35 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { block_->AddInstruction(std::move(spv_inst)); break; } + default: { + Errorf(consumer_, src, loc, + "Debug info extension instruction other than DebugScope, " + "DebugNoScope, DebugFunctionDefinition, DebugDeclare, and " + "DebugValue found inside function", + opcode); + return false; + } + } + } else if (inst->ext_inst_type == + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { + const NonSemanticShaderDebugInfo100Instructions ext_inst_key = + NonSemanticShaderDebugInfo100Instructions(ext_inst_index); + switch (ext_inst_key) { + case NonSemanticShaderDebugInfo100DebugDeclare: + case NonSemanticShaderDebugInfo100DebugValue: + case NonSemanticShaderDebugInfo100DebugScope: + case NonSemanticShaderDebugInfo100DebugNoScope: + case NonSemanticShaderDebugInfo100DebugFunctionDefinition: { + if (block_ == nullptr) { // Inside function but outside blocks + Errorf(consumer_, src, loc, + "Debug info extension instruction found inside function " + "but outside block", + opcode); + } else { + block_->AddInstruction(std::move(spv_inst)); + } + break; + } default: { Errorf(consumer_, src, loc, "Debug info extension instruction other than DebugScope, " diff --git a/third_party/spirv-tools/source/opt/iterator.h b/third_party/spirv-tools/source/opt/iterator.h index 2280582dfe..847e1bbd52 100644 --- a/third_party/spirv-tools/source/opt/iterator.h +++ b/third_party/spirv-tools/source/opt/iterator.h @@ -142,7 +142,7 @@ inline IteratorRange make_range(const IteratorType& begin, template inline IteratorRange make_range(IteratorType&& begin, IteratorType&& end) { - return {std::move(begin), std::move(end)}; + return {std::forward(begin), std::forward(end)}; } // Returns a (begin, end) iterator pair for the given container. diff --git a/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp b/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp index 5c10ecec78..da9ba8cc01 100644 --- a/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp +++ b/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp @@ -184,8 +184,8 @@ bool LocalAccessChainConvertPass::IsConstantIndexAccessChain( bool LocalAccessChainConvertPass::HasOnlySupportedRefs(uint32_t ptrId) { if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true; if (get_def_use_mgr()->WhileEachUser(ptrId, [this](Instruction* user) { - if (user->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue || - user->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) { + if (user->GetCommonDebugOpcode() == CommonDebugInfoDebugValue || + user->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) { return true; } SpvOp op = user->opcode(); @@ -333,6 +333,20 @@ bool LocalAccessChainConvertPass::AllExtensionsSupported() const { if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } + // only allow NonSemantic.Shader.DebugInfo.100, we cannot safely optimise + // around unknown extended + // instruction sets even if they are non-semantic + for (auto& inst : context()->module()->ext_inst_imports()) { + assert(inst.opcode() == SpvOpExtInstImport && + "Expecting an import of an extension's instruction set."); + const char* extension_name = + reinterpret_cast(&inst.GetInOperand(0).words[0]); + if (0 == std::strncmp(extension_name, "NonSemantic.", 12) && + 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100", + 32)) { + return false; + } + } return true; } @@ -420,6 +434,8 @@ void LocalAccessChainConvertPass::InitExtensions() { "SPV_KHR_terminate_invocation", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", + "SPV_EXT_shader_image_int64", + "SPV_KHR_non_semantic_info", }); } diff --git a/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp b/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp index 05ed28ae8a..5fd4f658d4 100644 --- a/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp @@ -31,9 +31,9 @@ const uint32_t kStoreValIdInIdx = 1; bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) { if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true; if (get_def_use_mgr()->WhileEachUser(ptrId, [this](Instruction* user) { - auto dbg_op = user->GetOpenCL100DebugOpcode(); - if (dbg_op == OpenCLDebugInfo100DebugDeclare || - dbg_op == OpenCLDebugInfo100DebugValue) { + auto dbg_op = user->GetCommonDebugOpcode(); + if (dbg_op == CommonDebugInfoDebugDeclare || + dbg_op == CommonDebugInfoDebugValue) { return true; } SpvOp op = user->opcode(); @@ -188,6 +188,20 @@ bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const { if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } + // only allow NonSemantic.Shader.DebugInfo.100, we cannot safely optimise + // around unknown extended + // instruction sets even if they are non-semantic + for (auto& inst : context()->module()->ext_inst_imports()) { + assert(inst.opcode() == SpvOpExtInstImport && + "Expecting an import of an extension's instruction set."); + const char* extension_name = + reinterpret_cast(&inst.GetInOperand(0).words[0]); + if (0 == std::strncmp(extension_name, "NonSemantic.", 12) && + 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100", + 32)) { + return false; + } + } return true; } @@ -209,7 +223,7 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::ProcessImpl() { return LocalSingleBlockLoadStoreElim(fp); }; - bool modified = context()->ProcessEntryPointCallTree(pfn); + bool modified = context()->ProcessReachableCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } @@ -272,6 +286,8 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_KHR_terminate_invocation", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", + "SPV_EXT_shader_image_int64", + "SPV_KHR_non_semantic_info", }); } diff --git a/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp b/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp index 7eb4b1fda9..051bcada76 100644 --- a/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp @@ -53,6 +53,20 @@ bool LocalSingleStoreElimPass::AllExtensionsSupported() const { if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } + // only allow NonSemantic.Shader.DebugInfo.100, we cannot safely optimise + // around unknown extended + // instruction sets even if they are non-semantic + for (auto& inst : context()->module()->ext_inst_imports()) { + assert(inst.opcode() == SpvOpExtInstImport && + "Expecting an import of an extension's instruction set."); + const char* extension_name = + reinterpret_cast(&inst.GetInOperand(0).words[0]); + if (0 == std::strncmp(extension_name, "NonSemantic.", 12) && + 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100", + 32)) { + return false; + } + } return true; } @@ -67,7 +81,7 @@ Pass::Status LocalSingleStoreElimPass::ProcessImpl() { ProcessFunction pfn = [this](Function* fp) { return LocalSingleStoreElim(fp); }; - bool modified = context()->ProcessEntryPointCallTree(pfn); + bool modified = context()->ProcessReachableCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } @@ -125,6 +139,8 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() { "SPV_KHR_terminate_invocation", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", + "SPV_EXT_shader_image_int64", + "SPV_KHR_non_semantic_info", }); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { @@ -223,9 +239,9 @@ Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses( case SpvOpCopyObject: break; case SpvOpExtInst: { - auto dbg_op = user->GetOpenCL100DebugOpcode(); - if (dbg_op == OpenCLDebugInfo100DebugDeclare || - dbg_op == OpenCLDebugInfo100DebugValue) { + auto dbg_op = user->GetCommonDebugOpcode(); + if (dbg_op == CommonDebugInfoDebugDeclare || + dbg_op == CommonDebugInfoDebugValue) { break; } return nullptr; @@ -292,9 +308,9 @@ bool LocalSingleStoreElimPass::RewriteLoads( bool modified = false; for (Instruction* use : uses) { if (use->opcode() == SpvOpStore) continue; - auto dbg_op = use->GetOpenCL100DebugOpcode(); - if (dbg_op == OpenCLDebugInfo100DebugDeclare || - dbg_op == OpenCLDebugInfo100DebugValue) + auto dbg_op = use->GetCommonDebugOpcode(); + if (dbg_op == CommonDebugInfoDebugDeclare || + dbg_op == CommonDebugInfoDebugValue) continue; if (use->opcode() == SpvOpLoad && dominator_analysis->Dominates(store_inst, use)) { diff --git a/third_party/spirv-tools/source/opt/loop_unroller.cpp b/third_party/spirv-tools/source/opt/loop_unroller.cpp index df68bd20ed..aff191febc 100644 --- a/third_party/spirv-tools/source/opt/loop_unroller.cpp +++ b/third_party/spirv-tools/source/opt/loop_unroller.cpp @@ -760,7 +760,7 @@ void LoopUnrollerUtilsImpl::FoldConditionBlock(BasicBlock* condition_block, IRContext::Analysis::kAnalysisInstrToBlockMapping); Instruction* new_branch = builder.AddBranch(new_target); - new_branch->set_dbg_line_insts(lines); + if (!lines.empty()) new_branch->AddDebugLine(&lines.back()); new_branch->SetDebugScope(scope); } @@ -873,6 +873,10 @@ void LoopUnrollerUtilsImpl::AssignNewResultIds(BasicBlock* basic_block) { def_use_mgr->AnalyzeInstDefUse(basic_block->GetLabelInst()); for (Instruction& inst : *basic_block) { + // Do def/use analysis on new lines + for (auto& line : inst.dbg_line_insts()) + def_use_mgr->AnalyzeInstDefUse(&line); + uint32_t old_id = inst.result_id(); // Ignore stores etc. @@ -1098,6 +1102,10 @@ void LoopUtils::Finalize() { Pass::Status LoopUnroller::Process() { bool changed = false; for (Function& f : *context()->module()) { + if (f.IsDeclaration()) { + continue; + } + LoopDescriptor* LD = context()->GetLoopDescriptor(&f); for (Loop& loop : *LD) { LoopUtils loop_utils{context(), &loop}; diff --git a/third_party/spirv-tools/source/opt/mem_pass.cpp b/third_party/spirv-tools/source/opt/mem_pass.cpp index 573879842c..ca4889b7cc 100644 --- a/third_party/spirv-tools/source/opt/mem_pass.cpp +++ b/third_party/spirv-tools/source/opt/mem_pass.cpp @@ -20,7 +20,6 @@ #include #include -#include "OpenCLDebugInfo100.h" #include "source/cfa.h" #include "source/opt/basic_block.h" #include "source/opt/dominator_analysis.h" @@ -87,8 +86,8 @@ bool MemPass::IsPtr(uint32_t ptrId) { } const SpvOp op = ptrInst->opcode(); if (op == SpvOpVariable || IsNonPtrAccessChain(op)) return true; - if (op != SpvOpFunctionParameter) return false; const uint32_t varTypeId = ptrInst->type_id(); + if (varTypeId == 0) return false; const Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId); return varTypeInst->opcode() == SpvOpTypePointer; } @@ -226,9 +225,9 @@ MemPass::MemPass() {} bool MemPass::HasOnlySupportedRefs(uint32_t varId) { return get_def_use_mgr()->WhileEachUser(varId, [this](Instruction* user) { - auto dbg_op = user->GetOpenCL100DebugOpcode(); - if (dbg_op == OpenCLDebugInfo100DebugDeclare || - dbg_op == OpenCLDebugInfo100DebugValue) { + auto dbg_op = user->GetCommonDebugOpcode(); + if (dbg_op == CommonDebugInfoDebugDeclare || + dbg_op == CommonDebugInfoDebugValue) { return true; } SpvOp op = user->opcode(); diff --git a/third_party/spirv-tools/source/opt/merge_return_pass.cpp b/third_party/spirv-tools/source/opt/merge_return_pass.cpp index f1601049e9..a962a7ccb0 100644 --- a/third_party/spirv-tools/source/opt/merge_return_pass.cpp +++ b/third_party/spirv-tools/source/opt/merge_return_pass.cpp @@ -111,7 +111,9 @@ bool MergeReturnPass::ProcessStructured( } RecordImmediateDominators(function); - AddSingleCaseSwitchAroundFunction(); + if (!AddSingleCaseSwitchAroundFunction()) { + return false; + } std::list order; cfg()->ComputeStructuredOrder(function, &*function->begin(), &order); @@ -770,7 +772,7 @@ void MergeReturnPass::InsertAfterElement(BasicBlock* element, list->insert(pos, new_element); } -void MergeReturnPass::AddSingleCaseSwitchAroundFunction() { +bool MergeReturnPass::AddSingleCaseSwitchAroundFunction() { CreateReturnBlock(); CreateReturn(final_return_block_); @@ -778,7 +780,10 @@ void MergeReturnPass::AddSingleCaseSwitchAroundFunction() { cfg()->RegisterBlock(final_return_block_); } - CreateSingleCaseSwitch(final_return_block_); + if (!CreateSingleCaseSwitch(final_return_block_)) { + return false; + } + return true; } BasicBlock* MergeReturnPass::CreateContinueTarget(uint32_t header_label_id) { @@ -813,7 +818,7 @@ BasicBlock* MergeReturnPass::CreateContinueTarget(uint32_t header_label_id) { return new_block; } -void MergeReturnPass::CreateSingleCaseSwitch(BasicBlock* merge_target) { +bool MergeReturnPass::CreateSingleCaseSwitch(BasicBlock* merge_target) { // Insert the switch before any code is run. We have to split the entry // block to make sure the OpVariable instructions remain in the entry block. BasicBlock* start_block = &*function_->begin(); @@ -830,13 +835,17 @@ void MergeReturnPass::CreateSingleCaseSwitch(BasicBlock* merge_target) { context(), start_block, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - builder.AddSwitch(builder.GetUintConstantId(0u), old_block->id(), {}, - merge_target->id()); + uint32_t const_zero_id = builder.GetUintConstantId(0u); + if (const_zero_id == 0) { + return false; + } + builder.AddSwitch(const_zero_id, old_block->id(), {}, merge_target->id()); if (context()->AreAnalysesValid(IRContext::kAnalysisCFG)) { cfg()->RegisterBlock(old_block); cfg()->AddEdges(start_block); } + return true; } bool MergeReturnPass::HasNontrivialUnreachableBlocks(Function* function) { diff --git a/third_party/spirv-tools/source/opt/merge_return_pass.h b/third_party/spirv-tools/source/opt/merge_return_pass.h index 06a3e7b550..4096ce7dd4 100644 --- a/third_party/spirv-tools/source/opt/merge_return_pass.h +++ b/third_party/spirv-tools/source/opt/merge_return_pass.h @@ -277,7 +277,7 @@ class MergeReturnPass : public MemPass { // current function where the switch and case value are both zero and the // default is the merge block. Returns after the switch is executed. Sets // |final_return_block_|. - void AddSingleCaseSwitchAroundFunction(); + bool AddSingleCaseSwitchAroundFunction(); // Creates a new basic block that branches to |header_label_id|. Returns the // new basic block. The block will be the second last basic block in the @@ -286,7 +286,7 @@ class MergeReturnPass : public MemPass { // Creates a one case switch around the executable code of the function with // |merge_target| as the merge node. - void CreateSingleCaseSwitch(BasicBlock* merge_target); + bool CreateSingleCaseSwitch(BasicBlock* merge_target); // Returns true if |function| has an unreachable block that is not a continue // target that simply branches back to the header, or a merge block containing diff --git a/third_party/spirv-tools/source/opt/module.cpp b/third_party/spirv-tools/source/opt/module.cpp index 0c88601097..f97defbd6f 100644 --- a/third_party/spirv-tools/source/opt/module.cpp +++ b/third_party/spirv-tools/source/opt/module.cpp @@ -145,20 +145,21 @@ void Module::ToBinary(std::vector* binary, bool skip_nop) const { DebugScope last_scope(kNoDebugScope, kNoInlinedAt); const Instruction* last_line_inst = nullptr; bool between_merge_and_branch = false; + bool between_label_and_phi_var = false; auto write_inst = [binary, skip_nop, &last_scope, &last_line_inst, - &between_merge_and_branch, this](const Instruction* i) { + &between_merge_and_branch, &between_label_and_phi_var, + this](const Instruction* i) { // Skip emitting line instructions between merge and branch instructions. auto opcode = i->opcode(); - if (between_merge_and_branch && - (opcode == SpvOpLine || opcode == SpvOpNoLine)) { + if (between_merge_and_branch && i->IsLineInst()) { return; } between_merge_and_branch = false; if (last_line_inst != nullptr) { - // If the current instruction is OpLine and it is the same with - // the last line instruction that is still effective (can be applied + // If the current instruction is OpLine or DebugLine and it is the same + // as the last line instruction that is still effective (can be applied // to the next instruction), we skip writing the current instruction. - if (opcode == SpvOpLine) { + if (i->IsLine()) { uint32_t operand_index = 0; if (last_line_inst->WhileEachInOperand( [&operand_index, i](const uint32_t* word) { @@ -167,39 +168,67 @@ void Module::ToBinary(std::vector* binary, bool skip_nop) const { })) { return; } - } else if (opcode != SpvOpNoLine && i->dbg_line_insts().empty()) { + } else if (!i->IsNoLine() && i->dbg_line_insts().empty()) { // If the current instruction does not have the line information, // the last line information is not effective any more. Emit OpNoLine - // to specify it. - binary->push_back((1 << 16) | static_cast(SpvOpNoLine)); + // or DebugNoLine to specify it. + uint32_t shader_set_id = context() + ->get_feature_mgr() + ->GetExtInstImportId_Shader100DebugInfo(); + if (shader_set_id != 0) { + binary->push_back((5 << 16) | static_cast(SpvOpExtInst)); + binary->push_back(context()->get_type_mgr()->GetVoidTypeId()); + binary->push_back(context()->TakeNextId()); + binary->push_back(shader_set_id); + binary->push_back(NonSemanticShaderDebugInfo100DebugNoLine); + } else { + binary->push_back((1 << 16) | static_cast(SpvOpNoLine)); + } last_line_inst = nullptr; } } + + if (opcode == SpvOpLabel) { + between_label_and_phi_var = true; + } else if (opcode != SpvOpVariable && opcode != SpvOpPhi && + !spvtools::opt::IsOpLineInst(opcode)) { + between_label_and_phi_var = false; + } + if (!(skip_nop && i->IsNop())) { const auto& scope = i->GetDebugScope(); if (scope != last_scope) { - // Emit DebugScope |scope| to |binary|. - auto dbg_inst = ext_inst_debuginfo_.begin(); - scope.ToBinary(dbg_inst->type_id(), context()->TakeNextId(), - dbg_inst->GetSingleWordOperand(2), binary); + // Can only emit nonsemantic instructions after all phi instructions + // in a block so don't emit scope instructions before phi instructions + // for NonSemantic.Shader.DebugInfo.100. + if (!between_label_and_phi_var || + context() + ->get_feature_mgr() + ->GetExtInstImportId_OpenCL100DebugInfo()) { + // Emit DebugScope |scope| to |binary|. + auto dbg_inst = ext_inst_debuginfo_.begin(); + scope.ToBinary(dbg_inst->type_id(), context()->TakeNextId(), + dbg_inst->GetSingleWordOperand(2), binary); + } last_scope = scope; } i->ToBinaryWithoutAttachedDebugInsts(binary); } // Update the last line instruction. - if (spvOpcodeIsBlockTerminator(opcode) || opcode == SpvOpNoLine) { + if (spvOpcodeIsBlockTerminator(opcode) || i->IsNoLine()) { last_line_inst = nullptr; } else if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) { between_merge_and_branch = true; last_line_inst = nullptr; - } else if (opcode == SpvOpLine) { + } else if (i->IsLine()) { last_line_inst = i; } }; ForEachInst(write_inst, true); - // We create new instructions for DebugScope. The bound must be updated. + // We create new instructions for DebugScope and DebugNoLine. The bound must + // be updated. binary->data()[bound_idx] = header_.bound; } diff --git a/third_party/spirv-tools/source/opt/module.h b/third_party/spirv-tools/source/opt/module.h index d609b603ab..0360b7d5b4 100644 --- a/third_party/spirv-tools/source/opt/module.h +++ b/third_party/spirv-tools/source/opt/module.h @@ -103,8 +103,8 @@ class Module { // This is due to decision by the SPIR Working Group, pending publication. inline void AddDebug3Inst(std::unique_ptr d); - // Appends a debug info extension (OpenCL.DebugInfo.100 or DebugInfo) - // instruction to this module. + // Appends a debug info extension (OpenCL.DebugInfo.100, + // NonSemantic.Shader.DebugInfo.100, or DebugInfo) instruction to this module. inline void AddExtInstDebugInfo(std::unique_ptr d); // Appends an annotation instruction to this module. @@ -192,8 +192,8 @@ class Module { inline IteratorRange debugs3() const; // Iterators for debug info instructions (excluding OpLine & OpNoLine) - // contained in this module. These are OpExtInst for OpenCL.DebugInfo.100 - // or DebugInfo extension placed between section 9 and 10. + // contained in this module. These are OpExtInst for DebugInfo extension + // placed between section 9 and 10. inline inst_iterator ext_inst_debuginfo_begin(); inline inst_iterator ext_inst_debuginfo_end(); inline IteratorRange ext_inst_debuginfo(); diff --git a/third_party/spirv-tools/source/opt/optimizer.cpp b/third_party/spirv-tools/source/opt/optimizer.cpp index 69103b26c9..e74db26f0c 100644 --- a/third_party/spirv-tools/source/opt/optimizer.cpp +++ b/third_party/spirv-tools/source/opt/optimizer.cpp @@ -320,6 +320,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateCombineAccessChainsPass()); } else if (pass_name == "convert-local-access-chains") { RegisterPass(CreateLocalAccessChainConvertPass()); + } else if (pass_name == "replace-desc-array-access-using-var-index") { + RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass()); } else if (pass_name == "descriptor-scalar-replacement") { RegisterPass(CreateDescriptorScalarReplacementPass()); } else if (pass_name == "eliminate-dead-code-aggressive") { @@ -385,7 +387,23 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } else if (pass_name == "loop-invariant-code-motion") { RegisterPass(CreateLoopInvariantCodeMotionPass()); } else if (pass_name == "reduce-load-size") { - RegisterPass(CreateReduceLoadSizePass()); + if (pass_args.size() == 0) { + RegisterPass(CreateReduceLoadSizePass()); + } else { + double load_replacement_threshold = 0.9; + if (pass_args.find_first_not_of(".0123456789") == std::string::npos) { + load_replacement_threshold = atof(pass_args.c_str()); + } + + if (load_replacement_threshold >= 0) { + RegisterPass(CreateReduceLoadSizePass(load_replacement_threshold)); + } else { + Error(consumer(), nullptr, {}, + "--reduce-load-size must have no arguments or a non-negative " + "double argument"); + return false; + } + } } else if (pass_name == "redundancy-elimination") { RegisterPass(CreateRedundancyEliminationPass()); } else if (pass_name == "private-to-local") { @@ -401,22 +419,22 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateSimplificationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateAggressiveDCEPass()); + RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "inst-desc-idx-check") { RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true)); RegisterPass(CreateSimplificationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateAggressiveDCEPass()); + RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "inst-buff-oob-check") { RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true)); RegisterPass(CreateSimplificationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateAggressiveDCEPass()); + RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "inst-buff-addr-check") { RegisterPass(CreateInstBuffAddrCheckPass(7, 23)); - RegisterPass(CreateAggressiveDCEPass()); + RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "convert-relaxed-to-half") { RegisterPass(CreateConvertRelaxedToHalfPass()); } else if (pass_name == "relax-float-ops") { @@ -499,6 +517,26 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateAmdExtToKhrPass()); } else if (pass_name == "interpolate-fixup") { RegisterPass(CreateInterpolateFixupPass()); + } else if (pass_name == "convert-to-sampled-image") { + if (pass_args.size() > 0) { + auto descriptor_set_binding_pairs = + opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString( + pass_args.c_str()); + if (!descriptor_set_binding_pairs) { + Errorf(consumer(), nullptr, {}, + "Invalid argument for --convert-to-sampled-image: %s", + pass_args.c_str()); + return false; + } + RegisterPass(CreateConvertToSampledImagePass( + std::move(*descriptor_set_binding_pairs))); + } else { + Errorf(consumer(), nullptr, {}, + "Invalid pairs of descriptor set and binding '%s'. Expected a " + "string of : pairs.", + pass_args.c_str()); + return false; + } } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -726,9 +764,9 @@ Optimizer::PassToken CreateLocalMultiStoreElimPass() { MakeUnique()); } -Optimizer::PassToken CreateAggressiveDCEPass() { +Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) { return MakeUnique( - MakeUnique()); + MakeUnique(preserve_interface)); } Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() { @@ -859,9 +897,10 @@ Optimizer::PassToken CreateVectorDCEPass() { return MakeUnique(MakeUnique()); } -Optimizer::PassToken CreateReduceLoadSizePass() { +Optimizer::PassToken CreateReduceLoadSizePass( + double load_replacement_threshold) { return MakeUnique( - MakeUnique()); + MakeUnique(load_replacement_threshold)); } Optimizer::PassToken CreateCombineAccessChainsPass() { @@ -921,6 +960,11 @@ Optimizer::PassToken CreateGraphicsRobustAccessPass() { MakeUnique()); } +Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() { + return MakeUnique( + MakeUnique()); +} + Optimizer::PassToken CreateDescriptorScalarReplacementPass() { return MakeUnique( MakeUnique()); @@ -940,4 +984,11 @@ Optimizer::PassToken CreateInterpolateFixupPass() { MakeUnique()); } +Optimizer::PassToken CreateConvertToSampledImagePass( + const std::vector& + descriptor_set_binding_pairs) { + return MakeUnique( + MakeUnique(descriptor_set_binding_pairs)); +} + } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/pass.cpp b/third_party/spirv-tools/source/opt/pass.cpp index 09b78af933..017aad10f9 100644 --- a/third_party/spirv-tools/source/opt/pass.cpp +++ b/third_party/spirv-tools/source/opt/pass.cpp @@ -43,8 +43,8 @@ Pass::Status Pass::Run(IRContext* ctx) { if (status == Status::SuccessWithChange) { ctx->InvalidateAnalysesExceptFor(GetPreservedAnalyses()); } - assert((status == Status::Failure || ctx->IsConsistent()) && - "An analysis in the context is out of date."); + if (!(status == Status::Failure || ctx->IsConsistent())) + assert(false && "An analysis in the context is out of date."); return status; } diff --git a/third_party/spirv-tools/source/opt/passes.h b/third_party/spirv-tools/source/opt/passes.h index aeae44494d..f3c30d578b 100644 --- a/third_party/spirv-tools/source/opt/passes.h +++ b/third_party/spirv-tools/source/opt/passes.h @@ -26,6 +26,7 @@ #include "source/opt/combine_access_chains.h" #include "source/opt/compact_ids_pass.h" #include "source/opt/convert_to_half_pass.h" +#include "source/opt/convert_to_sampled_image_pass.h" #include "source/opt/copy_prop_arrays.h" #include "source/opt/dead_branch_elim_pass.h" #include "source/opt/dead_insert_elim_pass.h" @@ -65,6 +66,7 @@ #include "source/opt/relax_float_ops_pass.h" #include "source/opt/remove_duplicates_pass.h" #include "source/opt/remove_unused_interface_variables_pass.h" +#include "source/opt/replace_desc_array_access_using_var_index.h" #include "source/opt/replace_invalid_opc.h" #include "source/opt/scalar_replacement_pass.h" #include "source/opt/set_spec_constant_default_value_pass.h" diff --git a/third_party/spirv-tools/source/opt/private_to_local_pass.cpp b/third_party/spirv-tools/source/opt/private_to_local_pass.cpp index dd6cbbdef8..12a226d5f1 100644 --- a/third_party/spirv-tools/source/opt/private_to_local_pass.cpp +++ b/third_party/spirv-tools/source/opt/private_to_local_pass.cpp @@ -157,8 +157,7 @@ uint32_t PrivateToLocalPass::GetNewType(uint32_t old_type_id) { bool PrivateToLocalPass::IsValidUse(const Instruction* inst) const { // The cases in this switch have to match the cases in |UpdateUse|. // If we don't know how to update it, it is not valid. - if (inst->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugGlobalVariable) { + if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugGlobalVariable) { return true; } switch (inst->opcode()) { @@ -183,8 +182,7 @@ bool PrivateToLocalPass::UpdateUse(Instruction* inst, Instruction* user) { // The cases in this switch have to match the cases in |IsValidUse|. If we // don't think it is valid, the optimization will not view the variable as a // candidate, and therefore the use will not be updated. - if (inst->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugGlobalVariable) { + if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugGlobalVariable) { context()->get_debug_info_mgr()->ConvertDebugGlobalToLocalVariable(inst, user); return true; diff --git a/third_party/spirv-tools/source/opt/reduce_load_size.cpp b/third_party/spirv-tools/source/opt/reduce_load_size.cpp index c58adf47cd..e9b8087489 100644 --- a/third_party/spirv-tools/source/opt/reduce_load_size.cpp +++ b/third_party/spirv-tools/source/opt/reduce_load_size.cpp @@ -27,7 +27,6 @@ namespace { const uint32_t kExtractCompositeIdInIdx = 0; const uint32_t kVariableStorageClassInIdx = 0; const uint32_t kLoadPointerInIdx = 0; -const double kThreshold = 0.9; } // namespace @@ -139,7 +138,7 @@ bool ReduceLoadSize::ShouldReplaceExtract(Instruction* inst) { all_elements_used = !def_use_mgr->WhileEachUser(op_inst, [&elements_used](Instruction* use) { - if (use->IsOpenCL100DebugInstr()) return true; + if (use->IsCommonDebugInstr()) return true; if (use->opcode() != SpvOpCompositeExtract || use->NumInOperands() == 1) { return false; @@ -151,6 +150,8 @@ bool ReduceLoadSize::ShouldReplaceExtract(Instruction* inst) { bool should_replace = false; if (all_elements_used) { should_replace = false; + } else if (1.0 <= replacement_threshold_) { + should_replace = true; } else { analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); analysis::TypeManager* type_mgr = context()->get_type_mgr(); @@ -172,7 +173,7 @@ bool ReduceLoadSize::ShouldReplaceExtract(Instruction* inst) { } double percent_used = static_cast(elements_used.size()) / static_cast(total_size); - should_replace = (percent_used < kThreshold); + should_replace = (percent_used < replacement_threshold_); } should_replace_cache_[op_inst->result_id()] = should_replace; diff --git a/third_party/spirv-tools/source/opt/reduce_load_size.h b/third_party/spirv-tools/source/opt/reduce_load_size.h index ccac49be6d..b323845366 100644 --- a/third_party/spirv-tools/source/opt/reduce_load_size.h +++ b/third_party/spirv-tools/source/opt/reduce_load_size.h @@ -27,6 +27,9 @@ namespace opt { // See optimizer.hpp for documentation. class ReduceLoadSize : public Pass { public: + explicit ReduceLoadSize(double replacement_threshold) + : replacement_threshold_(replacement_threshold) {} + const char* name() const override { return "reduce-load-size"; } Status Process() override; @@ -54,6 +57,11 @@ class ReduceLoadSize : public Pass { // on the load feeding |inst|. bool ShouldReplaceExtract(Instruction* inst); + // Threshold to determine whether we have to replace the load or not. If the + // ratio of the used components of the load is less than the threshold, we + // replace the load. + double replacement_threshold_; + // Maps the result id of an OpLoad instruction to the result of whether or // not the OpCompositeExtract that use the id should be replaced. std::unordered_map should_replace_cache_; diff --git a/third_party/spirv-tools/source/opt/redundancy_elimination.cpp b/third_party/spirv-tools/source/opt/redundancy_elimination.cpp index 362e54dc6b..398225bb5d 100644 --- a/third_party/spirv-tools/source/opt/redundancy_elimination.cpp +++ b/third_party/spirv-tools/source/opt/redundancy_elimination.cpp @@ -24,6 +24,10 @@ Pass::Status RedundancyEliminationPass::Process() { ValueNumberTable vnTable(context()); for (auto& func : *get_module()) { + if (func.IsDeclaration()) { + continue; + } + // Build the dominator tree for this function. It is how the code is // traversed. DominatorTree& dom_tree = diff --git a/third_party/spirv-tools/source/opt/reflect.h b/third_party/spirv-tools/source/opt/reflect.h index c7d46df548..c2ffb0beb4 100644 --- a/third_party/spirv-tools/source/opt/reflect.h +++ b/third_party/spirv-tools/source/opt/reflect.h @@ -34,7 +34,7 @@ inline bool IsDebug2Inst(SpvOp opcode) { inline bool IsDebug3Inst(SpvOp opcode) { return opcode == SpvOpModuleProcessed; } -inline bool IsDebugLineInst(SpvOp opcode) { +inline bool IsOpLineInst(SpvOp opcode) { return opcode == SpvOpLine || opcode == SpvOpNoLine; } inline bool IsAnnotationInst(SpvOp opcode) { @@ -51,7 +51,8 @@ inline bool IsTypeInst(SpvOp opcode) { opcode == SpvOpTypeCooperativeMatrixNV; } inline bool IsConstantInst(SpvOp opcode) { - return opcode >= SpvOpConstantTrue && opcode <= SpvOpSpecConstantOp; + return (opcode >= SpvOpConstantTrue && opcode <= SpvOpSpecConstantOp) || + opcode == SpvOpConstantFunctionPointerINTEL; } inline bool IsCompileTimeConstantInst(SpvOp opcode) { return opcode >= SpvOpConstantTrue && opcode <= SpvOpConstantNull; diff --git a/third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp b/third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp index 73f16ddf3f..3fcf879557 100644 --- a/third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp +++ b/third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp @@ -76,7 +76,7 @@ Pass::Status RelaxFloatOpsPass::ProcessImpl() { Pass::ProcessFunction pfn = [this](Function* fp) { return ProcessFunction(fp); }; - bool modified = context()->ProcessEntryPointCallTree(pfn); + bool modified = context()->ProcessReachableCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.cpp b/third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.cpp new file mode 100644 index 0000000000..1082e679b6 --- /dev/null +++ b/third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.cpp @@ -0,0 +1,423 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/replace_desc_array_access_using_var_index.h" + +#include "source/opt/desc_sroa_util.h" +#include "source/opt/ir_builder.h" +#include "source/util/string_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +const uint32_t kOpAccessChainInOperandIndexes = 1; +const uint32_t kOpTypePointerInOperandType = 1; +const uint32_t kOpTypeArrayInOperandType = 0; +const uint32_t kOpTypeStructInOperandMember = 0; +IRContext::Analysis kAnalysisDefUseAndInstrToBlockMapping = + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; + +uint32_t GetValueWithKeyExistenceCheck( + uint32_t key, const std::unordered_map& map) { + auto itr = map.find(key); + assert(itr != map.end() && "Key does not exist"); + return itr->second; +} + +} // namespace + +Pass::Status ReplaceDescArrayAccessUsingVarIndex::Process() { + Status status = Status::SuccessWithoutChange; + for (Instruction& var : context()->types_values()) { + if (descsroautil::IsDescriptorArray(context(), &var)) { + if (ReplaceVariableAccessesWithConstantElements(&var)) + status = Status::SuccessWithChange; + } + } + return status; +} + +bool ReplaceDescArrayAccessUsingVarIndex:: + ReplaceVariableAccessesWithConstantElements(Instruction* var) const { + std::vector work_list; + get_def_use_mgr()->ForEachUser(var, [&work_list](Instruction* use) { + switch (use->opcode()) { + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + work_list.push_back(use); + break; + default: + break; + } + }); + + bool updated = false; + for (Instruction* access_chain : work_list) { + if (descsroautil::GetAccessChainIndexAsConst(context(), access_chain) == + nullptr) { + ReplaceAccessChain(var, access_chain); + updated = true; + } + } + // Note that we do not consider OpLoad and OpCompositeExtract because + // OpCompositeExtract always has constant literals for indices. + return updated; +} + +void ReplaceDescArrayAccessUsingVarIndex::ReplaceAccessChain( + Instruction* var, Instruction* access_chain) const { + uint32_t number_of_elements = + descsroautil::GetNumberOfElementsForArrayOrStruct(context(), var); + assert(number_of_elements != 0 && "Number of element is 0"); + if (number_of_elements == 1) { + UseConstIndexForAccessChain(access_chain, 0); + get_def_use_mgr()->AnalyzeInstUse(access_chain); + return; + } + ReplaceUsersOfAccessChain(access_chain, number_of_elements); +} + +void ReplaceDescArrayAccessUsingVarIndex::ReplaceUsersOfAccessChain( + Instruction* access_chain, uint32_t number_of_elements) const { + std::vector final_users; + CollectRecursiveUsersWithConcreteType(access_chain, &final_users); + for (auto* inst : final_users) { + std::deque insts_to_be_cloned = + CollectRequiredImageInsts(inst); + ReplaceNonUniformAccessWithSwitchCase( + inst, access_chain, number_of_elements, insts_to_be_cloned); + } +} + +void ReplaceDescArrayAccessUsingVarIndex::CollectRecursiveUsersWithConcreteType( + Instruction* access_chain, std::vector* final_users) const { + std::queue work_list; + work_list.push(access_chain); + while (!work_list.empty()) { + auto* inst_from_work_list = work_list.front(); + work_list.pop(); + get_def_use_mgr()->ForEachUser( + inst_from_work_list, [this, final_users, &work_list](Instruction* use) { + // TODO: Support Boolean type as well. + if (!use->HasResultId() || IsConcreteType(use->type_id())) { + final_users->push_back(use); + } else { + work_list.push(use); + } + }); + } +} + +std::deque +ReplaceDescArrayAccessUsingVarIndex::CollectRequiredImageInsts( + Instruction* user_of_image_insts) const { + std::unordered_set seen_inst_ids; + std::queue work_list; + + auto decision_to_include_operand = [this, &seen_inst_ids, + &work_list](uint32_t* idp) { + if (!seen_inst_ids.insert(*idp).second) return; + Instruction* operand = get_def_use_mgr()->GetDef(*idp); + if (context()->get_instr_block(operand) != nullptr && + HasImageOrImagePtrType(operand)) { + work_list.push(operand); + } + }; + + std::deque required_image_insts; + required_image_insts.push_front(user_of_image_insts); + user_of_image_insts->ForEachInId(decision_to_include_operand); + while (!work_list.empty()) { + auto* inst_from_work_list = work_list.front(); + work_list.pop(); + required_image_insts.push_front(inst_from_work_list); + inst_from_work_list->ForEachInId(decision_to_include_operand); + } + return required_image_insts; +} + +bool ReplaceDescArrayAccessUsingVarIndex::HasImageOrImagePtrType( + const Instruction* inst) const { + assert(inst != nullptr && inst->type_id() != 0 && "Invalid instruction"); + return IsImageOrImagePtrType(get_def_use_mgr()->GetDef(inst->type_id())); +} + +bool ReplaceDescArrayAccessUsingVarIndex::IsImageOrImagePtrType( + const Instruction* type_inst) const { + if (type_inst->opcode() == SpvOpTypeImage || + type_inst->opcode() == SpvOpTypeSampler || + type_inst->opcode() == SpvOpTypeSampledImage) { + return true; + } + if (type_inst->opcode() == SpvOpTypePointer) { + Instruction* pointee_type_inst = get_def_use_mgr()->GetDef( + type_inst->GetSingleWordInOperand(kOpTypePointerInOperandType)); + return IsImageOrImagePtrType(pointee_type_inst); + } + if (type_inst->opcode() == SpvOpTypeArray) { + Instruction* element_type_inst = get_def_use_mgr()->GetDef( + type_inst->GetSingleWordInOperand(kOpTypeArrayInOperandType)); + return IsImageOrImagePtrType(element_type_inst); + } + if (type_inst->opcode() != SpvOpTypeStruct) return false; + for (uint32_t in_operand_idx = kOpTypeStructInOperandMember; + in_operand_idx < type_inst->NumInOperands(); ++in_operand_idx) { + Instruction* member_type_inst = get_def_use_mgr()->GetDef( + type_inst->GetSingleWordInOperand(kOpTypeStructInOperandMember)); + if (IsImageOrImagePtrType(member_type_inst)) return true; + } + return false; +} + +bool ReplaceDescArrayAccessUsingVarIndex::IsConcreteType( + uint32_t type_id) const { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + if (type_inst->opcode() == SpvOpTypeInt || + type_inst->opcode() == SpvOpTypeFloat) { + return true; + } + if (type_inst->opcode() == SpvOpTypeVector || + type_inst->opcode() == SpvOpTypeMatrix || + type_inst->opcode() == SpvOpTypeArray) { + return IsConcreteType(type_inst->GetSingleWordInOperand(0)); + } + if (type_inst->opcode() == SpvOpTypeStruct) { + for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) { + if (!IsConcreteType(type_inst->GetSingleWordInOperand(i))) return false; + } + return true; + } + return false; +} + +BasicBlock* ReplaceDescArrayAccessUsingVarIndex::CreateCaseBlock( + Instruction* access_chain, uint32_t element_index, + const std::deque& insts_to_be_cloned, + uint32_t branch_target_id, + std::unordered_map* old_ids_to_new_ids) const { + auto* case_block = CreateNewBlock(); + AddConstElementAccessToCaseBlock(case_block, access_chain, element_index, + old_ids_to_new_ids); + CloneInstsToBlock(case_block, access_chain, insts_to_be_cloned, + old_ids_to_new_ids); + AddBranchToBlock(case_block, branch_target_id); + UseNewIdsInBlock(case_block, *old_ids_to_new_ids); + return case_block; +} + +void ReplaceDescArrayAccessUsingVarIndex::CloneInstsToBlock( + BasicBlock* block, Instruction* inst_to_skip_cloning, + const std::deque& insts_to_be_cloned, + std::unordered_map* old_ids_to_new_ids) const { + for (auto* inst_to_be_cloned : insts_to_be_cloned) { + if (inst_to_be_cloned == inst_to_skip_cloning) continue; + std::unique_ptr clone(inst_to_be_cloned->Clone(context())); + if (inst_to_be_cloned->HasResultId()) { + uint32_t new_id = context()->TakeNextId(); + clone->SetResultId(new_id); + (*old_ids_to_new_ids)[inst_to_be_cloned->result_id()] = new_id; + } + get_def_use_mgr()->AnalyzeInstDefUse(clone.get()); + context()->set_instr_block(clone.get(), block); + block->AddInstruction(std::move(clone)); + } +} + +void ReplaceDescArrayAccessUsingVarIndex::UseNewIdsInBlock( + BasicBlock* block, + const std::unordered_map& old_ids_to_new_ids) const { + for (auto block_itr = block->begin(); block_itr != block->end(); + ++block_itr) { + (&*block_itr)->ForEachInId([&old_ids_to_new_ids](uint32_t* idp) { + auto old_ids_to_new_ids_itr = old_ids_to_new_ids.find(*idp); + if (old_ids_to_new_ids_itr == old_ids_to_new_ids.end()) return; + *idp = old_ids_to_new_ids_itr->second; + }); + get_def_use_mgr()->AnalyzeInstUse(&*block_itr); + } +} + +void ReplaceDescArrayAccessUsingVarIndex::ReplaceNonUniformAccessWithSwitchCase( + Instruction* access_chain_final_user, Instruction* access_chain, + uint32_t number_of_elements, + const std::deque& insts_to_be_cloned) const { + // Create merge block and add terminator + auto* block = context()->get_instr_block(access_chain_final_user); + auto* merge_block = SeparateInstructionsIntoNewBlock( + block, access_chain_final_user->NextNode()); + + auto* function = block->GetParent(); + + // Add case blocks + std::vector phi_operands; + std::vector case_block_ids; + for (uint32_t idx = 0; idx < number_of_elements; ++idx) { + std::unordered_map old_ids_to_new_ids_for_cloned_insts; + std::unique_ptr case_block(CreateCaseBlock( + access_chain, idx, insts_to_be_cloned, merge_block->id(), + &old_ids_to_new_ids_for_cloned_insts)); + case_block_ids.push_back(case_block->id()); + function->InsertBasicBlockBefore(std::move(case_block), merge_block); + + // Keep the operand for OpPhi + if (!access_chain_final_user->HasResultId()) continue; + uint32_t phi_operand = + GetValueWithKeyExistenceCheck(access_chain_final_user->result_id(), + old_ids_to_new_ids_for_cloned_insts); + phi_operands.push_back(phi_operand); + } + + // Create default block + std::unique_ptr default_block( + CreateDefaultBlock(access_chain_final_user->HasResultId(), &phi_operands, + merge_block->id())); + uint32_t default_block_id = default_block->id(); + function->InsertBasicBlockBefore(std::move(default_block), merge_block); + + // Create OpSwitch + uint32_t access_chain_index_var_id = + descsroautil::GetFirstIndexOfAccessChain(access_chain); + AddSwitchForAccessChain(block, access_chain_index_var_id, default_block_id, + merge_block->id(), case_block_ids); + + // Create phi instructions + if (!phi_operands.empty()) { + uint32_t phi_id = CreatePhiInstruction(merge_block, phi_operands, + case_block_ids, default_block_id); + context()->ReplaceAllUsesWith(access_chain_final_user->result_id(), phi_id); + } + + // Replace OpPhi incoming block operand that uses |block| with |merge_block| + ReplacePhiIncomingBlock(block->id(), merge_block->id()); +} + +BasicBlock* +ReplaceDescArrayAccessUsingVarIndex::SeparateInstructionsIntoNewBlock( + BasicBlock* block, Instruction* separation_begin_inst) const { + auto separation_begin = block->begin(); + while (separation_begin != block->end() && + &*separation_begin != separation_begin_inst) { + ++separation_begin; + } + return block->SplitBasicBlock(context(), context()->TakeNextId(), + separation_begin); +} + +BasicBlock* ReplaceDescArrayAccessUsingVarIndex::CreateNewBlock() const { + auto* new_block = new BasicBlock(std::unique_ptr( + new Instruction(context(), SpvOpLabel, 0, context()->TakeNextId(), {}))); + get_def_use_mgr()->AnalyzeInstDefUse(new_block->GetLabelInst()); + context()->set_instr_block(new_block->GetLabelInst(), new_block); + return new_block; +} + +void ReplaceDescArrayAccessUsingVarIndex::UseConstIndexForAccessChain( + Instruction* access_chain, uint32_t const_element_idx) const { + uint32_t const_element_idx_id = + context()->get_constant_mgr()->GetUIntConst(const_element_idx); + access_chain->SetInOperand(kOpAccessChainInOperandIndexes, + {const_element_idx_id}); +} + +void ReplaceDescArrayAccessUsingVarIndex::AddConstElementAccessToCaseBlock( + BasicBlock* case_block, Instruction* access_chain, + uint32_t const_element_idx, + std::unordered_map* old_ids_to_new_ids) const { + std::unique_ptr access_clone(access_chain->Clone(context())); + UseConstIndexForAccessChain(access_clone.get(), const_element_idx); + + uint32_t new_access_id = context()->TakeNextId(); + (*old_ids_to_new_ids)[access_clone->result_id()] = new_access_id; + access_clone->SetResultId(new_access_id); + get_def_use_mgr()->AnalyzeInstDefUse(access_clone.get()); + + context()->set_instr_block(access_clone.get(), case_block); + case_block->AddInstruction(std::move(access_clone)); +} + +void ReplaceDescArrayAccessUsingVarIndex::AddBranchToBlock( + BasicBlock* parent_block, uint32_t branch_destination) const { + InstructionBuilder builder{context(), parent_block, + kAnalysisDefUseAndInstrToBlockMapping}; + builder.AddBranch(branch_destination); +} + +BasicBlock* ReplaceDescArrayAccessUsingVarIndex::CreateDefaultBlock( + bool null_const_for_phi_is_needed, std::vector* phi_operands, + uint32_t merge_block_id) const { + auto* default_block = CreateNewBlock(); + AddBranchToBlock(default_block, merge_block_id); + if (!null_const_for_phi_is_needed) return default_block; + + // Create null value for OpPhi + Instruction* inst = context()->get_def_use_mgr()->GetDef((*phi_operands)[0]); + auto* null_const_inst = GetConstNull(inst->type_id()); + phi_operands->push_back(null_const_inst->result_id()); + return default_block; +} + +Instruction* ReplaceDescArrayAccessUsingVarIndex::GetConstNull( + uint32_t type_id) const { + assert(type_id != 0 && "Result type is expected"); + auto* type = context()->get_type_mgr()->GetType(type_id); + auto* null_const = context()->get_constant_mgr()->GetConstant(type, {}); + return context()->get_constant_mgr()->GetDefiningInstruction(null_const); +} + +void ReplaceDescArrayAccessUsingVarIndex::AddSwitchForAccessChain( + BasicBlock* parent_block, uint32_t access_chain_index_var_id, + uint32_t default_id, uint32_t merge_id, + const std::vector& case_block_ids) const { + InstructionBuilder builder{context(), parent_block, + kAnalysisDefUseAndInstrToBlockMapping}; + std::vector> cases; + for (uint32_t i = 0; i < static_cast(case_block_ids.size()); ++i) { + cases.emplace_back(Operand::OperandData{i}, case_block_ids[i]); + } + builder.AddSwitch(access_chain_index_var_id, default_id, cases, merge_id); +} + +uint32_t ReplaceDescArrayAccessUsingVarIndex::CreatePhiInstruction( + BasicBlock* parent_block, const std::vector& phi_operands, + const std::vector& case_block_ids, + uint32_t default_block_id) const { + std::vector incomings; + assert(case_block_ids.size() + 1 == phi_operands.size() && + "Number of Phi operands must be exactly 1 bigger than the one of case " + "blocks"); + for (size_t i = 0; i < case_block_ids.size(); ++i) { + incomings.push_back(phi_operands[i]); + incomings.push_back(case_block_ids[i]); + } + incomings.push_back(phi_operands.back()); + incomings.push_back(default_block_id); + + InstructionBuilder builder{context(), &*parent_block->begin(), + kAnalysisDefUseAndInstrToBlockMapping}; + uint32_t phi_result_type_id = + context()->get_def_use_mgr()->GetDef(phi_operands[0])->type_id(); + auto* phi = builder.AddPhi(phi_result_type_id, incomings); + return phi->result_id(); +} + +void ReplaceDescArrayAccessUsingVarIndex::ReplacePhiIncomingBlock( + uint32_t old_incoming_block_id, uint32_t new_incoming_block_id) const { + context()->ReplaceAllUsesWithPredicate( + old_incoming_block_id, new_incoming_block_id, + [](Instruction* use) { return use->opcode() == SpvOpPhi; }); +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h b/third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h new file mode 100644 index 0000000000..e18222c858 --- /dev/null +++ b/third_party/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h @@ -0,0 +1,204 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_REPLACE_DESC_VAR_INDEX_ACCESS_H_ +#define SOURCE_OPT_REPLACE_DESC_VAR_INDEX_ACCESS_H_ + +#include +#include +#include +#include +#include +#include + +#include "source/opt/function.h" +#include "source/opt/pass.h" +#include "source/opt/type_manager.h" + +namespace spvtools { +namespace opt { + +// See optimizer.hpp for documentation. +class ReplaceDescArrayAccessUsingVarIndex : public Pass { + public: + ReplaceDescArrayAccessUsingVarIndex() {} + + const char* name() const override { + return "replace-desc-array-access-using-var-index"; + } + + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; + } + + private: + // Replaces all acceses to |var| using variable indices with constant + // elements of the array |var|. Creates switch-case statements to determine + // the value of the variable index for all the possible cases. Returns + // whether replacement is done or not. + bool ReplaceVariableAccessesWithConstantElements(Instruction* var) const; + + // Replaces the OpAccessChain or OpInBoundsAccessChain instruction |use| that + // uses the descriptor variable |var| with the OpAccessChain or + // OpInBoundsAccessChain instruction with a constant Indexes operand. + void ReplaceAccessChain(Instruction* var, Instruction* use) const; + + // Updates the first Indexes operand of the OpAccessChain or + // OpInBoundsAccessChain instruction |access_chain| to let it use a constant + // index |const_element_idx|. + void UseConstIndexForAccessChain(Instruction* access_chain, + uint32_t const_element_idx) const; + + // Replaces users of the OpAccessChain or OpInBoundsAccessChain instruction + // |access_chain| that accesses an array descriptor variable using variable + // indices with constant elements. |number_of_elements| is the number + // of array elements. + void ReplaceUsersOfAccessChain(Instruction* access_chain, + uint32_t number_of_elements) const; + + // Puts all the recursive users of |access_chain| with concrete result types + // or the ones without result it in |final_users|. + void CollectRecursiveUsersWithConcreteType( + Instruction* access_chain, std::vector* final_users) const; + + // Recursively collects the operands of |user_of_image_insts| (and operands + // of the operands) whose result types are images/samplers or pointers/array/ + // struct of them and returns them. + std::deque CollectRequiredImageInsts( + Instruction* user_of_image_insts) const; + + // Returns whether result type of |inst| is an image/sampler/pointer of image + // or sampler or not. + bool HasImageOrImagePtrType(const Instruction* inst) const; + + // Returns whether |type_inst| is an image/sampler or pointer/array/struct of + // image or sampler or not. + bool IsImageOrImagePtrType(const Instruction* type_inst) const; + + // Returns whether the type with |type_id| is a concrete type or not. + bool IsConcreteType(uint32_t type_id) const; + + // Replaces the non-uniform access to a descriptor variable + // |access_chain_final_user| with OpSwitch instruction and case blocks. Each + // case block will contain a clone of |access_chain| and clones of + // |non_uniform_accesses_to_clone| that are recursively used by + // |access_chain_final_user|. The clone of |access_chain| (or + // OpInBoundsAccessChain) will have a constant index for its first index. The + // OpSwitch instruction will have the cases for the variable index of + // |access_chain| from 0 to |number_of_elements| - 1. + void ReplaceNonUniformAccessWithSwitchCase( + Instruction* access_chain_final_user, Instruction* access_chain, + uint32_t number_of_elements, + const std::deque& non_uniform_accesses_to_clone) const; + + // Creates and returns a new basic block that contains all instructions of + // |block| after |separation_begin_inst|. The new basic block is added to the + // function in this method. + BasicBlock* SeparateInstructionsIntoNewBlock( + BasicBlock* block, Instruction* separation_begin_inst) const; + + // Creates and returns a new block. + BasicBlock* CreateNewBlock() const; + + // Returns the first operand id of the OpAccessChain or OpInBoundsAccessChain + // instruction |access_chain|. + uint32_t GetFirstIndexOfAccessChain(Instruction* access_chain) const; + + // Adds a clone of the OpAccessChain or OpInBoundsAccessChain instruction + // |access_chain| to |case_block|. The clone of |access_chain| will use + // |const_element_idx| for its first index. |old_ids_to_new_ids| keeps the + // mapping from the result id of |access_chain| to the result of its clone. + void AddConstElementAccessToCaseBlock( + BasicBlock* case_block, Instruction* access_chain, + uint32_t const_element_idx, + std::unordered_map* old_ids_to_new_ids) const; + + // Clones all instructions in |insts_to_be_cloned| and put them to |block|. + // |old_ids_to_new_ids| keeps the mapping from the result id of each + // instruction of |insts_to_be_cloned| to the result of their clones. + void CloneInstsToBlock( + BasicBlock* block, Instruction* inst_to_skip_cloning, + const std::deque& insts_to_be_cloned, + std::unordered_map* old_ids_to_new_ids) const; + + // Adds OpBranch to |branch_destination| at the end of |parent_block|. + void AddBranchToBlock(BasicBlock* parent_block, + uint32_t branch_destination) const; + + // Replaces in-operands of all instructions in the basic block |block| using + // |old_ids_to_new_ids|. It conducts the replacement only if the in-operand + // id is a key of |old_ids_to_new_ids|. + void UseNewIdsInBlock( + BasicBlock* block, + const std::unordered_map& old_ids_to_new_ids) const; + + // Creates a case block for |element_index| case. It adds clones of + // |insts_to_be_cloned| and a clone of |access_chain| with |element_index| as + // its first index. The termination instruction of the created case block will + // be a branch to |branch_target_id|. Puts old ids to new ids map for the + // cloned instructions in |old_ids_to_new_ids|. + BasicBlock* CreateCaseBlock( + Instruction* access_chain, uint32_t element_index, + const std::deque& insts_to_be_cloned, + uint32_t branch_target_id, + std::unordered_map* old_ids_to_new_ids) const; + + // Creates a default block for switch-case statement that has only a single + // instruction OpBranch whose target is a basic block with |merge_block_id|. + // If |null_const_for_phi_is_needed| is true, gets or creates a default null + // constant value for a phi instruction whose operands are |phi_operands| and + // puts it in |phi_operands|. + BasicBlock* CreateDefaultBlock(bool null_const_for_phi_is_needed, + std::vector* phi_operands, + uint32_t merge_block_id) const; + + // Creates and adds an OpSwitch used for the selection of OpAccessChain whose + // first Indexes operand is |access_chain_index_var_id|. The OpSwitch will be + // added at the end of |parent_block|. It will jump to |default_id| for the + // default case and jumps to one of case blocks whoes ids are |case_block_ids| + // if |access_chain_index_var_id| matches the case number. |merge_id| is the + // merge block id. + void AddSwitchForAccessChain( + BasicBlock* parent_block, uint32_t access_chain_index_var_id, + uint32_t default_id, uint32_t merge_id, + const std::vector& case_block_ids) const; + + // Creates a phi instruction with |phi_operands| as values and + // |case_block_ids| and |default_block_id| as incoming blocks. The size of + // |phi_operands| must be exactly 1 larger than the size of |case_block_ids|. + // The last element of |phi_operands| will be used for |default_block_id|. It + // adds the phi instruction to the beginning of |parent_block|. + uint32_t CreatePhiInstruction(BasicBlock* parent_block, + const std::vector& phi_operands, + const std::vector& case_block_ids, + uint32_t default_block_id) const; + + // Replaces the incoming block operand of OpPhi instructions with + // |new_incoming_block_id| if the incoming block operand is + // |old_incoming_block_id|. + void ReplacePhiIncomingBlock(uint32_t old_incoming_block_id, + uint32_t new_incoming_block_id) const; + + // Create an OpConstantNull instruction whose result type id is |type_id|. + Instruction* GetConstNull(uint32_t type_id) const; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_REPLACE_DESC_VAR_INDEX_ACCESS_H_ diff --git a/third_party/spirv-tools/source/opt/replace_invalid_opc.cpp b/third_party/spirv-tools/source/opt/replace_invalid_opc.cpp index 38b7539bf9..e3b9d3e403 100644 --- a/third_party/spirv-tools/source/opt/replace_invalid_opc.cpp +++ b/third_party/spirv-tools/source/opt/replace_invalid_opc.cpp @@ -71,10 +71,10 @@ bool ReplaceInvalidOpcodePass::RewriteFunction(Function* function, function->ForEachInst( [model, &modified, &last_line_dbg_inst, this](Instruction* inst) { // Track the debug information so we can have a meaningful message. - if (inst->opcode() == SpvOpLabel || inst->opcode() == SpvOpNoLine) { + if (inst->opcode() == SpvOpLabel || inst->IsNoLine()) { last_line_dbg_inst = nullptr; return; - } else if (inst->opcode() == SpvOpLine) { + } else if (inst->IsLine()) { last_line_dbg_inst = inst; return; } @@ -100,8 +100,18 @@ bool ReplaceInvalidOpcodePass::RewriteFunction(Function* function, ReplaceInstruction(inst, nullptr, 0, 0); } else { // Get the name of the source file. - Instruction* file_name = context()->get_def_use_mgr()->GetDef( - last_line_dbg_inst->GetSingleWordInOperand(0)); + uint32_t file_name_id = 0; + if (last_line_dbg_inst->opcode() == SpvOpLine) { + file_name_id = last_line_dbg_inst->GetSingleWordInOperand(0); + } else { // Shader100::DebugLine + uint32_t debug_source_id = + last_line_dbg_inst->GetSingleWordInOperand(2); + Instruction* debug_source_inst = + context()->get_def_use_mgr()->GetDef(debug_source_id); + file_name_id = debug_source_inst->GetSingleWordInOperand(2); + } + Instruction* file_name = + context()->get_def_use_mgr()->GetDef(file_name_id); const char* source = reinterpret_cast( &file_name->GetInOperand(0).words[0]); diff --git a/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp b/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp index 4d47bdd8df..4d6a7aadd5 100644 --- a/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp +++ b/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp @@ -27,6 +27,7 @@ static const uint32_t kDebugValueOperandValueIndex = 5; static const uint32_t kDebugValueOperandExpressionIndex = 6; +static const uint32_t kDebugDeclareOperandVariableIndex = 5; namespace spvtools { namespace opt { @@ -34,6 +35,10 @@ namespace opt { Pass::Status ScalarReplacementPass::Process() { Status status = Status::SuccessWithoutChange; for (auto& f : *get_module()) { + if (f.IsDeclaration()) { + continue; + } + Status functionStatus = ProcessFunction(&f); if (functionStatus == Status::Failure) return functionStatus; @@ -83,14 +88,14 @@ Pass::Status ScalarReplacementPass::ReplaceVariable( std::vector dead; bool replaced_all_uses = get_def_use_mgr()->WhileEachUser( inst, [this, &replacements, &dead](Instruction* user) { - if (user->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) { + if (user->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) { if (ReplaceWholeDebugDeclare(user, replacements)) { dead.push_back(user); return true; } return false; } - if (user->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) { + if (user->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) { if (ReplaceWholeDebugValue(user, replacements)) { dead.push_back(user); return true; @@ -172,10 +177,14 @@ bool ScalarReplacementPass::ReplaceWholeDebugDeclare( // Add DebugValue instruction with Indexes operand and Deref operation. int32_t idx = 0; for (const auto* var : replacements) { + Instruction* insert_before = var->NextNode(); + while (insert_before->opcode() == SpvOpVariable) + insert_before = insert_before->NextNode(); + assert(insert_before != nullptr && "unexpected end of list"); Instruction* added_dbg_value = context()->get_debug_info_mgr()->AddDebugValueForDecl( dbg_decl, /*value_id=*/var->result_id(), - /*insert_before=*/var->NextNode(), /*scope_and_line=*/dbg_decl); + /*insert_before=*/insert_before, /*scope_and_line=*/dbg_decl); if (added_dbg_value == nullptr) return false; added_dbg_value->AddOperand( @@ -504,7 +513,7 @@ void ScalarReplacementPass::CreateVariable( } } - // Update the OpenCL.DebugInfo.100 debug information. + // Update the DebugInfo debug information. inst->UpdateDebugInfoFrom(varInst); replacements->push_back(inst); @@ -791,8 +800,8 @@ bool ScalarReplacementPass::CheckUses(const Instruction* inst, get_def_use_mgr()->ForEachUse(inst, [this, max_legal_index, stats, &ok]( const Instruction* user, uint32_t index) { - if (user->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare || - user->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) { + if (user->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare || + user->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) { // TODO: include num_partial_accesses if it uses Fragment operation or // DebugValue has Indexes operand. stats->num_full_accesses++; @@ -864,6 +873,11 @@ bool ScalarReplacementPass::CheckUsesRelaxed(const Instruction* inst) const { case SpvOpImageTexelPointer: if (!CheckImageTexelPointer(index)) ok = false; break; + case SpvOpExtInst: + if (user->GetCommonDebugOpcode() != CommonDebugInfoDebugDeclare || + !CheckDebugDeclare(index)) + ok = false; + break; default: ok = false; break; @@ -894,6 +908,12 @@ bool ScalarReplacementPass::CheckStore(const Instruction* inst, return false; return true; } + +bool ScalarReplacementPass::CheckDebugDeclare(uint32_t index) const { + if (index != kDebugDeclareOperandVariableIndex) return false; + return true; +} + bool ScalarReplacementPass::IsLargerThanSizeLimit(uint64_t length) const { if (max_num_elements_ == 0) { return false; diff --git a/third_party/spirv-tools/source/opt/scalar_replacement_pass.h b/third_party/spirv-tools/source/opt/scalar_replacement_pass.h index 9e9f073948..0928830c07 100644 --- a/third_party/spirv-tools/source/opt/scalar_replacement_pass.h +++ b/third_party/spirv-tools/source/opt/scalar_replacement_pass.h @@ -142,6 +142,9 @@ class ScalarReplacementPass : public Pass { // of |inst| and the store is not to volatile memory. bool CheckStore(const Instruction* inst, uint32_t index) const; + // Returns true if the DebugDeclare can be scalarized at |index|. + bool CheckDebugDeclare(uint32_t index) const; + // Returns true if |index| is the pointer operand of an OpImageTexelPointer // instruction. bool CheckImageTexelPointer(uint32_t index) const; diff --git a/third_party/spirv-tools/source/opt/set_spec_constant_default_value_pass.cpp b/third_party/spirv-tools/source/opt/set_spec_constant_default_value_pass.cpp index 4c8d116f76..4def2b09a9 100644 --- a/third_party/spirv-tools/source/opt/set_spec_constant_default_value_pass.cpp +++ b/third_party/spirv-tools/source/opt/set_spec_constant_default_value_pass.cpp @@ -85,6 +85,10 @@ std::vector ParseDefaultValueStr(const char* text, // with 0x1, which represents a 'true'. // If all words in the bit pattern are zero, returns a bit pattern with 0x0, // which represents a 'false'. +// For integer and floating point types narrower than 32 bits, the upper bits +// in the input bit pattern are ignored. Instead the upper bits are set +// according to SPIR-V literal requirements: sign extend a signed integer, and +// otherwise set the upper bits to zero. std::vector ParseDefaultValueBitPattern( const std::vector& input_bit_pattern, const analysis::Type* type) { @@ -98,12 +102,33 @@ std::vector ParseDefaultValueBitPattern( } return result; } else if (const auto* IT = type->AsInteger()) { - if (IT->width() == input_bit_pattern.size() * sizeof(uint32_t) * 8) { - return std::vector(input_bit_pattern); + const auto width = IT->width(); + assert(width > 0); + const auto adjusted_width = std::max(32u, width); + if (adjusted_width == input_bit_pattern.size() * sizeof(uint32_t) * 8) { + result = std::vector(input_bit_pattern); + if (width < 32) { + const uint32_t high_active_bit = (1u << width) >> 1; + if (IT->IsSigned() && (high_active_bit & result[0])) { + // Sign extend. This overwrites the sign bit again, but that's ok. + result[0] = result[0] | ~(high_active_bit - 1); + } else { + // Upper bits must be zero. + result[0] = result[0] & ((1u << width) - 1); + } + } + return result; } } else if (const auto* FT = type->AsFloat()) { - if (FT->width() == input_bit_pattern.size() * sizeof(uint32_t) * 8) { - return std::vector(input_bit_pattern); + const auto width = FT->width(); + const auto adjusted_width = std::max(32u, width); + if (adjusted_width == input_bit_pattern.size() * sizeof(uint32_t) * 8) { + result = std::vector(input_bit_pattern); + if (width < 32) { + // Upper bits must be zero. + result[0] = result[0] & ((1u << width) - 1); + } + return result; } } result.clear(); diff --git a/third_party/spirv-tools/source/opt/simplification_pass.cpp b/third_party/spirv-tools/source/opt/simplification_pass.cpp index 319ceecfd4..43ec15f805 100644 --- a/third_party/spirv-tools/source/opt/simplification_pass.cpp +++ b/third_party/spirv-tools/source/opt/simplification_pass.cpp @@ -45,6 +45,10 @@ void SimplificationPass::AddNewOperands( } bool SimplificationPass::SimplifyFunction(Function* function) { + if (function->IsDeclaration()) { + return false; + } + bool modified = false; // Phase 1: Traverse all instructions in dominance order. // The second phase will only be on the instructions whose inputs have changed diff --git a/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp b/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp index 81770d779f..29ab6123f9 100644 --- a/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp +++ b/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp @@ -753,6 +753,9 @@ Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) { Pass::Status SSARewritePass::Process() { Status status = Status::SuccessWithoutChange; for (auto& fn : *get_module()) { + if (fn.IsDeclaration()) { + continue; + } status = CombineStatus(status, SSARewriter(this).RewriteFunctionIntoSSA(&fn)); // Kill DebugDeclares for target variables. diff --git a/third_party/spirv-tools/source/opt/value_number_table.cpp b/third_party/spirv-tools/source/opt/value_number_table.cpp index 32d6de94f9..5271e3fe92 100644 --- a/third_party/spirv-tools/source/opt/value_number_table.cpp +++ b/third_party/spirv-tools/source/opt/value_number_table.cpp @@ -50,7 +50,7 @@ uint32_t ValueNumberTable::AssignValueNumber(Instruction* inst) { // OpSampledImage and OpImage must remain in the same basic block in which // they are used, because of this we will assign each one it own value number. if (!context()->IsCombinatorInstruction(inst) && - !inst->IsOpenCL100DebugInstr()) { + !inst->IsCommonDebugInstr()) { value = TakeNextValueNumber(); id_to_value_[inst->result_id()] = value; return value; diff --git a/third_party/spirv-tools/source/opt/vector_dce.cpp b/third_party/spirv-tools/source/opt/vector_dce.cpp index 14a55c1eab..28d94a076f 100644 --- a/third_party/spirv-tools/source/opt/vector_dce.cpp +++ b/third_party/spirv-tools/source/opt/vector_dce.cpp @@ -52,7 +52,7 @@ void VectorDCE::FindLiveComponents(Function* function, // components are live because of arbitrary nesting of structs. function->ForEachInst( [&work_list, this, live_components](Instruction* current_inst) { - if (current_inst->IsOpenCL100DebugInstr()) { + if (current_inst->IsCommonDebugInstr()) { return; } if (!HasVectorOrScalarResult(current_inst) || @@ -110,7 +110,11 @@ void VectorDCE::MarkExtractUseAsLive(const Instruction* current_inst, if (current_inst->NumInOperands() < 2) { new_item.components = live_elements; } else { - new_item.components.Set(current_inst->GetSingleWordInOperand(1)); + uint32_t element_index = current_inst->GetSingleWordInOperand(1); + uint32_t item_size = GetVectorComponentCount(operand_inst->type_id()); + if (element_index < item_size) { + new_item.components.Set(element_index); + } } AddItemToWorkListIfNeeded(new_item, live_components, work_list); } @@ -176,10 +180,10 @@ void VectorDCE::MarkVectorShuffleUsesAsLive( second_operand.instruction = def_use_mgr->GetDef(current_item.instruction->GetSingleWordInOperand(1)); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::Vector* first_type = - type_mgr->GetType(first_operand.instruction->type_id())->AsVector(); - uint32_t size_of_first_operand = first_type->element_count(); + uint32_t size_of_first_operand = + GetVectorComponentCount(first_operand.instruction->type_id()); + uint32_t size_of_second_operand = + GetVectorComponentCount(second_operand.instruction->type_id()); for (uint32_t in_op = 2; in_op < current_item.instruction->NumInOperands(); ++in_op) { @@ -187,7 +191,7 @@ void VectorDCE::MarkVectorShuffleUsesAsLive( if (current_item.components.Get(in_op - 2)) { if (index < size_of_first_operand) { first_operand.components.Set(index); - } else { + } else if (index - size_of_first_operand < size_of_second_operand) { second_operand.components.Set(index - size_of_first_operand); } } @@ -202,7 +206,6 @@ void VectorDCE::MarkCompositeContructUsesAsLive( VectorDCE::LiveComponentMap* live_components, std::vector* work_list) { analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); uint32_t current_component = 0; Instruction* current_inst = work_item.instruction; @@ -223,8 +226,7 @@ void VectorDCE::MarkCompositeContructUsesAsLive( assert(HasVectorResult(op_inst)); WorkListItem new_work_item; new_work_item.instruction = op_inst; - uint32_t op_vector_size = - type_mgr->GetType(op_inst->type_id())->AsVector()->element_count(); + uint32_t op_vector_size = GetVectorComponentCount(op_inst->type_id()); for (uint32_t op_vector_idx = 0; op_vector_idx < op_vector_size; op_vector_idx++, current_component++) { @@ -297,6 +299,18 @@ bool VectorDCE::HasScalarResult(const Instruction* inst) const { } } +uint32_t VectorDCE::GetVectorComponentCount(uint32_t type_id) { + assert(type_id != 0 && + "Trying to get the vector element count, but the type id is 0"); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + const analysis::Type* type = type_mgr->GetType(type_id); + const analysis::Vector* vector_type = type->AsVector(); + assert( + vector_type && + "Trying to get the vector element count, but the type is not a vector"); + return vector_type->element_count(); +} + bool VectorDCE::RewriteInstructions( Function* function, const VectorDCE::LiveComponentMap& live_components) { bool modified = false; @@ -394,7 +408,7 @@ void VectorDCE::MarkDebugValueUsesAsDead( Instruction* composite, std::vector* dead_dbg_value) { context()->get_def_use_mgr()->ForEachUser( composite, [&dead_dbg_value](Instruction* use) { - if (use->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) + if (use->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) dead_dbg_value->push_back(use); }); } diff --git a/third_party/spirv-tools/source/opt/vector_dce.h b/third_party/spirv-tools/source/opt/vector_dce.h index 0df9aee13d..4d30b926b8 100644 --- a/third_party/spirv-tools/source/opt/vector_dce.h +++ b/third_party/spirv-tools/source/opt/vector_dce.h @@ -94,12 +94,15 @@ class VectorDCE : public MemPass { // Returns true if the result of |inst| is a vector or a scalar. bool HasVectorOrScalarResult(const Instruction* inst) const; - // Returns true if the result of |inst| is a scalar. + // Returns true if the result of |inst| is a vector. bool HasVectorResult(const Instruction* inst) const; - // Returns true if the result of |inst| is a vector. + // Returns true if the result of |inst| is a scalar. bool HasScalarResult(const Instruction* inst) const; + // Returns the number of elements in the vector type with id |type_id|. + uint32_t GetVectorComponentCount(uint32_t type_id); + // Adds |work_item| to |work_list| if it is not already live according to // |live_components|. |live_components| is updated to indicate that // |work_item| is now live. diff --git a/third_party/spirv-tools/source/spirv_constant.h b/third_party/spirv-tools/source/spirv_constant.h index 39771ccb26..8636806c54 100644 --- a/third_party/spirv-tools/source/spirv_constant.h +++ b/third_party/spirv-tools/source/spirv_constant.h @@ -84,6 +84,7 @@ typedef enum spv_generator_t { SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR = 6, SPV_GENERATOR_KHRONOS_ASSEMBLER = 7, SPV_GENERATOR_KHRONOS_GLSLANG = 8, + SPV_GENERATOR_KHRONOS_LINKER = 17, SPV_GENERATOR_NUM_ENTRIES, SPV_FORCE_16_BIT_ENUM(spv_generator_t) } spv_generator_t; diff --git a/third_party/spirv-tools/source/spirv_target_env.cpp b/third_party/spirv-tools/source/spirv_target_env.cpp index f20ebb4fb5..187ab61ec9 100644 --- a/third_party/spirv-tools/source/spirv_target_env.cpp +++ b/third_party/spirv-tools/source/spirv_target_env.cpp @@ -62,7 +62,7 @@ const char* spvTargetEnvDescription(spv_target_env env) { case SPV_ENV_VULKAN_1_1: return "SPIR-V 1.3 (under Vulkan 1.1 semantics)"; case SPV_ENV_WEBGPU_0: - assert(false); + assert(false && "Deprecated target environment value."); break; case SPV_ENV_UNIVERSAL_1_4: return "SPIR-V 1.4"; @@ -72,6 +72,9 @@ const char* spvTargetEnvDescription(spv_target_env env) { return "SPIR-V 1.5"; case SPV_ENV_VULKAN_1_2: return "SPIR-V 1.5 (under Vulkan 1.2 semantics)"; + case SPV_ENV_MAX: + assert(false && "Invalid target environment value."); + break; } return ""; } @@ -102,7 +105,7 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_1: return SPV_SPIRV_VERSION_WORD(1, 3); case SPV_ENV_WEBGPU_0: - assert(false); + assert(false && "Deprecated target environment value."); break; case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: @@ -110,6 +113,9 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: return SPV_SPIRV_VERSION_WORD(1, 5); + case SPV_ENV_MAX: + assert(false && "Invalid target environment value."); + break; } return SPV_SPIRV_VERSION_WORD(0, 0); } @@ -212,7 +218,10 @@ bool spvIsVulkanEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_2: return true; case SPV_ENV_WEBGPU_0: - assert(false); + assert(false && "Deprecated target environment value."); + break; + case SPV_ENV_MAX: + assert(false && "Invalid target environment value."); break; } return false; @@ -246,7 +255,10 @@ bool spvIsOpenCLEnv(spv_target_env env) { case SPV_ENV_OPENCL_2_2: return true; case SPV_ENV_WEBGPU_0: - assert(false); + assert(false && "Deprecated target environment value."); + break; + case SPV_ENV_MAX: + assert(false && "Invalid target environment value."); break; } return false; @@ -280,7 +292,43 @@ bool spvIsOpenGLEnv(spv_target_env env) { case SPV_ENV_OPENGL_4_5: return true; case SPV_ENV_WEBGPU_0: - assert(false); + assert(false && "Deprecated target environment value."); + break; + case SPV_ENV_MAX: + assert(false && "Invalid target environment value."); + break; + } + return false; +} + +bool spvIsValidEnv(spv_target_env env) { + switch (env) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_1: + case SPV_ENV_OPENCL_1_2: + case SPV_ENV_OPENCL_EMBEDDED_1_2: + case SPV_ENV_OPENCL_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_1: + case SPV_ENV_OPENCL_EMBEDDED_2_2: + case SPV_ENV_OPENCL_2_1: + case SPV_ENV_OPENCL_2_2: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + case SPV_ENV_UNIVERSAL_1_5: + case SPV_ENV_VULKAN_1_2: + case SPV_ENV_OPENGL_4_0: + case SPV_ENV_OPENGL_4_1: + case SPV_ENV_OPENGL_4_2: + case SPV_ENV_OPENGL_4_3: + case SPV_ENV_OPENGL_4_5: + return true; + case SPV_ENV_WEBGPU_0: + case SPV_ENV_MAX: break; } return false; @@ -320,7 +368,10 @@ std::string spvLogStringForEnv(spv_target_env env) { return "Universal"; } case SPV_ENV_WEBGPU_0: - assert(false); + assert(false && "Deprecated target environment value."); + break; + case SPV_ENV_MAX: + assert(false && "Invalid target environment value."); break; } return "Unknown"; diff --git a/third_party/spirv-tools/source/spirv_target_env.h b/third_party/spirv-tools/source/spirv_target_env.h index a804d615c5..cc06deca74 100644 --- a/third_party/spirv-tools/source/spirv_target_env.h +++ b/third_party/spirv-tools/source/spirv_target_env.h @@ -28,6 +28,9 @@ bool spvIsOpenCLEnv(spv_target_env env); // Returns true if |env| is an OPENGL environment, false otherwise. bool spvIsOpenGLEnv(spv_target_env env); +// Returns true if |env| is an implemented/valid environment, false otherwise. +bool spvIsValidEnv(spv_target_env env); + // Returns the version number for the given SPIR-V target environment. uint32_t spvVersionForTargetEnv(spv_target_env env); diff --git a/third_party/spirv-tools/source/spirv_validator_options.cpp b/third_party/spirv-tools/source/spirv_validator_options.cpp index 2716cca9be..e5b1eece0d 100644 --- a/third_party/spirv-tools/source/spirv_validator_options.cpp +++ b/third_party/spirv-tools/source/spirv_validator_options.cpp @@ -120,3 +120,8 @@ void spvValidatorOptionsSetSkipBlockLayout(spv_validator_options options, bool val) { options->skip_block_layout = val; } + +void spvValidatorOptionsSetAllowLocalSizeId(spv_validator_options options, + bool val) { + options->allow_localsizeid = val; +} diff --git a/third_party/spirv-tools/source/spirv_validator_options.h b/third_party/spirv-tools/source/spirv_validator_options.h index baaa5359e9..a357c031b5 100644 --- a/third_party/spirv-tools/source/spirv_validator_options.h +++ b/third_party/spirv-tools/source/spirv_validator_options.h @@ -47,6 +47,7 @@ struct spv_validator_options_t { scalar_block_layout(false), workgroup_scalar_block_layout(false), skip_block_layout(false), + allow_localsizeid(false), before_hlsl_legalization(false) {} validator_universal_limits_t universal_limits_; @@ -57,6 +58,7 @@ struct spv_validator_options_t { bool scalar_block_layout; bool workgroup_scalar_block_layout; bool skip_block_layout; + bool allow_localsizeid; bool before_hlsl_legalization; }; diff --git a/third_party/spirv-tools/source/text_handler.cpp b/third_party/spirv-tools/source/text_handler.cpp index c31f34a6bf..46b9845617 100644 --- a/third_party/spirv-tools/source/text_handler.cpp +++ b/third_party/spirv-tools/source/text_handler.cpp @@ -120,7 +120,8 @@ spv_result_t getWord(spv_text text, spv_position position, std::string* word) { case '\n': case '\r': if (escaping || quoting) break; - // Fall through. + word->assign(text->str + start_index, text->str + position->index); + return SPV_SUCCESS; case '\0': { // NOTE: End of word found! word->assign(text->str + start_index, text->str + position->index); return SPV_SUCCESS; diff --git a/third_party/spirv-tools/source/util/hex_float.h b/third_party/spirv-tools/source/util/hex_float.h index cfc40fa689..be28eae3ae 100644 --- a/third_party/spirv-tools/source/util/hex_float.h +++ b/third_party/spirv-tools/source/util/hex_float.h @@ -1005,6 +1005,9 @@ std::istream& operator>>(std::istream& is, HexFloat& value) { is.get(); next_char = is.peek(); } + + // Finished reading the part preceding any '.' or 'p'. + bits_written = false; while (seen_dot && !seen_p) { // Handle only fractional parts now. @@ -1037,11 +1040,16 @@ std::istream& operator>>(std::istream& is, HexFloat& value) { next_char = is.peek(); } + // Finished reading the part preceding 'p'. + // In hex floats syntax, the binary exponent is required. + bool seen_sign = false; int8_t exponent_sign = 1; + bool seen_written_exponent_digits = false; int_type written_exponent = 0; while (true) { - if ((next_char == '-' || next_char == '+')) { + if (!seen_written_exponent_digits && + (next_char == '-' || next_char == '+')) { if (seen_sign) { is.setstate(std::ios::failbit); return is; @@ -1049,6 +1057,7 @@ std::istream& operator>>(std::istream& is, HexFloat& value) { seen_sign = true; exponent_sign = (next_char == '-') ? -1 : 1; } else if (::isdigit(next_char)) { + seen_written_exponent_digits = true; // Hex-floats express their exponent as decimal. written_exponent = static_cast(written_exponent * 10); written_exponent = @@ -1059,6 +1068,11 @@ std::istream& operator>>(std::istream& is, HexFloat& value) { is.get(); next_char = is.peek(); } + if (!seen_written_exponent_digits) { + // Binary exponent had no digits. + is.setstate(std::ios::failbit); + return is; + } written_exponent = static_cast(written_exponent * exponent_sign); exponent = static_cast(exponent + written_exponent); diff --git a/third_party/spirv-tools/source/val/construct.cpp b/third_party/spirv-tools/source/val/construct.cpp index 5300869062..251e2bbaee 100644 --- a/third_party/spirv-tools/source/val/construct.cpp +++ b/third_party/spirv-tools/source/val/construct.cpp @@ -181,8 +181,9 @@ bool Construct::IsStructuredExit(ValidationState_t& _, BasicBlock* dest) const { for (auto& use : block->label()->uses()) { if ((use.first->opcode() == SpvOpLoopMerge || use.first->opcode() == SpvOpSelectionMerge) && - use.second == 1) + use.second == 1 && use.first->block()->dominates(*block)) { return use.first->block(); + } } return block->immediate_dominator(); }; diff --git a/third_party/spirv-tools/source/val/function.cpp b/third_party/spirv-tools/source/val/function.cpp index 249c8664fe..9ad68e8672 100644 --- a/third_party/spirv-tools/source/val/function.cpp +++ b/third_party/spirv-tools/source/val/function.cpp @@ -308,6 +308,9 @@ int Function::GetBlockDepth(BasicBlock* bb) { if (block_depth_.find(bb) != block_depth_.end()) { return block_depth_[bb]; } + // Avoid recursion. Something is wrong if the same block is encountered + // multiple times. + block_depth_[bb] = 0; BasicBlock* bb_dom = bb->immediate_dominator(); if (!bb_dom || bb == bb_dom) { diff --git a/third_party/spirv-tools/source/val/validate_adjacency.cpp b/third_party/spirv-tools/source/val/validate_adjacency.cpp index 64655b0dc7..8e6c373ea9 100644 --- a/third_party/spirv-tools/source/val/validate_adjacency.cpp +++ b/third_party/spirv-tools/source/val/validate_adjacency.cpp @@ -60,7 +60,10 @@ spv_result_t ValidateAdjacency(ValidationState_t& _) { // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We need // to discuss the location of DebugScope, DebugNoScope, DebugDeclare, // and DebugValue. - if (!spvExtInstIsDebugInfo(inst.ext_inst_type())) { + // NOTE: This does not apply to the non-semantic vulkan debug info. + if (!spvExtInstIsDebugInfo(inst.ext_inst_type()) || + inst.ext_inst_type() == + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { adjacency_status = PHI_AND_VAR_INVALID; } break; diff --git a/third_party/spirv-tools/source/val/validate_annotation.cpp b/third_party/spirv-tools/source/val/validate_annotation.cpp index 85d2b7515a..3a77552e18 100644 --- a/third_party/spirv-tools/source/val/validate_annotation.cpp +++ b/third_party/spirv-tools/source/val/validate_annotation.cpp @@ -138,14 +138,14 @@ std::string LogStringForDecoration(uint32_t decoration) { return "PerTaskNV"; case SpvDecorationPerVertexNV: return "PerVertexNV"; - case SpvDecorationNonUniformEXT: - return "NonUniformEXT"; - case SpvDecorationRestrictPointerEXT: - return "RestrictPointerEXT"; - case SpvDecorationAliasedPointerEXT: - return "AliasedPointerEXT"; - case SpvDecorationHlslCounterBufferGOOGLE: - return "HlslCounterBufferGOOGLE"; + case SpvDecorationNonUniform: + return "NonUniform"; + case SpvDecorationRestrictPointer: + return "RestrictPointer"; + case SpvDecorationAliasedPointer: + return "AliasedPointer"; + case SpvDecorationCounterBuffer: + return "CounterBuffer"; case SpvDecorationHlslSemanticGOOGLE: return "HlslSemanticGOOGLE"; default: @@ -156,8 +156,8 @@ std::string LogStringForDecoration(uint32_t decoration) { // Returns true if the decoration takes ID parameters. // TODO(dneto): This can be generated from the grammar. -bool DecorationTakesIdParameters(uint32_t type) { - switch (static_cast(type)) { +bool DecorationTakesIdParameters(SpvDecoration type) { + switch (type) { case SpvDecorationUniformId: case SpvDecorationAlignmentId: case SpvDecorationMaxByteOffsetId: @@ -169,17 +169,213 @@ bool DecorationTakesIdParameters(uint32_t type) { return false; } -spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { - const auto decoration = inst->GetOperandAs(1); - if (decoration == SpvDecorationSpecId) { - const auto target_id = inst->GetOperandAs(0); - const auto target = _.FindDef(target_id); - if (!target || !spvOpcodeIsScalarSpecConstant(target->opcode())) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpDecorate SpecId decoration target '" - << _.getIdName(target_id) - << "' is not a scalar specialization constant."; +bool IsMemberDecorationOnly(SpvDecoration dec) { + switch (dec) { + case SpvDecorationRowMajor: + case SpvDecorationColMajor: + case SpvDecorationMatrixStride: + // SPIR-V spec bug? Offset is generated on variables when dealing with + // transform feedback. + // case SpvDecorationOffset: + return true; + default: + break; + } + return false; +} + +bool IsNotMemberDecoration(SpvDecoration dec) { + switch (dec) { + case SpvDecorationSpecId: + case SpvDecorationBlock: + case SpvDecorationBufferBlock: + case SpvDecorationArrayStride: + case SpvDecorationGLSLShared: + case SpvDecorationGLSLPacked: + case SpvDecorationCPacked: + // TODO: https://github.com/KhronosGroup/glslang/issues/703: + // glslang applies Restrict to structure members. + // case SpvDecorationRestrict: + case SpvDecorationAliased: + case SpvDecorationConstant: + case SpvDecorationUniform: + case SpvDecorationUniformId: + case SpvDecorationSaturatedConversion: + case SpvDecorationIndex: + case SpvDecorationBinding: + case SpvDecorationDescriptorSet: + case SpvDecorationFuncParamAttr: + case SpvDecorationFPRoundingMode: + case SpvDecorationFPFastMathMode: + case SpvDecorationLinkageAttributes: + case SpvDecorationNoContraction: + case SpvDecorationInputAttachmentIndex: + case SpvDecorationAlignment: + case SpvDecorationMaxByteOffset: + case SpvDecorationAlignmentId: + case SpvDecorationMaxByteOffsetId: + case SpvDecorationNoSignedWrap: + case SpvDecorationNoUnsignedWrap: + case SpvDecorationNonUniform: + case SpvDecorationRestrictPointer: + case SpvDecorationAliasedPointer: + case SpvDecorationCounterBuffer: + return true; + default: + break; + } + return false; +} + +spv_result_t ValidateDecorationTarget(ValidationState_t& _, SpvDecoration dec, + const Instruction* inst, + const Instruction* target) { + auto fail = [&_, dec, inst, target](uint32_t vuid = 0) -> DiagnosticStream { + DiagnosticStream ds = std::move( + _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(vuid) << LogStringForDecoration(dec) + << " decoration on target '" << _.getIdName(target->id()) << "' "); + return ds; + }; + switch (dec) { + case SpvDecorationSpecId: + if (!spvOpcodeIsScalarSpecConstant(target->opcode())) { + return fail() << "must be a scalar specialization constant"; + } + break; + case SpvDecorationBlock: + case SpvDecorationBufferBlock: + case SpvDecorationGLSLShared: + case SpvDecorationGLSLPacked: + case SpvDecorationCPacked: + if (target->opcode() != SpvOpTypeStruct) { + return fail() << "must be a structure type"; + } + break; + case SpvDecorationArrayStride: + if (target->opcode() != SpvOpTypeArray && + target->opcode() != SpvOpTypeRuntimeArray && + target->opcode() != SpvOpTypePointer) { + return fail() << "must be an array or pointer type"; + } + break; + case SpvDecorationBuiltIn: + if (target->opcode() != SpvOpVariable && + !spvOpcodeIsConstant(target->opcode())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "BuiltIns can only target variables, structure members or " + "constants"; + } + if (_.HasCapability(SpvCapabilityShader) && + inst->GetOperandAs(2) == SpvBuiltInWorkgroupSize) { + if (!spvOpcodeIsConstant(target->opcode())) { + return fail() << "must be a constant for WorkgroupSize"; + } + } else if (target->opcode() != SpvOpVariable) { + return fail() << "must be a variable"; + } + break; + case SpvDecorationNoPerspective: + case SpvDecorationFlat: + case SpvDecorationPatch: + case SpvDecorationCentroid: + case SpvDecorationSample: + case SpvDecorationRestrict: + case SpvDecorationAliased: + case SpvDecorationVolatile: + case SpvDecorationCoherent: + case SpvDecorationNonWritable: + case SpvDecorationNonReadable: + case SpvDecorationXfbBuffer: + case SpvDecorationXfbStride: + case SpvDecorationComponent: + case SpvDecorationStream: + case SpvDecorationRestrictPointer: + case SpvDecorationAliasedPointer: + if (target->opcode() != SpvOpVariable && + target->opcode() != SpvOpFunctionParameter) { + return fail() << "must be a memory object declaration"; + } + if (_.GetIdOpcode(target->type_id()) != SpvOpTypePointer) { + return fail() << "must be a pointer type"; + } + break; + case SpvDecorationInvariant: + case SpvDecorationConstant: + case SpvDecorationLocation: + case SpvDecorationIndex: + case SpvDecorationBinding: + case SpvDecorationDescriptorSet: + case SpvDecorationInputAttachmentIndex: + if (target->opcode() != SpvOpVariable) { + return fail() << "must be a variable"; + } + break; + default: + break; + } + + if (spvIsVulkanEnv(_.context()->target_env)) { + // The following were all checked as pointer types above. + SpvStorageClass sc = SpvStorageClassUniform; + const auto type = _.FindDef(target->type_id()); + if (type && type->operands().size() > 2) { + sc = type->GetOperandAs(1); } + switch (dec) { + case SpvDecorationLocation: + case SpvDecorationComponent: + // Location is used for input, output and ray tracing stages. + if (sc == SpvStorageClassStorageBuffer || + sc == SpvStorageClassUniform || + sc == SpvStorageClassUniformConstant || + sc == SpvStorageClassWorkgroup || sc == SpvStorageClassPrivate || + sc == SpvStorageClassFunction) { + return _.diag(SPV_ERROR_INVALID_ID, target) + << LogStringForDecoration(dec) + << " decoration must not be applied to this storage class"; + } + break; + case SpvDecorationIndex: + if (sc != SpvStorageClassOutput) { + return fail() << "must be in the Output storage class"; + } + break; + case SpvDecorationBinding: + case SpvDecorationDescriptorSet: + if (sc != SpvStorageClassStorageBuffer && + sc != SpvStorageClassUniform && + sc != SpvStorageClassUniformConstant) { + return fail() << "must be in the StorageBuffer, Uniform, or " + "UniformConstant storage class"; + } + break; + case SpvDecorationInputAttachmentIndex: + if (sc != SpvStorageClassUniformConstant) { + return fail() << "must be in the UniformConstant storage class"; + } + break; + case SpvDecorationFlat: + case SpvDecorationNoPerspective: + case SpvDecorationCentroid: + case SpvDecorationSample: + if (sc != SpvStorageClassInput && sc != SpvStorageClassOutput) { + return fail(4670) << "storage class must be Input or Output"; + } + break; + default: + break; + } + } + return SPV_SUCCESS; +} + +spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { + const auto decoration = inst->GetOperandAs(1); + const auto target_id = inst->GetOperandAs(0); + const auto target = _.FindDef(target_id); + if (!target) { + return _.diag(SPV_ERROR_INVALID_ID, inst) << "target is not defined"; } if (spvIsVulkanEnv(_.context()->target_env)) { @@ -197,17 +393,34 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { << "Decorations taking ID parameters may not be used with " "OpDecorateId"; } + + if (target->opcode() != SpvOpDecorationGroup) { + if (IsMemberDecorationOnly(decoration)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << LogStringForDecoration(decoration) + << " can only be applied to structure members"; + } + + if (auto error = ValidateDecorationTarget(_, decoration, inst, target)) { + return error; + } + } + // TODO: Add validations for all decorations. return SPV_SUCCESS; } spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) { - const auto decoration = inst->GetOperandAs(1); + const auto decoration = inst->GetOperandAs(1); if (!DecorationTakesIdParameters(decoration)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Decorations that don't take ID parameters may not be used with " "OpDecorateId"; } + + // No member decorations take id parameters, so we don't bother checking if + // we are using a member only decoration here. + // TODO: Add validations for these decorations. // UniformId is covered elsewhere. return SPV_SUCCESS; @@ -234,6 +447,13 @@ spv_result_t ValidateMemberDecorate(ValidationState_t& _, << " members. Largest valid index is " << member_count - 1 << "."; } + const auto decoration = inst->GetOperandAs(2); + if (IsNotMemberDecoration(decoration)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << LogStringForDecoration(decoration) + << " cannot be applied to structure members"; + } + return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/val/validate_atomics.cpp b/third_party/spirv-tools/source/val/validate_atomics.cpp index da023b80c5..cfa15d9f72 100644 --- a/third_party/spirv-tools/source/val/validate_atomics.cpp +++ b/third_party/spirv-tools/source/val/validate_atomics.cpp @@ -184,7 +184,7 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { } // Can't use result_type because OpAtomicStore doesn't have a result - if (_.GetBitWidth(data_type) == 64 && _.IsIntScalarType(data_type) && + if ( _.IsIntScalarType(data_type) &&_.GetBitWidth(data_type) == 64 && !_.HasCapability(SpvCapabilityInt64Atomics)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) diff --git a/third_party/spirv-tools/source/val/validate_builtins.cpp b/third_party/spirv-tools/source/val/validate_builtins.cpp index 3c9df9fc2d..57dde8ad92 100644 --- a/third_party/spirv-tools/source/val/validate_builtins.cpp +++ b/third_party/spirv-tools/source/val/validate_builtins.cpp @@ -2846,7 +2846,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) - << " to be used only with GLCompute execution model. " + << " to be used only with GLCompute, MeshNV, or TaskNV execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); } @@ -2928,7 +2928,7 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) - << " to be used only with GLCompute execution model. " + << " to be used only with GLCompute, MeshNV, or TaskNV execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); } @@ -3070,14 +3070,16 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { for (const SpvExecutionModel execution_model : execution_models_) { - if (execution_model != SpvExecutionModelGLCompute) { + if (execution_model != SpvExecutionModelGLCompute && + execution_model != SpvExecutionModelTaskNV && + execution_model != SpvExecutionModelMeshNV) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(4425) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) - << " to be used only with GLCompute execution model. " + << " to be used only with GLCompute, MeshNV, or TaskNV execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); } @@ -3991,14 +3993,6 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]); - // Builtins can only be applied to variables, structures or constants. - auto target_opcode = inst.opcode(); - if (target_opcode != SpvOpTypeStruct && target_opcode != SpvOpVariable && - !spvOpcodeIsConstant(target_opcode)) { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "BuiltIns can only target variables, structs or constants"; - } - if (!spvIsVulkanEnv(_.context()->target_env)) { // Early return. All currently implemented rules are based on Vulkan spec. // @@ -4190,6 +4184,7 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInMeshViewIndicesNV: case SpvBuiltInBaryCoordNV: case SpvBuiltInBaryCoordNoPerspNV: + case SpvBuiltInCurrentRayTimeNV: // No validation rules (for the moment). break; diff --git a/third_party/spirv-tools/source/val/validate_cfg.cpp b/third_party/spirv-tools/source/val/validate_cfg.cpp index 36f632a8d8..7842e56de2 100644 --- a/third_party/spirv-tools/source/val/validate_cfg.cpp +++ b/third_party/spirv-tools/source/val/validate_cfg.cpp @@ -199,6 +199,18 @@ spv_result_t ValidateSwitch(ValidationState_t& _, const Instruction* inst) { // At least two operands (selector, default), any more than that are // literal/target. + const auto sel_type_id = _.GetOperandTypeId(inst, 0); + if (!_.IsIntScalarType(sel_type_id)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Selector type must be OpTypeInt"; + } + + const auto default_label = _.FindDef(inst->GetOperandAs(1)); + if (default_label->opcode() != SpvOpLabel) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Default must be an OpLabel instruction"; + } + // target operands must be OpLabel for (size_t i = 2; i < num_operands; i += 2) { // literal, id @@ -647,9 +659,9 @@ spv_result_t ValidateStructuredSelections( // Mark the upcoming blocks as seen now, but only error out if this block // was missing a merge instruction and both labels hadn't been seen // previously. - const bool both_unseen = - seen.insert(true_label).second && seen.insert(false_label).second; - if (!merge && both_unseen) { + const bool true_label_unseen = seen.insert(true_label).second; + const bool false_label_unseen = seen.insert(false_label).second; + if (!merge && true_label_unseen && false_label_unseen) { return _.diag(SPV_ERROR_INVALID_CFG, terminator) << "Selection must be structured"; } diff --git a/third_party/spirv-tools/source/val/validate_decorations.cpp b/third_party/spirv-tools/source/val/validate_decorations.cpp index f076b04c76..3cdb471c70 100644 --- a/third_party/spirv-tools/source/val/validate_decorations.cpp +++ b/third_party/spirv-tools/source/val/validate_decorations.cpp @@ -129,18 +129,30 @@ std::vector getStructMembers(uint32_t struct_id, SpvOp type, // Returns whether the given structure is missing Offset decoration for any // member. Handles also nested structures. bool isMissingOffsetInStruct(uint32_t struct_id, ValidationState_t& vstate) { - std::vector hasOffset(getStructMembers(struct_id, vstate).size(), - false); - // Check offsets of member decorations - for (auto& decoration : vstate.id_decorations(struct_id)) { - if (SpvDecorationOffset == decoration.dec_type() && - Decoration::kInvalidMember != decoration.struct_member_index()) { - hasOffset[decoration.struct_member_index()] = true; + const auto* inst = vstate.FindDef(struct_id); + std::vector hasOffset; + std::vector struct_members; + if (inst->opcode() == SpvOpTypeStruct) { + // Check offsets of member decorations. + struct_members = getStructMembers(struct_id, vstate); + hasOffset.resize(struct_members.size(), false); + + for (auto& decoration : vstate.id_decorations(struct_id)) { + if (SpvDecorationOffset == decoration.dec_type() && + Decoration::kInvalidMember != decoration.struct_member_index()) { + // Offset 0xffffffff is not valid so ignore it for simplicity's sake. + if (decoration.params()[0] == 0xffffffff) return true; + hasOffset[decoration.struct_member_index()] = true; + } } + } else if (inst->opcode() == SpvOpTypeArray || + inst->opcode() == SpvOpTypeRuntimeArray) { + hasOffset.resize(1, true); + struct_members.push_back(inst->GetOperandAs(1u)); } - // Check also nested structures + // Look through nested structs (which may be in an array). bool nestedStructsMissingOffset = false; - for (auto id : getStructMembers(struct_id, SpvOpTypeStruct, vstate)) { + for (auto id : struct_members) { if (isMissingOffsetInStruct(id, vstate)) { nestedStructsMissingOffset = true; break; @@ -506,12 +518,10 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, return recursive_status; // Check matrix stride. if (SpvOpTypeMatrix == opcode) { - for (auto& decoration : vstate.id_decorations(id)) { - if (SpvDecorationMatrixStride == decoration.dec_type() && - !IsAlignedTo(decoration.params()[0], alignment)) - return fail(memberIdx) - << "is a matrix with stride " << decoration.params()[0] - << " not satisfying alignment to " << alignment; + const auto stride = constraint.matrix_stride; + if (!IsAlignedTo(stride, alignment)) { + return fail(memberIdx) << "is a matrix with stride " << stride + << " not satisfying alignment to " << alignment; } } @@ -549,17 +559,23 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, // limitation to this check if the array size is a spec constant or is a // runtime array then we will only check a single element. This means // some improper straddles might be missed. - for (uint32_t i = 0; i < num_elements; ++i) { - uint32_t next_offset = i * array_stride + offset; - if (SpvOpTypeStruct == element_inst->opcode() && - SPV_SUCCESS != (recursive_status = checkLayout( - typeId, storage_class_str, decoration_str, - blockRules, scalar_block_layout, - next_offset, constraints, vstate))) - return recursive_status; - // If offsets accumulate up to a 16-byte multiple stop checking since - // it will just repeat. - if (i > 0 && (next_offset % 16 == 0)) break; + if (SpvOpTypeStruct == element_inst->opcode()) { + std::vector seen(16, false); + for (uint32_t i = 0; i < num_elements; ++i) { + uint32_t next_offset = i * array_stride + offset; + // Stop checking if offsets repeat in terms of 16-byte multiples. + if (seen[next_offset % 16]) { + break; + } + + if (SPV_SUCCESS != + (recursive_status = checkLayout( + typeId, storage_class_str, decoration_str, blockRules, + scalar_block_layout, next_offset, constraints, vstate))) + return recursive_status; + + seen[next_offset % 16] = true; + } } // Proceed to the element in case it is an array. @@ -981,7 +997,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { const bool phys_storage_buffer = storageClass == SpvStorageClassPhysicalStorageBufferEXT; - const bool workgroup = storageClass == SpvStorageClassWorkgroup; + const bool workgroup = + storageClass == SpvStorageClassWorkgroup && + vstate.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayoutKHR); if (uniform || push_constant || storage_buffer || phys_storage_buffer || workgroup) { const auto ptrInst = vstate.FindDef(words[1]); diff --git a/third_party/spirv-tools/source/val/validate_derivatives.cpp b/third_party/spirv-tools/source/val/validate_derivatives.cpp index 067cc964ce..25b941abaf 100644 --- a/third_party/spirv-tools/source/val/validate_derivatives.cpp +++ b/third_party/spirv-tools/source/val/validate_derivatives.cpp @@ -79,11 +79,13 @@ spv_result_t DerivativesPass(ValidationState_t& _, const Instruction* inst) { std::string* message) { const auto* models = state.GetExecutionModels(entry_point->id()); const auto* modes = state.GetExecutionModes(entry_point->id()); - if (models->find(SpvExecutionModelGLCompute) != models->end() && - modes->find(SpvExecutionModeDerivativeGroupLinearNV) == - modes->end() && - modes->find(SpvExecutionModeDerivativeGroupQuadsNV) == - modes->end()) { + if (models && + models->find(SpvExecutionModelGLCompute) != models->end() && + (!modes || + (modes->find(SpvExecutionModeDerivativeGroupLinearNV) == + modes->end() && + modes->find(SpvExecutionModeDerivativeGroupQuadsNV) == + modes->end()))) { if (message) { *message = std::string( "Derivative instructions require " diff --git a/third_party/spirv-tools/source/val/validate_extensions.cpp b/third_party/spirv-tools/source/val/validate_extensions.cpp index b5b98783e3..dccbe14908 100644 --- a/third_party/spirv-tools/source/val/validate_extensions.cpp +++ b/third_party/spirv-tools/source/val/validate_extensions.cpp @@ -20,7 +20,9 @@ #include "spirv/unified1/NonSemanticClspvReflection.h" +#include "NonSemanticShaderDebugInfo100.h" #include "OpenCLDebugInfo100.h" +#include "source/common_debug_info.h" #include "source/diagnostic.h" #include "source/enum_string_mapping.h" #include "source/extensions.h" @@ -45,6 +47,34 @@ uint32_t GetSizeTBitWidth(const ValidationState_t& _) { return 0; } +bool IsIntScalar(ValidationState_t& _, uint32_t id, bool must_len32, + bool must_unsigned) { + auto type = _.FindDef(id); + if (!type || type->opcode() != SpvOpTypeInt) { + return false; + } + + if (must_len32 && type->GetOperandAs(1) != 32) { + return false; + } + + return !must_unsigned || type->GetOperandAs(2) == 0; +} + +bool IsUint32Constant(ValidationState_t& _, uint32_t id) { + auto inst = _.FindDef(id); + if (!inst || inst->opcode() != SpvOpConstant) { + return false; + } + + return IsIntScalar(_, inst->type_id(), true, true); +} + +uint32_t GetUint32Constant(ValidationState_t& _, uint32_t id) { + auto inst = _.FindDef(id); + return inst->word(3); +} + // Check that the operand of a debug info instruction |inst| at |word_index| // is a result id of an instruction with |expected_opcode|. spv_result_t ValidateOperandForDebugInfo( @@ -68,6 +98,22 @@ spv_result_t ValidateOperandForDebugInfo( return SPV_SUCCESS; } +// For NonSemantic.Shader.DebugInfo.100 check that the operand of a debug info +// instruction |inst| at |word_index| is a result id of a 32-bit integer +// OpConstant instruction. For OpenCL.DebugInfo.100 the parameter is a literal +// word so cannot be validated. +spv_result_t ValidateUint32ConstantOperandForDebugInfo( + ValidationState_t& _, const std::string& operand_name, + const Instruction* inst, uint32_t word_index, + const std::function& ext_inst_name) { + if (!IsUint32Constant(_, inst->word(word_index))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": expected operand " << operand_name + << " must be a result id of 32-bit unsigned OpConstant"; + } + return SPV_SUCCESS; +} + #define CHECK_OPERAND(NAME, opcode, index) \ do { \ auto result = ValidateOperandForDebugInfo(_, NAME, opcode, inst, index, \ @@ -75,18 +121,27 @@ spv_result_t ValidateOperandForDebugInfo( if (result != SPV_SUCCESS) return result; \ } while (0) +#define CHECK_CONST_UINT_OPERAND(NAME, index) \ + if (vulkanDebugInfo) { \ + auto result = ValidateUint32ConstantOperandForDebugInfo( \ + _, NAME, inst, index, ext_inst_name); \ + if (result != SPV_SUCCESS) return result; \ + } + // True if the operand of a debug info instruction |inst| at |word_index| // satisifies |expectation| that is given as a function. Otherwise, // returns false. bool DoesDebugInfoOperandMatchExpectation( const ValidationState_t& _, - const std::function& expectation, + const std::function& expectation, const Instruction* inst, uint32_t word_index) { if (inst->words().size() <= word_index) return false; auto* debug_inst = _.FindDef(inst->word(word_index)); if (debug_inst->opcode() != SpvOpExtInst || - debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || - !expectation(OpenCLDebugInfo100Instructions(debug_inst->word(4)))) { + (debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 && + debug_inst->ext_inst_type() != + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) || + !expectation(CommonDebugInfoInstructions(debug_inst->word(4)))) { return false; } return true; @@ -97,20 +152,18 @@ bool DoesDebugInfoOperandMatchExpectation( // is |expected_debug_inst|. spv_result_t ValidateDebugInfoOperand( ValidationState_t& _, const std::string& debug_inst_name, - OpenCLDebugInfo100Instructions expected_debug_inst, const Instruction* inst, + CommonDebugInfoInstructions expected_debug_inst, const Instruction* inst, uint32_t word_index, const std::function& ext_inst_name) { - std::function expectation = - [expected_debug_inst](OpenCLDebugInfo100Instructions dbg_inst) { + std::function expectation = + [expected_debug_inst](CommonDebugInfoInstructions dbg_inst) { return dbg_inst == expected_debug_inst; }; if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) return SPV_SUCCESS; spv_ext_inst_desc desc = nullptr; - _.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, - expected_debug_inst, &desc); - if (_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, - expected_debug_inst, &desc) != SPV_SUCCESS || + if (_.grammar().lookupExtInst(inst->ext_inst_type(), expected_debug_inst, + &desc) != SPV_SUCCESS || !desc) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " @@ -134,9 +187,8 @@ spv_result_t ValidateDebugInfoOperand( spv_result_t ValidateOperandBaseType( ValidationState_t& _, const Instruction* inst, uint32_t word_index, const std::function& ext_inst_name) { - return ValidateDebugInfoOperand(_, "Base Type", - OpenCLDebugInfo100DebugTypeBasic, inst, - word_index, ext_inst_name); + return ValidateDebugInfoOperand(_, "Base Type", CommonDebugInfoDebugTypeBasic, + inst, word_index, ext_inst_name); } // Check that the operand of a debug info instruction |inst| at |word_index| @@ -147,12 +199,12 @@ spv_result_t ValidateOperandLexicalScope( ValidationState_t& _, const std::string& debug_inst_name, const Instruction* inst, uint32_t word_index, const std::function& ext_inst_name) { - std::function expectation = - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugCompilationUnit || - dbg_inst == OpenCLDebugInfo100DebugFunction || - dbg_inst == OpenCLDebugInfo100DebugLexicalBlock || - dbg_inst == OpenCLDebugInfo100DebugTypeComposite; + std::function expectation = + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugCompilationUnit || + dbg_inst == CommonDebugInfoDebugFunction || + dbg_inst == CommonDebugInfoDebugLexicalBlock || + dbg_inst == CommonDebugInfoDebugTypeComposite; }; if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) return SPV_SUCCESS; @@ -171,16 +223,15 @@ spv_result_t ValidateOperandDebugType( const Instruction* inst, uint32_t word_index, const std::function& ext_inst_name, bool allow_template_param) { - std::function expectation = - [&allow_template_param](OpenCLDebugInfo100Instructions dbg_inst) { + std::function expectation = + [&allow_template_param](CommonDebugInfoInstructions dbg_inst) { if (allow_template_param && - (dbg_inst == OpenCLDebugInfo100DebugTypeTemplateParameter || - dbg_inst == - OpenCLDebugInfo100DebugTypeTemplateTemplateParameter)) { + (dbg_inst == CommonDebugInfoDebugTypeTemplateParameter || + dbg_inst == CommonDebugInfoDebugTypeTemplateTemplateParameter)) { return true; } - return OpenCLDebugInfo100DebugTypeBasic <= dbg_inst && - dbg_inst <= OpenCLDebugInfo100DebugTypeTemplate; + return CommonDebugInfoDebugTypeBasic <= dbg_inst && + dbg_inst <= CommonDebugInfoDebugTypeTemplate; }; if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) return SPV_SUCCESS; @@ -191,28 +242,6 @@ spv_result_t ValidateOperandDebugType( << " is not a valid debug type"; } -bool IsUint32Constant(ValidationState_t& _, uint32_t id) { - auto inst = _.FindDef(id); - if (!inst || inst->opcode() != SpvOpConstant) { - return false; - } - - auto type = _.FindDef(inst->type_id()); - if (!type || type->opcode() != SpvOpTypeInt) { - return false; - } - - if (type->GetOperandAs(1) != 32) { - return false; - } - - if (type->GetOperandAs(2) != 0) { - return false; - } - - return true; -} - spv_result_t ValidateClspvReflectionKernel(ValidationState_t& _, const Instruction* inst) { const auto kernel_id = inst->GetOperandAs(4); @@ -667,18 +696,26 @@ bool IsDebugVariableWithIntScalarType(ValidationState_t& _, const Instruction* inst, uint32_t word_index) { auto* dbg_int_scalar_var = _.FindDef(inst->word(word_index)); - if (OpenCLDebugInfo100Instructions(dbg_int_scalar_var->word(4)) == - OpenCLDebugInfo100DebugLocalVariable || - OpenCLDebugInfo100Instructions(dbg_int_scalar_var->word(4)) == - OpenCLDebugInfo100DebugGlobalVariable) { + if (CommonDebugInfoInstructions(dbg_int_scalar_var->word(4)) == + CommonDebugInfoDebugLocalVariable || + CommonDebugInfoInstructions(dbg_int_scalar_var->word(4)) == + CommonDebugInfoDebugGlobalVariable) { auto* dbg_type = _.FindDef(dbg_int_scalar_var->word(6)); - if (OpenCLDebugInfo100Instructions(dbg_type->word(4)) == - OpenCLDebugInfo100DebugTypeBasic && - (OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(dbg_type->word(7)) == - OpenCLDebugInfo100Signed || - OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(dbg_type->word(7)) == - OpenCLDebugInfo100Unsigned)) { - return true; + if (CommonDebugInfoInstructions(dbg_type->word(4)) == + CommonDebugInfoDebugTypeBasic) { + const spv_ext_inst_type_t ext_inst_type = + spv_ext_inst_type_t(inst->ext_inst_type()); + const bool vulkanDebugInfo = + ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100; + uint32_t encoding = dbg_type->word(7); + if (!vulkanDebugInfo || IsUint32Constant(_, encoding)) { + auto ocl_encoding = OpenCLDebugInfo100DebugBaseTypeAttributeEncoding( + vulkanDebugInfo ? GetUint32Constant(_, encoding) : encoding); + if (ocl_encoding == OpenCLDebugInfo100Signed || + ocl_encoding == OpenCLDebugInfo100Unsigned) { + return true; + } + } } } return false; @@ -812,7 +849,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { for (uint32_t operand_index = 4; operand_index < num_operands; ++operand_index) { const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); - if (!_.IsIntScalarOrVectorType(operand_type)) { + if (!operand_type || !_.IsIntScalarOrVectorType(operand_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " << "expected all operands to be int scalars or vectors"; @@ -2668,7 +2705,9 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { break; } } - } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { + } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || + ext_inst_type == + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { if (!_.IsVoidType(result_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " @@ -2676,447 +2715,552 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { << "OpTypeVoid"; } + const bool vulkanDebugInfo = + ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100; + auto num_words = inst->words().size(); - const OpenCLDebugInfo100Instructions ext_inst_key = - OpenCLDebugInfo100Instructions(ext_inst_index); - switch (ext_inst_key) { - case OpenCLDebugInfo100DebugInfoNone: - case OpenCLDebugInfo100DebugNoScope: - case OpenCLDebugInfo100DebugOperation: - // The binary parser validates the opcode for DebugInfoNone, - // DebugNoScope, DebugOperation, and the literal values don't need - // further checks. - break; - case OpenCLDebugInfo100DebugCompilationUnit: { - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - break; - } - case OpenCLDebugInfo100DebugSource: { - CHECK_OPERAND("File", SpvOpString, 5); - if (num_words == 7) CHECK_OPERAND("Text", SpvOpString, 6); - break; - } - case OpenCLDebugInfo100DebugTypeBasic: { - CHECK_OPERAND("Name", SpvOpString, 5); - CHECK_OPERAND("Size", SpvOpConstant, 6); - // "Encoding" param is already validated by the binary parsing stage. - break; - } - case OpenCLDebugInfo100DebugTypePointer: - case OpenCLDebugInfo100DebugTypeQualifier: { - auto validate_base_type = - ValidateOperandBaseType(_, inst, 5, ext_inst_name); - if (validate_base_type != SPV_SUCCESS) return validate_base_type; - break; - } - case OpenCLDebugInfo100DebugTypeVector: { - auto validate_base_type = - ValidateOperandBaseType(_, inst, 5, ext_inst_name); - if (validate_base_type != SPV_SUCCESS) return validate_base_type; - - uint32_t component_count = inst->word(6); - if (!component_count || component_count > 4) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": Component Count must be positive " - << "integer less than or equal to 4"; + // Handle any non-common OpenCL insts, then common + if (ext_inst_type != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || + OpenCLDebugInfo100Instructions(ext_inst_index) != + OpenCLDebugInfo100DebugModuleINTEL) { + const CommonDebugInfoInstructions ext_inst_key = + CommonDebugInfoInstructions(ext_inst_index); + switch (ext_inst_key) { + case CommonDebugInfoDebugInfoNone: + case CommonDebugInfoDebugNoScope: + break; + // The binary parser validates the opcode for DebugInfoNone, + // DebugNoScope, DebugOperation. We just check the parameters to + // DebugOperation are properly constants for vulkan debug info. + case CommonDebugInfoDebugOperation: { + CHECK_CONST_UINT_OPERAND("Operation", 5); + for (uint32_t i = 6; i < num_words; ++i) { + CHECK_CONST_UINT_OPERAND("Operand", i); + } + break; } - break; - } - case OpenCLDebugInfo100DebugTypeArray: { - auto validate_base_type = ValidateOperandDebugType( - _, "Base Type", inst, 5, ext_inst_name, false); - if (validate_base_type != SPV_SUCCESS) return validate_base_type; - for (uint32_t i = 6; i < num_words; ++i) { - bool invalid = false; - auto* component_count = _.FindDef(inst->word(i)); - if (IsConstIntScalarTypeWith32Or64Bits(_, component_count)) { - // TODO: We need a spec discussion for the bindless array. - if (!component_count->word(3)) { - invalid = true; + case CommonDebugInfoDebugCompilationUnit: { + CHECK_CONST_UINT_OPERAND("Version", 5); + CHECK_CONST_UINT_OPERAND("DWARF Version", 6); + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Language", 8); + break; + } + case CommonDebugInfoDebugSource: { + CHECK_OPERAND("File", SpvOpString, 5); + if (num_words == 7) CHECK_OPERAND("Text", SpvOpString, 6); + break; + } + case CommonDebugInfoDebugTypeBasic: { + CHECK_OPERAND("Name", SpvOpString, 5); + CHECK_OPERAND("Size", SpvOpConstant, 6); + CHECK_CONST_UINT_OPERAND("Encoding", 7); + break; + } + case CommonDebugInfoDebugTypePointer: { + auto validate_base_type = + ValidateOperandBaseType(_, inst, 5, ext_inst_name); + if (validate_base_type != SPV_SUCCESS) return validate_base_type; + CHECK_CONST_UINT_OPERAND("Storage Class", 6); + CHECK_CONST_UINT_OPERAND("Flags", 7); + break; + } + case CommonDebugInfoDebugTypeQualifier: { + auto validate_base_type = + ValidateOperandBaseType(_, inst, 5, ext_inst_name); + if (validate_base_type != SPV_SUCCESS) return validate_base_type; + CHECK_CONST_UINT_OPERAND("Type Qualifier", 6); + break; + } + case CommonDebugInfoDebugTypeVector: { + auto validate_base_type = + ValidateOperandBaseType(_, inst, 5, ext_inst_name); + if (validate_base_type != SPV_SUCCESS) return validate_base_type; + + CHECK_CONST_UINT_OPERAND("Component Count", 6); + uint32_t component_count = inst->word(6); + if (vulkanDebugInfo) { + uint64_t const_val; + if (!_.GetConstantValUint64(component_count, &const_val)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() + << ": Component Count must be 32-bit integer OpConstant"; } - } else if (component_count->words().size() > 6 && - (OpenCLDebugInfo100Instructions(component_count->word( - 4)) == OpenCLDebugInfo100DebugLocalVariable || - OpenCLDebugInfo100Instructions(component_count->word( - 4)) == OpenCLDebugInfo100DebugGlobalVariable)) { - auto* component_count_type = _.FindDef(component_count->word(6)); - if (component_count_type->words().size() > 7) { - if (OpenCLDebugInfo100Instructions(component_count_type->word( - 4)) != OpenCLDebugInfo100DebugTypeBasic || - OpenCLDebugInfo100DebugBaseTypeAttributeEncoding( - component_count_type->word(7)) != - OpenCLDebugInfo100Unsigned) { + component_count = const_val & 0xffffffff; + } + + if (!component_count || component_count > 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": Component Count must be positive " + << "integer less than or equal to 4"; + } + break; + } + case CommonDebugInfoDebugTypeArray: { + auto validate_base_type = ValidateOperandDebugType( + _, "Base Type", inst, 5, ext_inst_name, false); + if (validate_base_type != SPV_SUCCESS) return validate_base_type; + for (uint32_t i = 6; i < num_words; ++i) { + bool invalid = false; + auto* component_count = _.FindDef(inst->word(i)); + if (IsConstIntScalarTypeWith32Or64Bits(_, component_count)) { + // TODO: We need a spec discussion for the bindless array. + if (!component_count->word(3)) { invalid = true; - } else { - // DebugTypeBasic for DebugLocalVariable/DebugGlobalVariable - // must have Unsigned encoding and 32 or 64 as its size in bits. - Instruction* size_in_bits = - _.FindDef(component_count_type->word(6)); - if (!_.IsIntScalarType(size_in_bits->type_id()) || - (size_in_bits->word(3) != 32 && - size_in_bits->word(3) != 64)) { + } + } else if (component_count->words().size() > 6 && + (CommonDebugInfoInstructions(component_count->word(4)) == + CommonDebugInfoDebugLocalVariable || + CommonDebugInfoInstructions(component_count->word(4)) == + CommonDebugInfoDebugGlobalVariable)) { + auto* component_count_type = _.FindDef(component_count->word(6)); + if (component_count_type->words().size() > 7) { + uint32_t encoding = component_count_type->word(7); + if (CommonDebugInfoInstructions(component_count_type->word( + 4)) != CommonDebugInfoDebugTypeBasic || + (vulkanDebugInfo && !IsUint32Constant(_, encoding)) || + OpenCLDebugInfo100DebugBaseTypeAttributeEncoding( + vulkanDebugInfo + ? GetUint32Constant(_, encoding) + : encoding) != OpenCLDebugInfo100Unsigned) { invalid = true; + } else { + // DebugTypeBasic for DebugLocalVariable/DebugGlobalVariable + // must have Unsigned encoding and 32 or 64 as its size in + // bits. + Instruction* size_in_bits = + _.FindDef(component_count_type->word(6)); + if (!_.IsIntScalarType(size_in_bits->type_id()) || + (size_in_bits->word(3) != 32 && + size_in_bits->word(3) != 64)) { + invalid = true; + } } + } else { + invalid = true; } } else { invalid = true; } + if (invalid) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": Component Count must be " + << "OpConstant with a 32- or 64-bits integer scalar type " + "or " + << "DebugGlobalVariable or DebugLocalVariable with a 32- " + "or " + << "64-bits unsigned integer scalar type"; + } + } + break; + } + case CommonDebugInfoDebugTypedef: { + CHECK_OPERAND("Name", SpvOpString, 5); + auto validate_base_type = + ValidateOperandBaseType(_, inst, 6, ext_inst_name); + if (validate_base_type != SPV_SUCCESS) return validate_base_type; + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + auto validate_parent = + ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); + if (validate_parent != SPV_SUCCESS) return validate_parent; + break; + } + case CommonDebugInfoDebugTypeFunction: { + CHECK_CONST_UINT_OPERAND("Flags", 5); + auto* return_type = _.FindDef(inst->word(6)); + // TODO: We need a spec discussion that we have to allow return and + // parameter types of a DebugTypeFunction to have template parameter. + if (return_type->opcode() != SpvOpTypeVoid) { + auto validate_return = ValidateOperandDebugType( + _, "Return Type", inst, 6, ext_inst_name, true); + if (validate_return != SPV_SUCCESS) return validate_return; + } + for (uint32_t word_index = 7; word_index < num_words; ++word_index) { + auto validate_param = ValidateOperandDebugType( + _, "Parameter Types", inst, word_index, ext_inst_name, true); + if (validate_param != SPV_SUCCESS) return validate_param; + } + break; + } + case CommonDebugInfoDebugTypeEnum: { + CHECK_OPERAND("Name", SpvOpString, 5); + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugInfoNone; + }, + inst, 6)) { + auto validate_underlying_type = ValidateOperandDebugType( + _, "Underlying Types", inst, 6, ext_inst_name, false); + if (validate_underlying_type != SPV_SUCCESS) + return validate_underlying_type; + } + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + auto validate_parent = + ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); + if (validate_parent != SPV_SUCCESS) return validate_parent; + CHECK_OPERAND("Size", SpvOpConstant, 11); + auto* size = _.FindDef(inst->word(11)); + if (!_.IsIntScalarType(size->type_id()) || !size->word(3)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": expected operand Size is a " + << "positive integer"; + } + CHECK_CONST_UINT_OPERAND("Flags", 12); + for (uint32_t word_index = 13; word_index + 1 < num_words; + word_index += 2) { + CHECK_OPERAND("Value", SpvOpConstant, word_index); + CHECK_OPERAND("Name", SpvOpString, word_index + 1); + } + break; + } + case CommonDebugInfoDebugTypeComposite: { + CHECK_OPERAND("Name", SpvOpString, 5); + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + auto validate_parent = + ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); + if (validate_parent != SPV_SUCCESS) return validate_parent; + CHECK_OPERAND("Linkage Name", SpvOpString, 11); + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugInfoNone; + }, + inst, 12)) { + CHECK_OPERAND("Size", SpvOpConstant, 12); + } + CHECK_CONST_UINT_OPERAND("Flags", 13); + for (uint32_t word_index = 14; word_index < num_words; ++word_index) { + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugTypeMember || + dbg_inst == CommonDebugInfoDebugFunction || + dbg_inst == CommonDebugInfoDebugTypeInheritance; + }, + inst, word_index)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected operand Members " + << "must be DebugTypeMember, DebugFunction, or " + "DebugTypeInheritance"; + } + } + break; + } + case CommonDebugInfoDebugTypeMember: { + CHECK_OPERAND("Name", SpvOpString, 5); + // TODO: We need a spec discussion that we have to allow member types + // to have template parameter. + auto validate_type = + ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true); + if (validate_type != SPV_SUCCESS) return validate_type; + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + // NonSemantic.Shader.DebugInfo doesn't have the Parent operand + if (vulkanDebugInfo) { + CHECK_OPERAND("Offset", SpvOpConstant, 10); + CHECK_OPERAND("Size", SpvOpConstant, 11); + CHECK_CONST_UINT_OPERAND("Flags", 12); + if (num_words == 14) CHECK_OPERAND("Value", SpvOpConstant, 13); } else { - invalid = true; - } - if (invalid) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": Component Count must be " - << "OpConstant with a 32- or 64-bits integer scalar type or " - << "DebugGlobalVariable or DebugLocalVariable with a 32- or " - << "64-bits unsigned integer scalar type"; + CHECK_DEBUG_OPERAND("Parent", CommonDebugInfoDebugTypeComposite, + 10); + CHECK_OPERAND("Offset", SpvOpConstant, 11); + CHECK_OPERAND("Size", SpvOpConstant, 12); + CHECK_CONST_UINT_OPERAND("Flags", 13); + if (num_words == 15) CHECK_OPERAND("Value", SpvOpConstant, 14); } + break; } - break; - } - case OpenCLDebugInfo100DebugTypedef: { - CHECK_OPERAND("Name", SpvOpString, 5); - auto validate_base_type = - ValidateOperandBaseType(_, inst, 6, ext_inst_name); - if (validate_base_type != SPV_SUCCESS) return validate_base_type; - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - auto validate_parent = - ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); - if (validate_parent != SPV_SUCCESS) return validate_parent; - break; - } - case OpenCLDebugInfo100DebugTypeFunction: { - auto* return_type = _.FindDef(inst->word(6)); - // TODO: We need a spec discussion that we have to allow return and - // parameter types of a DebugTypeFunction to have template parameter. - if (return_type->opcode() != SpvOpTypeVoid) { - auto validate_return = ValidateOperandDebugType( - _, "Return Type", inst, 6, ext_inst_name, true); - if (validate_return != SPV_SUCCESS) return validate_return; - } - for (uint32_t word_index = 7; word_index < num_words; ++word_index) { - auto validate_param = ValidateOperandDebugType( - _, "Parameter Types", inst, word_index, ext_inst_name, true); - if (validate_param != SPV_SUCCESS) return validate_param; - } - break; - } - case OpenCLDebugInfo100DebugTypeEnum: { - CHECK_OPERAND("Name", SpvOpString, 5); - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugInfoNone; - }, - inst, 6)) { - auto validate_underlying_type = ValidateOperandDebugType( - _, "Underlying Types", inst, 6, ext_inst_name, false); - if (validate_underlying_type != SPV_SUCCESS) - return validate_underlying_type; - } - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - auto validate_parent = - ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); - if (validate_parent != SPV_SUCCESS) return validate_parent; - CHECK_OPERAND("Size", SpvOpConstant, 11); - auto* size = _.FindDef(inst->word(11)); - if (!_.IsIntScalarType(size->type_id()) || !size->word(3)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": expected operand Size is a " - << "positive integer"; - } - for (uint32_t word_index = 13; word_index + 1 < num_words; - word_index += 2) { - CHECK_OPERAND("Value", SpvOpConstant, word_index); - CHECK_OPERAND("Name", SpvOpString, word_index + 1); - } - break; - } - case OpenCLDebugInfo100DebugTypeComposite: { - CHECK_OPERAND("Name", SpvOpString, 5); - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - auto validate_parent = - ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); - if (validate_parent != SPV_SUCCESS) return validate_parent; - CHECK_OPERAND("Linkage Name", SpvOpString, 11); - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugInfoNone; - }, - inst, 12)) { - CHECK_OPERAND("Size", SpvOpConstant, 12); - } - for (uint32_t word_index = 14; word_index < num_words; ++word_index) { - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugTypeMember || - dbg_inst == OpenCLDebugInfo100DebugFunction || - dbg_inst == OpenCLDebugInfo100DebugTypeInheritance; - }, - inst, word_index)) { + case CommonDebugInfoDebugTypeInheritance: { + CHECK_DEBUG_OPERAND("Child", CommonDebugInfoDebugTypeComposite, 5); + auto* debug_inst = _.FindDef(inst->word(5)); + auto composite_type = + OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6)); + if (composite_type != OpenCLDebugInfo100Class && + composite_type != OpenCLDebugInfo100Structure) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " - << "expected operand Members " - << "must be DebugTypeMember, DebugFunction, or " - "DebugTypeInheritance"; + << "expected operand Child must be class or struct debug " + "type"; } - } - break; - } - case OpenCLDebugInfo100DebugTypeMember: { - CHECK_OPERAND("Name", SpvOpString, 5); - // TODO: We need a spec discussion that we have to allow member types - // to have template parameter. - auto validate_type = - ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true); - if (validate_type != SPV_SUCCESS) return validate_type; - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 10); - CHECK_OPERAND("Offset", SpvOpConstant, 11); - CHECK_OPERAND("Size", SpvOpConstant, 12); - if (num_words == 15) CHECK_OPERAND("Value", SpvOpConstant, 14); - break; - } - case OpenCLDebugInfo100DebugTypeInheritance: { - CHECK_DEBUG_OPERAND("Child", OpenCLDebugInfo100DebugTypeComposite, 5); - auto* debug_inst = _.FindDef(inst->word(5)); - auto composite_type = - OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6)); - if (composite_type != OpenCLDebugInfo100Class && - composite_type != OpenCLDebugInfo100Structure) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected operand Child must be class or struct debug type"; - } - CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 6); - debug_inst = _.FindDef(inst->word(6)); - composite_type = - OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6)); - if (composite_type != OpenCLDebugInfo100Class && - composite_type != OpenCLDebugInfo100Structure) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected operand Parent must be class or struct debug " - "type"; - } - CHECK_OPERAND("Offset", SpvOpConstant, 7); - CHECK_OPERAND("Size", SpvOpConstant, 8); - break; - } - case OpenCLDebugInfo100DebugFunction: { - CHECK_OPERAND("Name", SpvOpString, 5); - auto validate_type = - ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false); - if (validate_type != SPV_SUCCESS) return validate_type; - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - auto validate_parent = - ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); - if (validate_parent != SPV_SUCCESS) return validate_parent; - CHECK_OPERAND("Linkage Name", SpvOpString, 11); - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugInfoNone; - }, - inst, 14)) { - CHECK_OPERAND("Function", SpvOpFunction, 14); - } - if (num_words == 16) { - CHECK_DEBUG_OPERAND("Declaration", - OpenCLDebugInfo100DebugFunctionDeclaration, 15); - } - break; - } - case OpenCLDebugInfo100DebugFunctionDeclaration: { - CHECK_OPERAND("Name", SpvOpString, 5); - auto validate_type = - ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false); - if (validate_type != SPV_SUCCESS) return validate_type; - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - auto validate_parent = - ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); - if (validate_parent != SPV_SUCCESS) return validate_parent; - CHECK_OPERAND("Linkage Name", SpvOpString, 11); - break; - } - case OpenCLDebugInfo100DebugLexicalBlock: { - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 5); - auto validate_parent = - ValidateOperandLexicalScope(_, "Parent", inst, 8, ext_inst_name); - if (validate_parent != SPV_SUCCESS) return validate_parent; - if (num_words == 10) CHECK_OPERAND("Name", SpvOpString, 9); - break; - } - case OpenCLDebugInfo100DebugScope: { - auto validate_scope = - ValidateOperandLexicalScope(_, "Scope", inst, 5, ext_inst_name); - if (validate_scope != SPV_SUCCESS) return validate_scope; - if (num_words == 7) { - CHECK_DEBUG_OPERAND("Inlined At", OpenCLDebugInfo100DebugInlinedAt, - 6); - } - break; - } - case OpenCLDebugInfo100DebugLocalVariable: { - CHECK_OPERAND("Name", SpvOpString, 5); - // TODO: We need a spec discussion that we have to allow local variable - // types to have template parameter. - auto validate_type = - ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true); - if (validate_type != SPV_SUCCESS) return validate_type; - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - auto validate_parent = - ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); - if (validate_parent != SPV_SUCCESS) return validate_parent; - break; - } - case OpenCLDebugInfo100DebugDeclare: { - CHECK_DEBUG_OPERAND("Local Variable", - OpenCLDebugInfo100DebugLocalVariable, 5); - auto* operand = _.FindDef(inst->word(6)); - if (operand->opcode() != SpvOpVariable && - operand->opcode() != SpvOpFunctionParameter) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected operand Variable must be a result id of " - "OpVariable or OpFunctionParameter"; - } - - CHECK_DEBUG_OPERAND("Expression", OpenCLDebugInfo100DebugExpression, 7); - break; - } - case OpenCLDebugInfo100DebugExpression: { - for (uint32_t word_index = 5; word_index < num_words; ++word_index) { - CHECK_DEBUG_OPERAND("Operation", OpenCLDebugInfo100DebugOperation, - word_index); - } - break; - } - case OpenCLDebugInfo100DebugTypeTemplate: { - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugTypeComposite || - dbg_inst == OpenCLDebugInfo100DebugFunction; - }, - inst, 5)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected operand Target must be DebugTypeComposite " - << "or DebugFunction"; - } - for (uint32_t word_index = 6; word_index < num_words; ++word_index) { - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == - OpenCLDebugInfo100DebugTypeTemplateParameter || - dbg_inst == - OpenCLDebugInfo100DebugTypeTemplateTemplateParameter; - }, - inst, word_index)) { + CHECK_DEBUG_OPERAND("Parent", CommonDebugInfoDebugTypeComposite, 6); + debug_inst = _.FindDef(inst->word(6)); + composite_type = + OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6)); + if (composite_type != OpenCLDebugInfo100Class && + composite_type != OpenCLDebugInfo100Structure) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " - << "expected operand Parameters must be " - << "DebugTypeTemplateParameter or " - << "DebugTypeTemplateTemplateParameter"; + << "expected operand Parent must be class or struct debug " + "type"; } + CHECK_OPERAND("Offset", SpvOpConstant, 7); + CHECK_OPERAND("Size", SpvOpConstant, 8); + CHECK_CONST_UINT_OPERAND("Flags", 9); + break; } - break; - } - case OpenCLDebugInfo100DebugTypeTemplateParameter: { - CHECK_OPERAND("Name", SpvOpString, 5); - auto validate_actual_type = ValidateOperandDebugType( - _, "Actual Type", inst, 6, ext_inst_name, false); - if (validate_actual_type != SPV_SUCCESS) return validate_actual_type; - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugInfoNone; - }, - inst, 7)) { - CHECK_OPERAND("Value", SpvOpConstant, 7); + case CommonDebugInfoDebugFunction: { + CHECK_OPERAND("Name", SpvOpString, 5); + auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6, + ext_inst_name, false); + if (validate_type != SPV_SUCCESS) return validate_type; + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + auto validate_parent = + ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); + if (validate_parent != SPV_SUCCESS) return validate_parent; + CHECK_OPERAND("Linkage Name", SpvOpString, 11); + CHECK_CONST_UINT_OPERAND("Flags", 12); + CHECK_CONST_UINT_OPERAND("Scope Line", 13); + // NonSemantic.Shader.DebugInfo.100 doesn't include a reference to the + // OpFunction + if (vulkanDebugInfo) { + if (num_words == 15) { + CHECK_DEBUG_OPERAND("Declaration", + CommonDebugInfoDebugFunctionDeclaration, 14); + } + } else { + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugInfoNone; + }, + inst, 14)) { + CHECK_OPERAND("Function", SpvOpFunction, 14); + } + if (num_words == 16) { + CHECK_DEBUG_OPERAND("Declaration", + CommonDebugInfoDebugFunctionDeclaration, 15); + } + } + break; } - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 8); - break; - } - case OpenCLDebugInfo100DebugGlobalVariable: { - CHECK_OPERAND("Name", SpvOpString, 5); - auto validate_type = - ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false); - if (validate_type != SPV_SUCCESS) return validate_type; - CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7); - auto validate_scope = - ValidateOperandLexicalScope(_, "Scope", inst, 10, ext_inst_name); - if (validate_scope != SPV_SUCCESS) return validate_scope; - CHECK_OPERAND("Linkage Name", SpvOpString, 11); - if (!DoesDebugInfoOperandMatchExpectation( - _, - [](OpenCLDebugInfo100Instructions dbg_inst) { - return dbg_inst == OpenCLDebugInfo100DebugInfoNone; - }, - inst, 12)) { - auto* operand = _.FindDef(inst->word(12)); + case CommonDebugInfoDebugFunctionDeclaration: { + CHECK_OPERAND("Name", SpvOpString, 5); + auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6, + ext_inst_name, false); + if (validate_type != SPV_SUCCESS) return validate_type; + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + auto validate_parent = + ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); + if (validate_parent != SPV_SUCCESS) return validate_parent; + CHECK_OPERAND("Linkage Name", SpvOpString, 11); + CHECK_CONST_UINT_OPERAND("Flags", 12); + break; + } + case CommonDebugInfoDebugLexicalBlock: { + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 5); + CHECK_CONST_UINT_OPERAND("Line", 6); + CHECK_CONST_UINT_OPERAND("Column", 7); + auto validate_parent = + ValidateOperandLexicalScope(_, "Parent", inst, 8, ext_inst_name); + if (validate_parent != SPV_SUCCESS) return validate_parent; + if (num_words == 10) CHECK_OPERAND("Name", SpvOpString, 9); + break; + } + case CommonDebugInfoDebugScope: { + auto validate_scope = + ValidateOperandLexicalScope(_, "Scope", inst, 5, ext_inst_name); + if (validate_scope != SPV_SUCCESS) return validate_scope; + if (num_words == 7) { + CHECK_DEBUG_OPERAND("Inlined At", CommonDebugInfoDebugInlinedAt, 6); + } + break; + } + case CommonDebugInfoDebugLocalVariable: { + CHECK_OPERAND("Name", SpvOpString, 5); + // TODO: We need a spec discussion that we have to allow local + // variable types to have template parameter. + auto validate_type = + ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true); + if (validate_type != SPV_SUCCESS) return validate_type; + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + auto validate_parent = + ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name); + if (validate_parent != SPV_SUCCESS) return validate_parent; + CHECK_CONST_UINT_OPERAND("Flags", 11); + if (num_words == 13) { + CHECK_CONST_UINT_OPERAND("ArgNumber", 12); + } + break; + } + case CommonDebugInfoDebugDeclare: { + CHECK_DEBUG_OPERAND("Local Variable", + CommonDebugInfoDebugLocalVariable, 5); + auto* operand = _.FindDef(inst->word(6)); if (operand->opcode() != SpvOpVariable && - operand->opcode() != SpvOpConstant) { + operand->opcode() != SpvOpFunctionParameter) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " << "expected operand Variable must be a result id of " - "OpVariable or OpConstant or DebugInfoNone"; + "OpVariable or OpFunctionParameter"; } - } - if (num_words == 15) { - CHECK_DEBUG_OPERAND("Static Member Declaration", - OpenCLDebugInfo100DebugTypeMember, 14); - } - break; - } - case OpenCLDebugInfo100DebugInlinedAt: { - auto validate_scope = - ValidateOperandLexicalScope(_, "Scope", inst, 6, ext_inst_name); - if (validate_scope != SPV_SUCCESS) return validate_scope; - if (num_words == 8) { - CHECK_DEBUG_OPERAND("Inlined", OpenCLDebugInfo100DebugInlinedAt, 7); - } - break; - } - case OpenCLDebugInfo100DebugValue: { - CHECK_DEBUG_OPERAND("Local Variable", - OpenCLDebugInfo100DebugLocalVariable, 5); - CHECK_DEBUG_OPERAND("Expression", OpenCLDebugInfo100DebugExpression, 7); - for (uint32_t word_index = 8; word_index < num_words; ++word_index) { - // TODO: The following code simply checks if it is a const int scalar - // or a DebugLocalVariable or DebugGlobalVariable, but we have to - // check it using the same validation for Indexes of OpAccessChain. - if (!IsConstWithIntScalarType(_, inst, word_index) && - !IsDebugVariableWithIntScalarType(_, inst, word_index)) { + CHECK_DEBUG_OPERAND("Expression", CommonDebugInfoDebugExpression, 7); + + if (vulkanDebugInfo) { + for (uint32_t word_index = 8; word_index < num_words; + ++word_index) { + auto index_inst = _.FindDef(inst->word(word_index)); + auto type_id = index_inst != nullptr ? index_inst->type_id() : 0; + if (type_id == 0 || !IsIntScalar(_, type_id, false, false)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected index must be scalar integer"; + } + } + break; + } + case CommonDebugInfoDebugExpression: { + for (uint32_t word_index = 5; word_index < num_words; ++word_index) { + CHECK_DEBUG_OPERAND("Operation", CommonDebugInfoDebugOperation, + word_index); + } + break; + } + case CommonDebugInfoDebugTypeTemplate: { + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugTypeComposite || + dbg_inst == CommonDebugInfoDebugFunction; + }, + inst, 5)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": expected operand Indexes is " - << "OpConstant, DebugGlobalVariable, or " - << "type is OpConstant with an integer scalar type"; + << ext_inst_name() << ": " + << "expected operand Target must be DebugTypeComposite " + << "or DebugFunction"; } + for (uint32_t word_index = 6; word_index < num_words; ++word_index) { + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == + CommonDebugInfoDebugTypeTemplateParameter || + dbg_inst == + CommonDebugInfoDebugTypeTemplateTemplateParameter; + }, + inst, word_index)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected operand Parameters must be " + << "DebugTypeTemplateParameter or " + << "DebugTypeTemplateTemplateParameter"; + } + } + break; } - break; - } + case CommonDebugInfoDebugTypeTemplateParameter: { + CHECK_OPERAND("Name", SpvOpString, 5); + auto validate_actual_type = ValidateOperandDebugType( + _, "Actual Type", inst, 6, ext_inst_name, false); + if (validate_actual_type != SPV_SUCCESS) return validate_actual_type; + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugInfoNone; + }, + inst, 7)) { + CHECK_OPERAND("Value", SpvOpConstant, 7); + } + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 8); + CHECK_CONST_UINT_OPERAND("Line", 9); + CHECK_CONST_UINT_OPERAND("Column", 10); + break; + } + case CommonDebugInfoDebugGlobalVariable: { + CHECK_OPERAND("Name", SpvOpString, 5); + auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6, + ext_inst_name, false); + if (validate_type != SPV_SUCCESS) return validate_type; + CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7); + CHECK_CONST_UINT_OPERAND("Line", 8); + CHECK_CONST_UINT_OPERAND("Column", 9); + auto validate_scope = + ValidateOperandLexicalScope(_, "Scope", inst, 10, ext_inst_name); + if (validate_scope != SPV_SUCCESS) return validate_scope; + CHECK_OPERAND("Linkage Name", SpvOpString, 11); + if (!DoesDebugInfoOperandMatchExpectation( + _, + [](CommonDebugInfoInstructions dbg_inst) { + return dbg_inst == CommonDebugInfoDebugInfoNone; + }, + inst, 12)) { + auto* operand = _.FindDef(inst->word(12)); + if (operand->opcode() != SpvOpVariable && + operand->opcode() != SpvOpConstant) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected operand Variable must be a result id of " + "OpVariable or OpConstant or DebugInfoNone"; + } + } + if (num_words == 15) { + CHECK_DEBUG_OPERAND("Static Member Declaration", + CommonDebugInfoDebugTypeMember, 14); + } + break; + } + case CommonDebugInfoDebugInlinedAt: { + CHECK_CONST_UINT_OPERAND("Line", 5); + auto validate_scope = + ValidateOperandLexicalScope(_, "Scope", inst, 6, ext_inst_name); + if (validate_scope != SPV_SUCCESS) return validate_scope; + if (num_words == 8) { + CHECK_DEBUG_OPERAND("Inlined", CommonDebugInfoDebugInlinedAt, 7); + } + break; + } + case CommonDebugInfoDebugValue: { + CHECK_DEBUG_OPERAND("Local Variable", + CommonDebugInfoDebugLocalVariable, 5); + CHECK_DEBUG_OPERAND("Expression", CommonDebugInfoDebugExpression, 7); - // TODO: Add validation rules for remaining cases as well. - case OpenCLDebugInfo100DebugTypePtrToMember: - case OpenCLDebugInfo100DebugTypeTemplateTemplateParameter: - case OpenCLDebugInfo100DebugTypeTemplateParameterPack: - case OpenCLDebugInfo100DebugLexicalBlockDiscriminator: - case OpenCLDebugInfo100DebugInlinedVariable: - case OpenCLDebugInfo100DebugMacroDef: - case OpenCLDebugInfo100DebugMacroUndef: - case OpenCLDebugInfo100DebugImportedEntity: - case OpenCLDebugInfo100DebugModuleINTEL: - break; - case OpenCLDebugInfo100InstructionsMax: - assert(0); - break; + for (uint32_t word_index = 8; word_index < num_words; ++word_index) { + // TODO: The following code simply checks if it is a const int + // scalar or a DebugLocalVariable or DebugGlobalVariable, but we + // have to check it using the same validation for Indexes of + // OpAccessChain. + if (!IsConstWithIntScalarType(_, inst, word_index) && + !IsDebugVariableWithIntScalarType(_, inst, word_index)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": expected operand Indexes is " + << "OpConstant, DebugGlobalVariable, or " + << "type is OpConstant with an integer scalar type"; + } + } + break; + } + + // TODO: Add validation rules for remaining cases as well. + case CommonDebugInfoDebugTypePtrToMember: + case CommonDebugInfoDebugTypeTemplateTemplateParameter: + case CommonDebugInfoDebugTypeTemplateParameterPack: + case CommonDebugInfoDebugLexicalBlockDiscriminator: + case CommonDebugInfoDebugInlinedVariable: + case CommonDebugInfoDebugMacroDef: + case CommonDebugInfoDebugMacroUndef: + case CommonDebugInfoDebugImportedEntity: + break; + case CommonDebugInfoInstructionsMax: + assert(0); + break; + } } } else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) { auto import_inst = _.FindDef(inst->GetOperandAs(2)); diff --git a/third_party/spirv-tools/source/val/validate_image.cpp b/third_party/spirv-tools/source/val/validate_image.cpp index e5968d06e7..64f6ba7bde 100644 --- a/third_party/spirv-tools/source/val/validate_image.cpp +++ b/third_party/spirv-tools/source/val/validate_image.cpp @@ -66,6 +66,11 @@ bool CheckAllImageOperandsHandled() { case SpvImageOperandsVolatileTexelKHRMask: case SpvImageOperandsSignExtendMask: case SpvImageOperandsZeroExtendMask: + // TODO(jaebaek): Move this line properly after handling image offsets + // operand. This line temporarily fixes CI failure that + // blocks other PRs. + // https://github.com/KhronosGroup/SPIRV-Tools/issues/4565 + case SpvImageOperandsOffsetsMask: return true; } return false; @@ -281,13 +286,14 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, // the module to be invalid. if (mask == 0) return SPV_SUCCESS; - if (spvtools::utils::CountSetBits( - mask & (SpvImageOperandsOffsetMask | SpvImageOperandsConstOffsetMask | - SpvImageOperandsConstOffsetsMask)) > 1) { + if (spvtools::utils::CountSetBits(mask & (SpvImageOperandsOffsetMask | + SpvImageOperandsConstOffsetMask | + SpvImageOperandsConstOffsetsMask | + SpvImageOperandsOffsetsMask)) > 1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << _.VkErrorID(4662) - << "Image Operands Offset, ConstOffset, ConstOffsets cannot be used " - << "together"; + << "Image Operands Offset, ConstOffset, ConstOffsets, Offsets " + "cannot be used together"; } const bool is_implicit_lod = IsImplicitLod(opcode); @@ -620,6 +626,10 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, // setup. } + if (mask & SpvImageOperandsOffsetsMask) { + // TODO: add validation + } + return SPV_SUCCESS; } @@ -2058,11 +2068,13 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { std::string* message) { const auto* models = state.GetExecutionModels(entry_point->id()); const auto* modes = state.GetExecutionModes(entry_point->id()); - if (models->find(SpvExecutionModelGLCompute) != models->end() && - modes->find(SpvExecutionModeDerivativeGroupLinearNV) == - modes->end() && - modes->find(SpvExecutionModeDerivativeGroupQuadsNV) == - modes->end()) { + if (models && + models->find(SpvExecutionModelGLCompute) != models->end() && + (!modes || + (modes->find(SpvExecutionModeDerivativeGroupLinearNV) == + modes->end() && + modes->find(SpvExecutionModeDerivativeGroupQuadsNV) == + modes->end()))) { if (message) { *message = std::string( diff --git a/third_party/spirv-tools/source/val/validate_instruction.cpp b/third_party/spirv-tools/source/val/validate_instruction.cpp index 9d395fb46b..dad98673b1 100644 --- a/third_party/spirv-tools/source/val/validate_instruction.cpp +++ b/third_party/spirv-tools/source/val/validate_instruction.cpp @@ -318,10 +318,9 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) { if (module_version < min_version) { return _.diag(SPV_ERROR_WRONG_VERSION, inst) - << spvOpcodeString(opcode) << " requires " - << spvTargetEnvDescription( - static_cast(min_version)) - << " at minimum."; + << spvOpcodeString(opcode) << " requires SPIR-V version " + << SPV_SPIRV_VERSION_MAJOR_PART(min_version) << "." + << SPV_SPIRV_VERSION_MINOR_PART(min_version) << " at minimum."; } } else if (!_.HasAnyOfExtensions(exts)) { // Otherwise, we only error out when no enabling extensions are diff --git a/third_party/spirv-tools/source/val/validate_interfaces.cpp b/third_party/spirv-tools/source/val/validate_interfaces.cpp index d16d48e269..7ccb6371bb 100644 --- a/third_party/spirv-tools/source/val/validate_interfaces.cpp +++ b/third_party/spirv-tools/source/val/validate_interfaces.cpp @@ -27,6 +27,10 @@ namespace spvtools { namespace val { namespace { +// Limit the number of checked locations to 4096. Multiplied by 4 to represent +// all the components. This limit is set to be well beyond practical use cases. +const uint32_t kMaxLocations = 4096 * 4; + // Returns true if \c inst is an input or output variable. bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) { if (is_spv_1_4) { @@ -195,6 +199,10 @@ uint32_t NumConsumedComponents(ValidationState_t& _, const Instruction* type) { NumConsumedComponents(_, _.FindDef(type->GetOperandAs(1))); num_components *= type->GetOperandAs(2); break; + case SpvOpTypeArray: + // Skip the array. + return NumConsumedComponents(_, + _.FindDef(type->GetOperandAs(1))); default: // This is an error that is validated elsewhere. break; @@ -347,6 +355,11 @@ spv_result_t GetLocationsForVariable( uint32_t num_components = NumConsumedComponents(_, sub_type); uint32_t array_location = location + (num_locations * array_idx); uint32_t start = array_location * 4; + if (kMaxLocations <= start) { + // Too many locations, give up. + break; + } + uint32_t end = (array_location + num_locations) * 4; if (num_components != 0) { start += component; @@ -416,17 +429,41 @@ spv_result_t GetLocationsForVariable( } uint32_t start = location * 4; - uint32_t end = (location + num_locations) * 4; - if (num_components != 0) { - start += component; - end = location * 4 + component + num_components; + if (kMaxLocations <= start) { + // Too many locations, give up. + continue; } - for (uint32_t l = start; l < end; ++l) { - if (!locations->insert(l).second) { - return _.diag(SPV_ERROR_INVALID_DATA, entry_point) - << "Entry-point has conflicting " << storage_class - << " location assignment at location " << l / 4 - << ", component " << l % 4; + + if (member->opcode() == SpvOpTypeArray && num_components >= 1 && + num_components < 4) { + // When an array has an element that takes less than a location in + // size, calculate the used locations in a strided manner. + for (uint32_t l = location; l < num_locations + location; ++l) { + for (uint32_t c = component; c < component + num_components; ++c) { + uint32_t check = 4 * l + c; + if (!locations->insert(check).second) { + return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << "Entry-point has conflicting " << storage_class + << " location assignment at location " << l + << ", component " << c; + } + } + } + } else { + // TODO: There is a hole here is the member is an array of 3- or + // 4-element vectors of 64-bit types. + uint32_t end = (location + num_locations) * 4; + if (num_components != 0) { + start += component; + end = location * 4 + component + num_components; + } + for (uint32_t l = start; l < end; ++l) { + if (!locations->insert(l).second) { + return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << "Entry-point has conflicting " << storage_class + << " location assignment at location " << l / 4 + << ", component " << l % 4; + } } } } @@ -454,6 +491,7 @@ spv_result_t ValidateLocations(ValidationState_t& _, std::unordered_set input_locations; std::unordered_set output_locations_index0; std::unordered_set output_locations_index1; + std::unordered_set seen; for (uint32_t i = 3; i < entry_point->operands().size(); ++i) { auto interface_id = entry_point->GetOperandAs(i); auto interface_var = _.FindDef(interface_id); @@ -462,6 +500,11 @@ spv_result_t ValidateLocations(ValidationState_t& _, storage_class != SpvStorageClassOutput) { continue; } + if (!seen.insert(interface_id).second) { + // Pre-1.4 an interface variable could be listed multiple times in an + // entry point. Validation for 1.4 or later is done elsewhere. + continue; + } auto locations = (storage_class == SpvStorageClassInput) ? &input_locations diff --git a/third_party/spirv-tools/source/val/validate_layout.cpp b/third_party/spirv-tools/source/val/validate_layout.cpp index b53f991e87..d5823219d9 100644 --- a/third_party/spirv-tools/source/val/validate_layout.cpp +++ b/third_party/spirv-tools/source/val/validate_layout.cpp @@ -17,6 +17,7 @@ #include #include "DebugInfo.h" +#include "NonSemanticShaderDebugInfo100.h" #include "OpenCLDebugInfo100.h" #include "source/diagnostic.h" #include "source/opcode.h" @@ -37,17 +38,7 @@ spv_result_t ModuleScopedInstructions(ValidationState_t& _, const Instruction* inst, SpvOp opcode) { switch (opcode) { case SpvOpExtInst: - if (spvExtInstIsNonSemantic(inst->ext_inst_type())) { - // non-semantic extinst opcodes are allowed beginning in the types - // section, but since they must name a return type they cannot be the - // first instruction in the types section. Therefore check that we are - // already in it. - if (_.current_layout_section() < kLayoutTypes) { - return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) - << "Non-semantic OpExtInst must not appear before types " - << "section"; - } - } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { + if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { const uint32_t ext_inst_index = inst->word(4); bool local_debug_info = false; if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { @@ -59,6 +50,20 @@ spv_result_t ModuleScopedInstructions(ValidationState_t& _, ext_inst_key == OpenCLDebugInfo100DebugValue) { local_debug_info = true; } + } else if (inst->ext_inst_type() == + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { + const NonSemanticShaderDebugInfo100Instructions ext_inst_key = + NonSemanticShaderDebugInfo100Instructions(ext_inst_index); + if (ext_inst_key == NonSemanticShaderDebugInfo100DebugScope || + ext_inst_key == NonSemanticShaderDebugInfo100DebugNoScope || + ext_inst_key == NonSemanticShaderDebugInfo100DebugDeclare || + ext_inst_key == NonSemanticShaderDebugInfo100DebugValue || + ext_inst_key == NonSemanticShaderDebugInfo100DebugLine || + ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine || + ext_inst_key == + NonSemanticShaderDebugInfo100DebugFunctionDefinition) { + local_debug_info = true; + } } else { const DebugInfoInstructions ext_inst_key = DebugInfoInstructions(ext_inst_index); @@ -94,6 +99,16 @@ spv_result_t ModuleScopedInstructions(ValidationState_t& _, << "declarations)"; } } + } else if (spvExtInstIsNonSemantic(inst->ext_inst_type())) { + // non-semantic extinst opcodes are allowed beginning in the types + // section, but since they must name a return type they cannot be the + // first instruction in the types section. Therefore check that we are + // already in it. + if (_.current_layout_section() < kLayoutTypes) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Non-semantic OpExtInst must not appear before types " + << "section"; + } } else { // otherwise they must be used in a block if (_.current_layout_section() < kLayoutFunctionDefinitions) { @@ -230,20 +245,7 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _, break; case SpvOpExtInst: - if (spvExtInstIsNonSemantic(inst->ext_inst_type())) { - // non-semantic extinst opcodes are allowed beginning in the types - // section, but must either be placed outside a function declaration, - // or inside a block. - if (_.current_layout_section() < kLayoutTypes) { - return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) - << "Non-semantic OpExtInst must not appear before types " - << "section"; - } else if (_.in_function_body() && _.in_block() == false) { - return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) - << "Non-semantic OpExtInst within function definition must " - "appear in a block"; - } - } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { + if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { const uint32_t ext_inst_index = inst->word(4); bool local_debug_info = false; if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { @@ -255,6 +257,20 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _, ext_inst_key == OpenCLDebugInfo100DebugValue) { local_debug_info = true; } + } else if (inst->ext_inst_type() == + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { + const NonSemanticShaderDebugInfo100Instructions ext_inst_key = + NonSemanticShaderDebugInfo100Instructions(ext_inst_index); + if (ext_inst_key == NonSemanticShaderDebugInfo100DebugScope || + ext_inst_key == NonSemanticShaderDebugInfo100DebugNoScope || + ext_inst_key == NonSemanticShaderDebugInfo100DebugDeclare || + ext_inst_key == NonSemanticShaderDebugInfo100DebugValue || + ext_inst_key == NonSemanticShaderDebugInfo100DebugLine || + ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine || + ext_inst_key == + NonSemanticShaderDebugInfo100DebugFunctionDefinition) { + local_debug_info = true; + } } else { const DebugInfoInstructions ext_inst_key = DebugInfoInstructions(ext_inst_index); @@ -290,6 +306,19 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _, << "declarations)"; } } + } else if (spvExtInstIsNonSemantic(inst->ext_inst_type())) { + // non-semantic extinst opcodes are allowed beginning in the types + // section, but must either be placed outside a function declaration, + // or inside a block. + if (_.current_layout_section() < kLayoutTypes) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Non-semantic OpExtInst must not appear before types " + << "section"; + } else if (_.in_function_body() && _.in_block() == false) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Non-semantic OpExtInst within function definition must " + "appear in a block"; + } } else { // otherwise they must be used in a block if (_.in_block() == false) { diff --git a/third_party/spirv-tools/source/val/validate_memory.cpp b/third_party/spirv-tools/source/val/validate_memory.cpp index a4bc0faba8..a7b0f82d5d 100644 --- a/third_party/spirv-tools/source/val/validate_memory.cpp +++ b/third_party/spirv-tools/source/val/validate_memory.cpp @@ -893,6 +893,12 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) { << "'s type."; } + if (!_.options()->before_hlsl_legalization && + _.ContainsRuntimeArray(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot load a runtime-sized array"; + } + if (auto error = CheckMemoryAccess(_, inst, 3)) return error; if (_.HasCapability(SpvCapabilityShader) && diff --git a/third_party/spirv-tools/source/val/validate_mode_setting.cpp b/third_party/spirv-tools/source/val/validate_mode_setting.cpp index 79f82d8d76..9635268708 100644 --- a/third_party/spirv-tools/source/val/validate_mode_setting.cpp +++ b/third_party/spirv-tools/source/val/validate_mode_setting.cpp @@ -225,14 +225,21 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { } } } + if (i.opcode() == SpvOpExecutionModeId) { + const auto mode = i.GetOperandAs(1); + if (mode == SpvExecutionModeLocalSizeId) { + ok = true; + break; + } + } } if (!ok) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(4683) + << _.VkErrorID(6426) << "In the Vulkan environment, GLCompute execution model " - "entry points require either the LocalSize execution " - "mode or an object decorated with WorkgroupSize must be " - "specified."; + "entry points require either the LocalSize or " + "LocalSizeId execution mode or an object decorated with " + "WorkgroupSize must be specified."; } } break; @@ -429,6 +436,10 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, break; case SpvExecutionModeLocalSize: case SpvExecutionModeLocalSizeId: + if (mode == SpvExecutionModeLocalSizeId && !_.IsLocalSizeIdAllowed()) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "LocalSizeId mode is not allowed by the current environment."; + if (!std::all_of(models->begin(), models->end(), [&_](const SpvExecutionModel& model) { switch (model) { diff --git a/third_party/spirv-tools/source/val/validate_type.cpp b/third_party/spirv-tools/source/val/validate_type.cpp index 612fc5c2ce..4376b52c6d 100644 --- a/third_party/spirv-tools/source/val/validate_type.cpp +++ b/third_party/spirv-tools/source/val/validate_type.cpp @@ -596,7 +596,7 @@ spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _, if (!cols || !_.IsIntScalarType(cols->type_id()) || !spvOpcodeIsConstant(cols->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeCooperativeMatrixNV Cols '" << _.getIdName(rows_id) + << "OpTypeCooperativeMatrixNV Cols '" << _.getIdName(cols_id) << "' is not a constant instruction with scalar integer type."; } diff --git a/third_party/spirv-tools/source/val/validation_state.cpp b/third_party/spirv-tools/source/val/validation_state.cpp index 52821636bf..8d1a0d3f4e 100644 --- a/third_party/spirv-tools/source/val/validation_state.cpp +++ b/third_party/spirv-tools/source/val/validation_state.cpp @@ -175,6 +175,9 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx, } } + // LocalSizeId is always allowed in non-Vulkan environments. + features_.env_allow_localsizeid = !spvIsVulkanEnv(env); + // Only attempt to count if we have words, otherwise let the other validation // fail and generate an error. if (num_words > 0) { @@ -729,19 +732,19 @@ uint32_t ValidationState_t::GetBitWidth(uint32_t id) const { bool ValidationState_t::IsVoidType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypeVoid; + return inst && inst->opcode() == SpvOpTypeVoid; } bool ValidationState_t::IsFloatScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypeFloat; + return inst && inst->opcode() == SpvOpTypeFloat; } bool ValidationState_t::IsFloatVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeVector) { return IsFloatScalarType(GetComponentType(id)); @@ -752,7 +755,9 @@ bool ValidationState_t::IsFloatVectorType(uint32_t id) const { bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeFloat) { return true; @@ -767,13 +772,14 @@ bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const { bool ValidationState_t::IsIntScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypeInt; + return inst && inst->opcode() == SpvOpTypeInt; } bool ValidationState_t::IsIntVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeVector) { return IsIntScalarType(GetComponentType(id)); @@ -784,7 +790,9 @@ bool ValidationState_t::IsIntVectorType(uint32_t id) const { bool ValidationState_t::IsIntScalarOrVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeInt) { return true; @@ -799,13 +807,14 @@ bool ValidationState_t::IsIntScalarOrVectorType(uint32_t id) const { bool ValidationState_t::IsUnsignedIntScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypeInt && inst->word(3) == 0; + return inst && inst->opcode() == SpvOpTypeInt && inst->word(3) == 0; } bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeVector) { return IsUnsignedIntScalarType(GetComponentType(id)); @@ -816,13 +825,14 @@ bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const { bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypeInt && inst->word(3) == 1; + return inst && inst->opcode() == SpvOpTypeInt && inst->word(3) == 1; } bool ValidationState_t::IsSignedIntVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeVector) { return IsSignedIntScalarType(GetComponentType(id)); @@ -833,13 +843,14 @@ bool ValidationState_t::IsSignedIntVectorType(uint32_t id) const { bool ValidationState_t::IsBoolScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypeBool; + return inst && inst->opcode() == SpvOpTypeBool; } bool ValidationState_t::IsBoolVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeVector) { return IsBoolScalarType(GetComponentType(id)); @@ -850,7 +861,9 @@ bool ValidationState_t::IsBoolVectorType(uint32_t id) const { bool ValidationState_t::IsBoolScalarOrVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeBool) { return true; @@ -865,7 +878,9 @@ bool ValidationState_t::IsBoolScalarOrVectorType(uint32_t id) const { bool ValidationState_t::IsFloatMatrixType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); + if (!inst) { + return false; + } if (inst->opcode() == SpvOpTypeMatrix) { return IsFloatScalarType(GetComponentType(id)); @@ -920,8 +935,7 @@ bool ValidationState_t::GetStructMemberTypes( bool ValidationState_t::IsPointerType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypePointer; + return inst && inst->opcode() == SpvOpTypePointer; } bool ValidationState_t::GetPointerTypeInfo(uint32_t id, uint32_t* data_type, @@ -939,8 +953,7 @@ bool ValidationState_t::GetPointerTypeInfo(uint32_t id, uint32_t* data_type, bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const { const Instruction* inst = FindDef(id); - assert(inst); - return inst->opcode() == SpvOpTypeCooperativeMatrixNV; + return inst && inst->opcode() == SpvOpTypeCooperativeMatrixNV; } bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const { @@ -1262,16 +1275,13 @@ const Instruction* ValidationState_t::TracePointer( return base_ptr; } -bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, - uint32_t width) const { - if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false; - +bool ValidationState_t::ContainsType( + uint32_t id, const std::function& f, + bool traverse_all_types) const { const auto inst = FindDef(id); if (!inst) return false; - if (inst->opcode() == type) { - return inst->GetOperandAs(1u) == width; - } + if (f(inst)) return true; switch (inst->opcode()) { case SpvOpTypeArray: @@ -1281,24 +1291,45 @@ bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, case SpvOpTypeImage: case SpvOpTypeSampledImage: case SpvOpTypeCooperativeMatrixNV: - return ContainsSizedIntOrFloatType(inst->GetOperandAs(1u), type, - width); + return ContainsType(inst->GetOperandAs(1u), f, + traverse_all_types); case SpvOpTypePointer: if (IsForwardPointer(id)) return false; - return ContainsSizedIntOrFloatType(inst->GetOperandAs(2u), type, - width); - case SpvOpTypeFunction: - case SpvOpTypeStruct: { - for (uint32_t i = 1; i < inst->operands().size(); ++i) { - if (ContainsSizedIntOrFloatType(inst->GetOperandAs(i), type, - width)) - return true; + if (traverse_all_types) { + return ContainsType(inst->GetOperandAs(2u), f, + traverse_all_types); } - return false; - } + break; + case SpvOpTypeFunction: + case SpvOpTypeStruct: + if (inst->opcode() == SpvOpTypeFunction && !traverse_all_types) { + return false; + } + for (uint32_t i = 1; i < inst->operands().size(); ++i) { + if (ContainsType(inst->GetOperandAs(i), f, + traverse_all_types)) { + return true; + } + } + break; default: - return false; + break; } + + return false; +} + +bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, + uint32_t width) const { + if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false; + + const auto f = [type, width](const Instruction* inst) { + if (inst->opcode() == type) { + return inst->GetOperandAs(1u) == width; + } + return false; + }; + return ContainsType(id, f); } bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const { @@ -1313,6 +1344,13 @@ bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const { return false; } +bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const { + const auto f = [](const Instruction* inst) { + return inst->opcode() == SpvOpTypeRuntimeArray; + }; + return ContainsType(id, f, /* traverse_all_types = */ false); +} + bool ValidationState_t::IsValidStorageClass( SpvStorageClass storage_class) const { if (spvIsVulkanEnv(context()->target_env)) { @@ -1801,14 +1839,16 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-None-04667); case 4669: return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); + case 4670: + return VUID_WRAP(VUID-StandaloneSpirv-Flat-04670); case 4675: return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); case 4677: return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677); case 4682: return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682); - case 4683: - return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683); + case 6426: + return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-06426); // formally 04683 case 4685: return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); case 4686: diff --git a/third_party/spirv-tools/source/val/validation_state.h b/third_party/spirv-tools/source/val/validation_state.h index 57634bf4a0..2ddfa4a938 100644 --- a/third_party/spirv-tools/source/val/validation_state.h +++ b/third_party/spirv-tools/source/val/validation_state.h @@ -90,23 +90,6 @@ class ValidationState_t { // conversion opcodes bool use_int8_type = false; - // Use scalar block layout. See VK_EXT_scalar_block_layout: - // Defines scalar alignment: - // - scalar alignment equals the scalar size in bytes - // - array alignment is same as its element alignment - // - array alignment is max alignment of any of its members - // - vector alignment is same as component alignment - // - matrix alignment is same as component alignment - // For struct in Uniform, StorageBuffer, PushConstant: - // - Offset of a member is multiple of scalar alignment of that member - // - ArrayStride and MatrixStride are multiples of scalar alignment - // Members need not be listed in offset order - bool scalar_block_layout = false; - - // Use scalar block layout (as defined above) for Workgroup block - // variables. See VK_KHR_workgroup_memory_explicit_layout. - bool workgroup_scalar_block_layout = false; - // SPIR-V 1.4 allows us to select between any two composite values // of the same type. bool select_between_composites = false; @@ -121,6 +104,9 @@ class ValidationState_t { // SPIR-V 1.4 allows Function and Private variables to be NonWritable bool nonwritable_var_in_function_or_private = false; + + // Whether LocalSizeId execution mode is allowed by the environment. + bool env_allow_localsizeid = false; }; ValidationState_t(const spv_const_context context, @@ -493,6 +479,12 @@ class ValidationState_t { return features_.env_relaxed_block_layout || options()->relax_block_layout; } + // Returns true if allowing localsizeid, either because the environment always + // allows it, or because it is enabled from the command-line. + bool IsLocalSizeIdAllowed() const { + return features_.env_allow_localsizeid || options()->allow_localsizeid; + } + /// Sets the struct nesting depth for a given struct ID void set_struct_nesting_depth(uint32_t id, uint32_t depth) { struct_nesting_depth_[id] = depth; @@ -595,6 +587,17 @@ class ValidationState_t { // 16-bit float that is not generally enabled for use. bool ContainsLimitedUseIntOrFloatType(uint32_t id) const; + // Returns true if |id| is a type that contains a runtime-sized array. + // Does not consider a pointers as contains the array. + bool ContainsRuntimeArray(uint32_t id) const; + + // Generic type traversal. + // Only traverse pointers and functions if |traverse_all_types| is true. + // Recursively tests |f| against the type hierarchy headed by |id|. + bool ContainsType(uint32_t id, + const std::function& f, + bool traverse_all_types = true) const; + // Gets value from OpConstant and OpSpecConstant as uint64. // Returns false on failure (no instruction, wrong instruction, not int). bool GetConstantValUint64(uint32_t id, uint64_t* val) const; diff --git a/third_party/spirv-tools/source/wasm/README.md b/third_party/spirv-tools/source/wasm/README.md new file mode 100644 index 0000000000..aca0f70cee --- /dev/null +++ b/third_party/spirv-tools/source/wasm/README.md @@ -0,0 +1,43 @@ +# SPIRV-Tools + +Wasm (WebAssembly) build of https://github.com/KhronosGroup/SPIRV-Tools + +## Usage + +```js +const spirvTools = require("spirv-tools"); + +const test = async () => { + // Load the library + const spv = await spirvTools(); + + // assemble + const source = ` + OpCapability Linkage + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpSource GLSL 450 + OpDecorate %spec SpecId 1 + %int = OpTypeInt 32 1 + %spec = OpSpecConstant %int 0 + %const = OpConstant %int 42`; + const asResult = spv.as( + source, + spv.SPV_ENV_UNIVERSAL_1_3, + spv.SPV_TEXT_TO_BINARY_OPTION_NONE + ); + console.log(`as returned ${asResult.byteLength} bytes`); + + // re-disassemble + const disResult = spv.dis( + asResult, + spv.SPV_ENV_UNIVERSAL_1_3, + spv.SPV_BINARY_TO_TEXT_OPTION_INDENT | + spv.SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | + spv.SPV_BINARY_TO_TEXT_OPTION_COLOR + ); + console.log("dis:\n", disResult); +}; + +test(); +``` diff --git a/third_party/spirv-tools/source/wasm/build.sh b/third_party/spirv-tools/source/wasm/build.sh new file mode 100755 index 0000000000..f02ae525c3 --- /dev/null +++ b/third_party/spirv-tools/source/wasm/build.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# Copyright (c) 2020 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. + +set -e + +NUM_CORES=$(nproc) +echo "Detected $NUM_CORES cores for building" + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +VERSION=$(sed -n '0,/^v20/ s/^v\(20[0-9.]*\).*/\1/p' $DIR/../../CHANGES).${GITHUB_RUN_NUMBER:-0} +echo "Version: $VERSION" + +build() { + type=$1 + shift + args=$@ + mkdir -p build/$type + pushd build/$type + echo $args + emcmake cmake \ + -DCMAKE_BUILD_TYPE=Release \ + $args \ + ../.. + emmake make -j $(( $NUM_CORES )) SPIRV-Tools-static + + echo Building js interface + emcc \ + --bind \ + -I../../include \ + -std=c++11 \ + ../../source/wasm/spirv-tools.cpp \ + source/libSPIRV-Tools.a \ + -o spirv-tools.js \ + -s MODULARIZE \ + -Oz + + popd + mkdir -p out/$type + + # copy other js files + cp source/wasm/spirv-tools.d.ts out/$type/ + sed -e 's/\("version"\s*:\s*\).*/\1"'$VERSION'",/' source/wasm/package.json > out/$type/package.json + cp source/wasm/README.md out/$type/ + cp LICENSE out/$type/ + + cp build/$type/spirv-tools.js out/$type/ + gzip -9 -k -f out/$type/spirv-tools.js + if [ -e build/$type/spirv-tools.wasm ] ; then + cp build/$type/spirv-tools.wasm out/$type/ + gzip -9 -k -f out/$type/spirv-tools.wasm + fi +} + +if [ ! -d external/spirv-headers ] ; then + echo "Fetching SPIRV-headers" + git clone https://github.com/KhronosGroup/SPIRV-Headers.git external/spirv-headers +fi + +echo Building ${BASH_REMATCH[1]} +build web\ + -DSPIRV_COLOR_TERMINAL=OFF\ + -DSPIRV_SKIP_TESTS=ON\ + -DSPIRV_SKIP_EXECUTABLES=ON + +wc -c out/*/* diff --git a/third_party/spirv-tools/source/wasm/package.json b/third_party/spirv-tools/source/wasm/package.json new file mode 100644 index 0000000000..7827353810 --- /dev/null +++ b/third_party/spirv-tools/source/wasm/package.json @@ -0,0 +1,17 @@ +{ + "name": "spirv-tools", + "version": "VERSION", + "license": "Apache-2.0", + "main": "spirv-tools", + "types": "spirv-tools.d.ts", + "files": [ + "*.wasm", + "*.js", + "*.d.ts" + ], + "repository": { + "type": "git", + "url": "https://github.com/KhronosGroup/SPIRV-Tools" + }, + "homepage": "https://github.com/KhronosGroup/SPIRV-Tools" +} diff --git a/third_party/spirv-tools/source/wasm/spirv-tools.cpp b/third_party/spirv-tools/source/wasm/spirv-tools.cpp new file mode 100644 index 0000000000..90407f328a --- /dev/null +++ b/third_party/spirv-tools/source/wasm/spirv-tools.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2020 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 "spirv-tools/libspirv.hpp" + +#include +#include +#include + +#include +#include +using namespace emscripten; + +void print_msg_to_stderr (spv_message_level_t, const char*, + const spv_position_t&, const char* m) { + std::cerr << "error: " << m << std::endl; +}; + +std::string dis(std::string const& buffer, uint32_t env, uint32_t options) { + spvtools::SpirvTools core(static_cast(env)); + core.SetMessageConsumer(print_msg_to_stderr); + + std::vector spirv; + const uint32_t* ptr = reinterpret_cast(buffer.data()); + spirv.assign(ptr, ptr + buffer.size() / 4); + std::string disassembly; + if (!core.Disassemble(spirv, &disassembly, options)) return "Error"; + return disassembly; +} + +emscripten::val as(std::string const& source, uint32_t env, uint32_t options) { + spvtools::SpirvTools core(static_cast(env)); + core.SetMessageConsumer(print_msg_to_stderr); + + std::vector spirv; + if (!core.Assemble(source, &spirv, options)) spirv.clear(); + const uint8_t* ptr = reinterpret_cast(spirv.data()); + return emscripten::val(emscripten::typed_memory_view(spirv.size() * 4, + ptr)); +} + +EMSCRIPTEN_BINDINGS(my_module) { + function("dis", &dis); + function("as", &as); + + constant("SPV_ENV_UNIVERSAL_1_0", static_cast(SPV_ENV_UNIVERSAL_1_0)); + constant("SPV_ENV_VULKAN_1_0", static_cast(SPV_ENV_VULKAN_1_0)); + constant("SPV_ENV_UNIVERSAL_1_1", static_cast(SPV_ENV_UNIVERSAL_1_1)); + constant("SPV_ENV_OPENCL_2_1", static_cast(SPV_ENV_OPENCL_2_1)); + constant("SPV_ENV_OPENCL_2_2", static_cast(SPV_ENV_OPENCL_2_2)); + constant("SPV_ENV_OPENGL_4_0", static_cast(SPV_ENV_OPENGL_4_0)); + constant("SPV_ENV_OPENGL_4_1", static_cast(SPV_ENV_OPENGL_4_1)); + constant("SPV_ENV_OPENGL_4_2", static_cast(SPV_ENV_OPENGL_4_2)); + constant("SPV_ENV_OPENGL_4_3", static_cast(SPV_ENV_OPENGL_4_3)); + constant("SPV_ENV_OPENGL_4_5", static_cast(SPV_ENV_OPENGL_4_5)); + constant("SPV_ENV_UNIVERSAL_1_2", static_cast(SPV_ENV_UNIVERSAL_1_2)); + constant("SPV_ENV_OPENCL_1_2", static_cast(SPV_ENV_OPENCL_1_2)); + constant("SPV_ENV_OPENCL_EMBEDDED_1_2", static_cast(SPV_ENV_OPENCL_EMBEDDED_1_2)); + constant("SPV_ENV_OPENCL_2_0", static_cast(SPV_ENV_OPENCL_2_0)); + constant("SPV_ENV_OPENCL_EMBEDDED_2_0", static_cast(SPV_ENV_OPENCL_EMBEDDED_2_0)); + constant("SPV_ENV_OPENCL_EMBEDDED_2_1", static_cast(SPV_ENV_OPENCL_EMBEDDED_2_1)); + constant("SPV_ENV_OPENCL_EMBEDDED_2_2", static_cast(SPV_ENV_OPENCL_EMBEDDED_2_2)); + constant("SPV_ENV_UNIVERSAL_1_3", static_cast(SPV_ENV_UNIVERSAL_1_3)); + constant("SPV_ENV_VULKAN_1_1", static_cast(SPV_ENV_VULKAN_1_1)); + constant("SPV_ENV_WEBGPU_0", static_cast(SPV_ENV_WEBGPU_0)); + constant("SPV_ENV_UNIVERSAL_1_4", static_cast(SPV_ENV_UNIVERSAL_1_4)); + constant("SPV_ENV_VULKAN_1_1_SPIRV_1_4", static_cast(SPV_ENV_VULKAN_1_1_SPIRV_1_4)); + constant("SPV_ENV_UNIVERSAL_1_5", static_cast(SPV_ENV_UNIVERSAL_1_5)); + constant("SPV_ENV_VULKAN_1_2", static_cast(SPV_ENV_VULKAN_1_2)); + + + constant("SPV_BINARY_TO_TEXT_OPTION_NONE", static_cast(SPV_BINARY_TO_TEXT_OPTION_NONE)); + constant("SPV_BINARY_TO_TEXT_OPTION_PRINT", static_cast(SPV_BINARY_TO_TEXT_OPTION_PRINT)); + constant("SPV_BINARY_TO_TEXT_OPTION_COLOR", static_cast(SPV_BINARY_TO_TEXT_OPTION_COLOR)); + constant("SPV_BINARY_TO_TEXT_OPTION_INDENT", static_cast(SPV_BINARY_TO_TEXT_OPTION_INDENT)); + constant("SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET", static_cast(SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET)); + constant("SPV_BINARY_TO_TEXT_OPTION_NO_HEADER", static_cast(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER)); + constant("SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES", static_cast(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)); + + constant("SPV_TEXT_TO_BINARY_OPTION_NONE", static_cast(SPV_TEXT_TO_BINARY_OPTION_NONE)); + constant("SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS", static_cast(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS)); +} \ No newline at end of file diff --git a/third_party/spirv-tools/source/wasm/spirv-tools.d.ts b/third_party/spirv-tools/source/wasm/spirv-tools.d.ts new file mode 100644 index 0000000000..9c197973d5 --- /dev/null +++ b/third_party/spirv-tools/source/wasm/spirv-tools.d.ts @@ -0,0 +1,56 @@ +// Copyright (c) 2020 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. + +declare interface SpirvTools { + as(input: string, env: number, options: number): Uint8Array; + dis(input: Uint8Array, env: number, options: number): string; + + SPV_ENV_UNIVERSAL_1_0: number; + SPV_ENV_VULKAN_1_0: number; + SPV_ENV_UNIVERSAL_1_1: number; + SPV_ENV_OPENCL_2_1: number; + SPV_ENV_OPENCL_2_2: number; + SPV_ENV_OPENGL_4_0: number; + SPV_ENV_OPENGL_4_1: number; + SPV_ENV_OPENGL_4_2: number; + SPV_ENV_OPENGL_4_3: number; + SPV_ENV_OPENGL_4_5: number; + SPV_ENV_UNIVERSAL_1_2: number; + SPV_ENV_OPENCL_1_2: number; + SPV_ENV_OPENCL_EMBEDDED_1_2: number; + SPV_ENV_OPENCL_2_0: number; + SPV_ENV_OPENCL_EMBEDDED_2_0: number; + SPV_ENV_OPENCL_EMBEDDED_2_1: number; + SPV_ENV_OPENCL_EMBEDDED_2_2: number; + SPV_ENV_UNIVERSAL_1_3: number; + SPV_ENV_VULKAN_1_1: number; + SPV_ENV_WEBGPU_0: number; + SPV_ENV_UNIVERSAL_1_4: number; + SPV_ENV_VULKAN_1_1_SPIRV_1_4: number; + SPV_ENV_UNIVERSAL_1_5: number; + SPV_ENV_VULKAN_1_2: number; + + SPV_TEXT_TO_BINARY_OPTION_NONE: number; + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS: number; + + SPV_BINARY_TO_TEXT_OPTION_NONE: number; + SPV_BINARY_TO_TEXT_OPTION_PRINT: number; + SPV_BINARY_TO_TEXT_OPTION_COLOR: number; + SPV_BINARY_TO_TEXT_OPTION_INDENT: number; + SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET: number; + SPV_BINARY_TO_TEXT_OPTION_NO_HEADER: number; + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES: number; +} + +export default function (): Promise; diff --git a/third_party/spirv-tools/test/CMakeLists.txt b/third_party/spirv-tools/test/CMakeLists.txt index 8ede58bfa6..e88df04d79 100644 --- a/third_party/spirv-tools/test/CMakeLists.txt +++ b/third_party/spirv-tools/test/CMakeLists.txt @@ -186,9 +186,11 @@ endif() add_subdirectory(link) +add_subdirectory(lint) add_subdirectory(opt) add_subdirectory(reduce) add_subdirectory(fuzz) add_subdirectory(tools) add_subdirectory(util) add_subdirectory(val) +add_subdirectory(fuzzers) diff --git a/third_party/spirv-tools/test/binary_to_text_test.cpp b/third_party/spirv-tools/test/binary_to_text_test.cpp index 9cad9661d1..df703e5df4 100644 --- a/third_party/spirv-tools/test/binary_to_text_test.cpp +++ b/third_party/spirv-tools/test/binary_to_text_test.cpp @@ -386,7 +386,7 @@ INSTANTIATE_TEST_SUITE_P( ::testing::ValuesIn(std::vector{ "OpExecutionModeId %1 SubgroupsPerWorkgroupId %2\n", "OpExecutionModeId %1 LocalSizeId %2 %3 %4\n", - "OpExecutionModeId %1 LocalSizeHintId %2\n", + "OpExecutionModeId %1 LocalSizeHintId %2 %3 %4\n", "OpDecorateId %1 AlignmentId %2\n", "OpDecorateId %1 MaxByteOffsetId %2\n", }))); diff --git a/third_party/spirv-tools/test/fuzz/CMakeLists.txt b/third_party/spirv-tools/test/fuzz/CMakeLists.txt index 8acebde6e7..56af0b9dd6 100644 --- a/third_party/spirv-tools/test/fuzz/CMakeLists.txt +++ b/third_party/spirv-tools/test/fuzz/CMakeLists.txt @@ -122,6 +122,7 @@ if (${SPIRV_BUILD_FUZZER}) transformation_vector_shuffle_test.cpp transformation_wrap_early_terminator_in_function_test.cpp transformation_wrap_region_in_selection_test.cpp + transformation_wrap_vector_synonym_test.cpp uniform_buffer_element_descriptor_test.cpp) if (${SPIRV_ENABLE_LONG_FUZZER_TESTS}) diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp index 734f47afd8..1045f8a157 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp @@ -134,7 +134,7 @@ TEST(FuzzerPassAddOpPhiSynonymsTest, HelperFunctions) { FuzzerPassAddOpPhiSynonyms fuzzer_pass(context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence); + &transformation_sequence, false); SetUpIdSynonyms(transformation_context.GetFactManager()); diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_pass_construct_composites_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_pass_construct_composites_test.cpp index a02176b215..a858e4ce60 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzer_pass_construct_composites_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzer_pass_construct_composites_test.cpp @@ -92,7 +92,7 @@ TEST(FuzzerPassConstructCompositesTest, IsomorphicStructs) { FuzzerPassConstructComposites fuzzer_pass( context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence); + &transformation_sequence, false); fuzzer_pass.Apply(); @@ -173,7 +173,7 @@ TEST(FuzzerPassConstructCompositesTest, IsomorphicArrays) { FuzzerPassConstructComposites fuzzer_pass( context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence); + &transformation_sequence, false); fuzzer_pass.Apply(); diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp index f11885d4e6..fe8e671d1b 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp @@ -210,7 +210,7 @@ TEST(FuzzerPassDonateModulesTest, BasicDonation) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -291,7 +291,7 @@ TEST(FuzzerPassDonateModulesTest, DonationWithUniforms) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -422,7 +422,7 @@ TEST(FuzzerPassDonateModulesTest, DonationWithInputAndOutputVariables) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -517,7 +517,7 @@ TEST(FuzzerPassDonateModulesTest, DonateFunctionTypeWithDifferentPointers) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -531,6 +531,7 @@ TEST(FuzzerPassDonateModulesTest, DonateOpConstantNull) { std::string recipient_shader = R"( OpCapability Shader OpCapability ImageQuery + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -548,6 +549,7 @@ TEST(FuzzerPassDonateModulesTest, DonateOpConstantNull) { std::string donor_shader = R"( OpCapability Shader OpCapability ImageQuery + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -587,7 +589,7 @@ TEST(FuzzerPassDonateModulesTest, DonateOpConstantNull) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -715,7 +717,7 @@ TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImages) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -811,7 +813,7 @@ TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesSampler) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -943,7 +945,7 @@ TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImageStructField) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -1079,7 +1081,7 @@ TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImageFunctionParameter) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -1161,7 +1163,7 @@ TEST(FuzzerPassDonateModulesTest, DonateShaderWithImageStorageClass) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), true); @@ -1248,7 +1250,7 @@ TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithRuntimeArray) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -1352,7 +1354,7 @@ TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithRuntimeArrayLivesafe) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), true); @@ -1424,7 +1426,7 @@ TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithWorkgroupVariables) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), true); @@ -1534,7 +1536,7 @@ TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithAtomics) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), true); @@ -1718,7 +1720,7 @@ TEST(FuzzerPassDonateModulesTest, Miscellaneous1) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -1790,7 +1792,7 @@ TEST(FuzzerPassDonateModulesTest, OpSpecConstantInstructions) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -1947,7 +1949,7 @@ TEST(FuzzerPassDonateModulesTest, DonationSupportsOpTypeRuntimeArray) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), false); @@ -2020,7 +2022,7 @@ TEST(FuzzerPassDonateModulesTest, HandlesCapabilities) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); ASSERT_TRUE(donor_context->get_feature_mgr()->HasCapability( SpvCapabilityVariablePointersStorageBuffer)); @@ -2253,7 +2255,7 @@ TEST(FuzzerPassDonateModulesTest, HandlesOpPhisInMergeBlock) { FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence, {}); + &transformation_sequence, false, {}); fuzzer_pass.DonateSingleModule(donor_context.get(), true); diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_pass_outline_functions_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_pass_outline_functions_test.cpp index 0d2c5bf745..a088e17b15 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzer_pass_outline_functions_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzer_pass_outline_functions_test.cpp @@ -130,7 +130,7 @@ TEST(FuzzerPassOutlineFunctionsTest, EntryIsAlreadySuitable) { FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence); + &transformation_sequence, false); // Block 28 auto suitable_entry_block = @@ -173,7 +173,7 @@ TEST(FuzzerPassOutlineFunctionsTest, EntryHasOpVariable) { FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence); + &transformation_sequence, false); // Block 20 auto suitable_entry_block = @@ -297,7 +297,7 @@ TEST(FuzzerPassOutlineFunctionsTest, EntryBlockIsHeader) { FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence); + &transformation_sequence, false); // Block 21 auto suitable_entry_block = @@ -464,7 +464,7 @@ TEST(FuzzerPassOutlineFunctionsTest, ExitBlock) { FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, &fuzzer_context, - &transformation_sequence); + &transformation_sequence, false); // Block 39 is not a merge block, so it is already suitable. auto suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining( diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_pass_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_pass_test.cpp index b035de7444..31b8582a5a 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzer_pass_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzer_pass_test.cpp @@ -29,7 +29,7 @@ class FuzzerPassMock : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} + transformations, false) {} ~FuzzerPassMock() override = default; diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp index 6dc7ffb11c..2a22e6a5ea 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp @@ -1596,6 +1596,23 @@ const std::string kTestShader6 = R"( OpFunctionEnd )"; +// A virtually empty piece of SPIR-V. + +const std::string kTestShader7 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + void AddConstantUniformFact(protobufs::FactSequence* facts, uint32_t descriptor_set, uint32_t binding, std::vector&& indices, uint32_t value) { @@ -1668,7 +1685,7 @@ void RunFuzzerAndReplayer(const std::string& shader, Fuzzer fuzzer(std::move(ir_context), std::move(transformation_context), std::move(fuzzer_context), kConsoleMessageConsumer, donor_suppliers, enable_all_passes, - strategies[strategy_index], true, validator_options); + strategies[strategy_index], true, validator_options, false); auto fuzzer_result = fuzzer.Run(0); // Cycle the repeated pass strategy so that we try a different one next time @@ -1760,6 +1777,13 @@ TEST(FuzzerReplayerTest, Miscellaneous6) { kNumFuzzerRuns); } +TEST(FuzzerReplayerTest, Miscellaneous7) { + // Do some fuzzer runs, starting from an initial seed of 1 (seed value chosen + // arbitrarily). + RunFuzzerAndReplayer(kTestShader7, protobufs::FactSequence(), 1, + kNumFuzzerRuns); +} + } // namespace } // namespace fuzz } // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp index e792116980..acee03c7a7 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp @@ -1068,7 +1068,7 @@ void RunFuzzerAndShrinker(const std::string& shader, Fuzzer fuzzer(std::move(ir_context), std::move(transformation_context), std::move(fuzzer_context), kConsoleMessageConsumer, donor_suppliers, enable_all_passes, repeated_pass_strategy, - true, validator_options); + true, validator_options, false); auto fuzzer_result = fuzzer.Run(0); ASSERT_NE(Fuzzer::Status::kFuzzerPassLedToInvalidModule, fuzzer_result.status); diff --git a/third_party/spirv-tools/test/fuzz/fuzzerutil_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzerutil_test.cpp index 7ff9b4d8d7..0ad3e742b1 100644 --- a/third_party/spirv-tools/test/fuzz/fuzzerutil_test.cpp +++ b/third_party/spirv-tools/test/fuzz/fuzzerutil_test.cpp @@ -196,8 +196,6 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetBoolTypeTest) { %50 = OpTypePointer Private %7 %34 = OpTypeBool %35 = OpConstantFalse %34 - %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -507,8 +505,6 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetFloatTypeTest) { %50 = OpTypePointer Private %7 %34 = OpTypeBool %35 = OpConstantFalse %34 - %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -799,8 +795,6 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetIntegerTypeTest) { %50 = OpTypePointer Private %7 %34 = OpTypeBool %35 = OpConstantFalse %34 - %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -894,8 +888,6 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetPointerTypeTest) { %50 = OpTypePointer Private %7 %34 = OpTypeBool %35 = OpConstantFalse %34 - %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -1165,8 +1157,6 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetStructTypeTest) { %50 = OpTypePointer Private %7 %34 = OpTypeBool %35 = OpConstantFalse %34 - %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -1261,8 +1251,6 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetVectorTypeTest) { %50 = OpTypePointer Private %7 %34 = OpTypeBool %35 = OpConstantFalse %34 - %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -1362,8 +1350,6 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetVoidTypeTest) { %50 = OpTypePointer Private %7 %34 = OpTypeBool %35 = OpConstantFalse %34 - %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -1563,6 +1549,259 @@ TEST(FuzzerutilTest, FuzzerUtilMaybeGetZeroConstantTest) { float_ids.end()); } +TEST(FuzzerutilTest, TypesAreCompatible) { + const std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpTypeInt 32 0 + %8 = OpTypeStruct %6 + %10 = OpTypePointer StorageBuffer %8 + %11 = OpVariable %10 StorageBuffer + %86 = OpTypeStruct %9 + %87 = OpTypePointer Workgroup %86 + %88 = OpVariable %87 Workgroup + %89 = OpTypePointer Workgroup %9 + %19 = OpConstant %9 0 + %18 = OpConstant %9 1 + %12 = OpConstant %6 0 + %13 = OpTypePointer StorageBuffer %6 + %15 = OpConstant %6 2 + %16 = OpConstant %6 7 + %20 = OpConstant %9 64 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %14 = OpAccessChain %13 %11 %12 + %90 = OpAccessChain %89 %88 %19 + %21 = OpAtomicLoad %6 %14 %15 %20 + %22 = OpAtomicExchange %6 %14 %15 %20 %16 + %23 = OpAtomicCompareExchange %6 %14 %15 %20 %12 %16 %15 + %24 = OpAtomicIIncrement %6 %14 %15 %20 + %25 = OpAtomicIDecrement %6 %14 %15 %20 + %26 = OpAtomicIAdd %6 %14 %15 %20 %16 + %27 = OpAtomicISub %6 %14 %15 %20 %16 + %28 = OpAtomicSMin %6 %14 %15 %20 %16 + %29 = OpAtomicUMin %9 %90 %15 %20 %18 + %30 = OpAtomicSMax %6 %14 %15 %20 %15 + %31 = OpAtomicUMax %9 %90 %15 %20 %18 + %32 = OpAtomicAnd %6 %14 %15 %20 %16 + %33 = OpAtomicOr %6 %14 %15 %20 %16 + %34 = OpAtomicXor %6 %14 %15 %20 %16 + OpAtomicStore %14 %15 %20 %16 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + const uint32_t int_type = 6; // The id of OpTypeInt 32 1 + const uint32_t uint_type = 9; // The id of OpTypeInt 32 0 + + // OpAtomicLoad +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicLoad, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicLoad, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicLoad, 2, + int_type, uint_type)); + + // OpAtomicExchange +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicExchange, 0, int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicExchange, + 1, int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicExchange, + 2, int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicExchange, 3, int_type, uint_type)); + + // OpAtomicStore +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, + 0, int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, + 3, int_type, uint_type)); + + // OpAtomicCompareExchange +#ifndef NDEBUG + ASSERT_DEATH( + fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicCompareExchange, + 0, int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicCompareExchange, 1, int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicCompareExchange, 2, int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicCompareExchange, 3, int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicCompareExchange, 4, int_type, uint_type)); + + // OpAtomicIIncrement +#ifndef NDEBUG + ASSERT_DEATH( + fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIIncrement, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicIIncrement, 1, int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible( + context.get(), SpvOpAtomicIIncrement, 2, int_type, uint_type)); + +// OpAtomicIDecrement +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, + 0, int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 2, + int_type, uint_type)); + +// OpAtomicIAdd +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 3, + int_type, uint_type)); + +// OpAtomicISub +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 3, + int_type, uint_type)); + +// OpAtomicSMin +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 3, + int_type, uint_type)); + +// OpAtomicUMin +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 3, + int_type, uint_type)); + +// OpAtomicSMax +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 3, + int_type, uint_type)); + +// OpAtomicUMax +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 3, + int_type, uint_type)); + +// OpAtomicAnd +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 3, + int_type, uint_type)); + +// OpAtomicOr +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 3, + int_type, uint_type)); + +// OpAtomicXor +#ifndef NDEBUG + ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 0, + int_type, uint_type), + "Signedness check should not occur on a pointer operand."); +#endif + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 1, + int_type, uint_type)); + ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 2, + int_type, uint_type)); + ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 3, + int_type, uint_type)); +} + } // namespace } // namespace fuzz } // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/shrinker_test.cpp b/third_party/spirv-tools/test/fuzz/shrinker_test.cpp index 447ebecd74..942de29a31 100644 --- a/third_party/spirv-tools/test/fuzz/shrinker_test.cpp +++ b/third_party/spirv-tools/test/fuzz/shrinker_test.cpp @@ -171,7 +171,7 @@ TEST(ShrinkerTest, ReduceAddedFunctions) { protobufs::TransformationSequence transformations; FuzzerPassDonateModules pass(variant_ir_context.get(), &transformation_context, &fuzzer_context, - &transformations, {}); + &transformations, false, {}); pass.DonateSingleModule(donor_ir_context.get(), true); protobufs::FactSequence no_facts; @@ -349,7 +349,7 @@ TEST(ShrinkerTest, HitStepLimitWhenReducingAddedFunctions) { protobufs::TransformationSequence transformations; FuzzerPassDonateModules pass(variant_ir_context.get(), &transformation_context, &fuzzer_context, - &transformations, {}); + &transformations, false, {}); pass.DonateSingleModule(donor_ir_context.get(), true); protobufs::FactSequence no_facts; diff --git a/third_party/spirv-tools/test/fuzz/transformation_access_chain_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_access_chain_test.cpp index e7919816d9..bddcf5fe53 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_access_chain_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_access_chain_test.cpp @@ -26,6 +26,7 @@ namespace { TEST(TransformationAccessChainTest, BasicTest) { std::string shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %48 %54 @@ -63,7 +64,6 @@ TEST(TransformationAccessChainTest, BasicTest) { %85 = OpConstant %10 5 %52 = OpTypeArray %50 %51 %53 = OpTypePointer Private %52 - %45 = OpUndef %9 %46 = OpConstantNull %9 %47 = OpTypePointer Private %8 %48 = OpVariable %47 Private @@ -203,15 +203,6 @@ TEST(TransformationAccessChainTest, BasicTest) { #ifndef NDEBUG // Bad: pointer is null - ASSERT_DEATH( - TransformationAccessChain(100, 45, {80}, - MakeInstructionDescriptor(24, SpvOpLoad, 0)) - .IsApplicable(context.get(), transformation_context), - "Access chains should not be created from null/undefined pointers"); -#endif - -#ifndef NDEBUG - // Bad: pointer is undef ASSERT_DEATH( TransformationAccessChain(100, 46, {80}, MakeInstructionDescriptor(24, SpvOpLoad, 0)) @@ -331,6 +322,7 @@ TEST(TransformationAccessChainTest, BasicTest) { std::string after_transformation = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %48 %54 @@ -368,7 +360,6 @@ TEST(TransformationAccessChainTest, BasicTest) { %85 = OpConstant %10 5 %52 = OpTypeArray %50 %51 %53 = OpTypePointer Private %52 - %45 = OpUndef %9 %46 = OpConstantNull %9 %47 = OpTypePointer Private %8 %48 = OpVariable %47 Private diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_copy_memory_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_copy_memory_test.cpp index 642a5561c1..ff8ac72e0b 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_add_copy_memory_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_add_copy_memory_test.cpp @@ -26,6 +26,7 @@ namespace { TEST(TransformationAddCopyMemoryTest, BasicTest) { std::string shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -64,7 +65,6 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) { %67 = OpTypePointer Function %66 %83 = OpTypePointer Private %66 %86 = OpVariable %79 Private %20 - %87 = OpUndef %79 %88 = OpConstantNull %79 %4 = OpFunction %2 None %3 %5 = OpLabel @@ -182,12 +182,6 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) { 90, 40, SpvStorageClassPrivate, 0) .IsApplicable(context.get(), transformation_context)); - // Source instruction is OpUndef. - ASSERT_FALSE( - TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0), - 90, 87, SpvStorageClassPrivate, 0) - .IsApplicable(context.get(), transformation_context)); - // Source instruction is OpConstantNull. ASSERT_FALSE( TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0), @@ -255,6 +249,7 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) { std::string expected = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -293,7 +288,6 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) { %67 = OpTypePointer Function %66 %83 = OpTypePointer Private %66 %86 = OpVariable %79 Private %20 - %87 = OpUndef %79 %88 = OpConstantNull %79 %90 = OpVariable %79 Private %20 %92 = OpVariable %78 Private %25 diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_synonym_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_synonym_test.cpp index 314b0039e9..ffcf1c9bd0 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_add_synonym_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_add_synonym_test.cpp @@ -1242,9 +1242,10 @@ TEST(TransformationAddSynonymTest, MiscellaneousCopies) { ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } -TEST(TransformationAddSynonymTest, DoNotCopyNullOrUndefPointers) { +TEST(TransformationAddSynonymTest, DoNotCopyNullPointers) { std::string shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -1255,7 +1256,6 @@ TEST(TransformationAddSynonymTest, DoNotCopyNullOrUndefPointers) { %6 = OpTypeInt 32 1 %7 = OpTypePointer Function %6 %8 = OpConstantNull %7 - %9 = OpUndef %7 %4 = OpFunction %2 None %3 %5 = OpLabel OpReturn @@ -1275,12 +1275,6 @@ TEST(TransformationAddSynonymTest, DoNotCopyNullOrUndefPointers) { 8, protobufs::TransformationAddSynonym::COPY_OBJECT, 100, MakeInstructionDescriptor(5, SpvOpReturn, 0)) .IsApplicable(context.get(), transformation_context)); - - // Illegal to copy an OpUndef of pointer type. - ASSERT_FALSE(TransformationAddSynonym( - 9, protobufs::TransformationAddSynonym::COPY_OBJECT, 100, - MakeInstructionDescriptor(5, SpvOpReturn, 0)) - .IsApplicable(context.get(), transformation_context)); } TEST(TransformationAddSynonymTest, PropagateIrrelevantPointeeFact) { diff --git a/third_party/spirv-tools/test/fuzz/transformation_load_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_load_test.cpp index a03ffdd65d..370826eb82 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_load_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_load_test.cpp @@ -26,6 +26,7 @@ namespace { TEST(TransformationLoadTest, BasicTest) { std::string shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -49,7 +50,6 @@ TEST(TransformationLoadTest, BasicTest) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %4 = OpFunction %2 None %3 @@ -129,65 +129,69 @@ TEST(TransformationLoadTest, BasicTest) { // Pointers that cannot be used: // 60 - null - // 61 - undefined // Bad: id is not fresh - ASSERT_FALSE(TransformationLoad( - 33, 33, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationLoad(33, 33, false, 0, 0, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: attempt to load from 11 from outside its function - ASSERT_FALSE(TransformationLoad( - 100, 11, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationLoad(100, 11, false, 0, 0, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: pointer is not available - ASSERT_FALSE(TransformationLoad( - 100, 33, MakeInstructionDescriptor(45, SpvOpCopyObject, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationLoad(100, 33, false, 0, 0, + MakeInstructionDescriptor(45, SpvOpCopyObject, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: attempt to insert before OpVariable - ASSERT_FALSE(TransformationLoad( - 100, 27, MakeInstructionDescriptor(27, SpvOpVariable, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationLoad(100, 27, false, 0, 0, + MakeInstructionDescriptor(27, SpvOpVariable, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: pointer id does not exist ASSERT_FALSE( - TransformationLoad(100, 1000, + TransformationLoad(100, 1000, false, 0, 0, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) .IsApplicable(context.get(), transformation_context)); // Bad: pointer id exists but does not have a type - ASSERT_FALSE(TransformationLoad( - 100, 5, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); - - // Bad: pointer id exists and has a type, but is not a pointer - ASSERT_FALSE(TransformationLoad( - 100, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); - - // Bad: attempt to load from null pointer - ASSERT_FALSE(TransformationLoad( - 100, 60, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); - - // Bad: attempt to load from undefined pointer - ASSERT_FALSE(TransformationLoad( - 100, 61, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); - // Bad: %40 is not available at the program point ASSERT_FALSE( - TransformationLoad(100, 40, MakeInstructionDescriptor(37, SpvOpReturn, 0)) + TransformationLoad(100, 5, false, 0, 0, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) .IsApplicable(context.get(), transformation_context)); - // Bad: The described instruction does not exist - ASSERT_FALSE(TransformationLoad( - 100, 33, MakeInstructionDescriptor(1000, SpvOpReturn, 0)) + // Bad: pointer id exists and has a type, but is not a pointer + ASSERT_FALSE( + TransformationLoad(100, 24, false, 0, 0, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: attempt to load from null pointer + ASSERT_FALSE( + TransformationLoad(100, 60, false, 0, 0, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: %40 is not available at the program point + ASSERT_FALSE(TransformationLoad(100, 40, false, 0, 0, + MakeInstructionDescriptor(37, SpvOpReturn, 0)) .IsApplicable(context.get(), transformation_context)); + // Bad: The described instruction does not exist + ASSERT_FALSE( + TransformationLoad(100, 33, false, 0, 0, + MakeInstructionDescriptor(1000, SpvOpReturn, 0)) + .IsApplicable(context.get(), transformation_context)); + { TransformationLoad transformation( - 100, 33, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)); + 100, 33, false, 0, 0, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -198,7 +202,8 @@ TEST(TransformationLoadTest, BasicTest) { { TransformationLoad transformation( - 101, 46, MakeInstructionDescriptor(16, SpvOpReturnValue, 0)); + 101, 46, false, 0, 0, + MakeInstructionDescriptor(16, SpvOpReturnValue, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -209,7 +214,8 @@ TEST(TransformationLoadTest, BasicTest) { { TransformationLoad transformation( - 102, 16, MakeInstructionDescriptor(16, SpvOpReturnValue, 0)); + 102, 16, false, 0, 0, + MakeInstructionDescriptor(16, SpvOpReturnValue, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -220,7 +226,8 @@ TEST(TransformationLoadTest, BasicTest) { { TransformationLoad transformation( - 103, 40, MakeInstructionDescriptor(43, SpvOpAccessChain, 0)); + 103, 40, false, 0, 0, + MakeInstructionDescriptor(43, SpvOpAccessChain, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -231,6 +238,7 @@ TEST(TransformationLoadTest, BasicTest) { std::string after_transformation = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -254,7 +262,6 @@ TEST(TransformationLoadTest, BasicTest) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %4 = OpFunction %2 None %3 @@ -293,6 +300,296 @@ TEST(TransformationLoadTest, BasicTest) { ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } +TEST(TransformationLoadTest, AtomicLoadTestCase) { + const std::string shader = R"( + OpCapability Shader + OpCapability Int8 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 8 1 + %9 = OpTypeInt 32 0 + %26 = OpTypeFloat 32 + %8 = OpTypeStruct %6 + %10 = OpTypePointer StorageBuffer %8 + %11 = OpVariable %10 StorageBuffer + %19 = OpConstant %26 0 + %18 = OpConstant %9 1 + %12 = OpConstant %6 0 + %13 = OpTypePointer StorageBuffer %6 + %15 = OpConstant %6 4 + %16 = OpConstant %6 7 + %17 = OpConstant %7 4 + %20 = OpConstant %9 64 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %14 = OpAccessChain %13 %11 %12 + %24 = OpAccessChain %13 %11 %12 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + // Bad: id is not fresh. + ASSERT_FALSE( + TransformationLoad(14, 14, true, 15, 20, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: id 100 of memory scope instruction does not exist. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 100, 20, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: id 100 of memory semantics instruction does not exist. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 15, 100, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: memory scope should be |OpConstant| opcode. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 5, 20, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: memory semantics should be |OpConstant| opcode. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 15, 5, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: The memory scope instruction must have an Integer operand. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 15, 19, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: The memory memory semantics instruction must have an Integer operand. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 19, 20, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: Integer size of the memory scope must be equal to 32 bits. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 17, 20, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: Integer size of memory semantics must be equal to 32 bits. + ASSERT_FALSE( + TransformationLoad(21, 14, true, 15, 17, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: memory scope value must be 4 (SpvScopeInvocation). + ASSERT_FALSE( + TransformationLoad(21, 14, true, 16, 20, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: memory semantics value must be either: + // 64 (SpvMemorySemanticsUniformMemoryMask) + // 256 (SpvMemorySemanticsWorkgroupMemoryMask) + ASSERT_FALSE( + TransformationLoad(21, 14, true, 15, 16, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: The described instruction does not exist + ASSERT_FALSE( + TransformationLoad(21, 14, false, 15, 20, + MakeInstructionDescriptor(150, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Successful transformations. + { + TransformationLoad transformation( + 21, 14, true, 15, 20, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)); + ASSERT_TRUE( + transformation.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation, context.get(), + &transformation_context); + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( + context.get(), validator_options, kConsoleMessageConsumer)); + } + + const std::string after_transformation = R"( + OpCapability Shader + OpCapability Int8 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 8 1 + %9 = OpTypeInt 32 0 + %26 = OpTypeFloat 32 + %8 = OpTypeStruct %6 + %10 = OpTypePointer StorageBuffer %8 + %11 = OpVariable %10 StorageBuffer + %19 = OpConstant %26 0 + %18 = OpConstant %9 1 + %12 = OpConstant %6 0 + %13 = OpTypePointer StorageBuffer %6 + %15 = OpConstant %6 4 + %16 = OpConstant %6 7 + %17 = OpConstant %7 4 + %20 = OpConstant %9 64 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %14 = OpAccessChain %13 %11 %12 + %21 = OpAtomicLoad %6 %14 %15 %20 + %24 = OpAccessChain %13 %11 %12 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationLoadTest, AtomicLoadTestCaseForWorkgroupMemory) { + std::string shader = R"( + OpCapability Shader + OpCapability Int8 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %26 = OpTypeFloat 32 + %27 = OpTypeInt 8 1 + %7 = OpTypeInt 32 0 ; 0 means unsigned + %8 = OpConstant %7 0 + %17 = OpConstant %27 4 + %19 = OpConstant %26 0 + %9 = OpTypePointer Function %6 + %13 = OpTypeStruct %6 + %12 = OpTypePointer Workgroup %13 + %11 = OpVariable %12 Workgroup + %14 = OpConstant %6 0 + %15 = OpTypePointer Function %6 + %51 = OpTypePointer Private %6 + %21 = OpConstant %6 4 + %23 = OpConstant %6 256 + %25 = OpTypePointer Function %7 + %50 = OpTypePointer Workgroup %6 + %34 = OpTypeBool + %35 = OpConstantFalse %34 + %53 = OpVariable %51 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %37 None + OpBranchConditional %35 %36 %37 + %36 = OpLabel + %38 = OpAccessChain %50 %11 %14 + %40 = OpAccessChain %50 %11 %14 + OpBranch %37 + %37 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + // Bad: Can't insert OpAccessChain before the id 23 of memory scope. + ASSERT_FALSE( + TransformationLoad(60, 38, true, 21, 23, + MakeInstructionDescriptor(23, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: Can't insert OpAccessChain before the id 23 of memory semantics. + ASSERT_FALSE( + TransformationLoad(60, 38, true, 21, 23, + MakeInstructionDescriptor(21, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Successful transformations. + { + TransformationLoad transformation( + 60, 38, true, 21, 23, + MakeInstructionDescriptor(40, SpvOpAccessChain, 0)); + ASSERT_TRUE( + transformation.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation, context.get(), + &transformation_context); + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( + context.get(), validator_options, kConsoleMessageConsumer)); + } + + std::string after_transformation = R"( + OpCapability Shader + OpCapability Int8 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %26 = OpTypeFloat 32 + %27 = OpTypeInt 8 1 + %7 = OpTypeInt 32 0 ; 0 means unsigned + %8 = OpConstant %7 0 + %17 = OpConstant %27 4 + %19 = OpConstant %26 0 + %9 = OpTypePointer Function %6 + %13 = OpTypeStruct %6 + %12 = OpTypePointer Workgroup %13 + %11 = OpVariable %12 Workgroup + %14 = OpConstant %6 0 + %15 = OpTypePointer Function %6 + %51 = OpTypePointer Private %6 + %21 = OpConstant %6 4 + %23 = OpConstant %6 256 + %25 = OpTypePointer Function %7 + %50 = OpTypePointer Workgroup %6 + %34 = OpTypeBool + %35 = OpConstantFalse %34 + %53 = OpVariable %51 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %37 None + OpBranchConditional %35 %36 %37 + %36 = OpLabel + %38 = OpAccessChain %50 %11 %14 + %60 = OpAtomicLoad %6 %38 %21 %23 + %40 = OpAccessChain %50 %11 %14 + OpBranch %37 + %37 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + } // namespace } // namespace fuzz } // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_mutate_pointer_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_mutate_pointer_test.cpp index ae42310004..e869efa6f0 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_mutate_pointer_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_mutate_pointer_test.cpp @@ -26,6 +26,7 @@ namespace { TEST(TransformationMutatePointerTest, BasicTest) { std::string shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -60,7 +61,6 @@ TEST(TransformationMutatePointerTest, BasicTest) { %23 = OpTypePointer Output %6 %24 = OpVariable %23 Output %27 = OpTypeFunction %2 %13 - %32 = OpUndef %16 %33 = OpConstantNull %16 %4 = OpFunction %2 None %3 %5 = OpLabel @@ -110,10 +110,6 @@ TEST(TransformationMutatePointerTest, BasicTest) { ASSERT_FALSE(TransformationMutatePointer(11, 70, insert_before) .IsApplicable(context.get(), transformation_context)); - // |pointer_id| is a result id of OpUndef. - ASSERT_FALSE(TransformationMutatePointer(32, 70, insert_before) - .IsApplicable(context.get(), transformation_context)); - // |pointer_id| is a result id of OpConstantNull. ASSERT_FALSE(TransformationMutatePointer(33, 70, insert_before) .IsApplicable(context.get(), transformation_context)); @@ -163,6 +159,7 @@ TEST(TransformationMutatePointerTest, BasicTest) { std::string after_transformation = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" @@ -197,7 +194,6 @@ TEST(TransformationMutatePointerTest, BasicTest) { %23 = OpTypePointer Output %6 %24 = OpVariable %23 Output %27 = OpTypeFunction %2 %13 - %32 = OpUndef %16 %33 = OpConstantNull %16 %4 = OpFunction %2 None %3 %5 = OpLabel diff --git a/third_party/spirv-tools/test/fuzz/transformation_push_id_through_variable_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_push_id_through_variable_test.cpp index 7487cab9df..b0fff58873 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_push_id_through_variable_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_push_id_through_variable_test.cpp @@ -26,6 +26,7 @@ namespace { TEST(TransformationPushIdThroughVariableTest, IsApplicable) { std::string reference_shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %92 %52 %53 @@ -50,7 +51,6 @@ TEST(TransformationPushIdThroughVariableTest, IsApplicable) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -257,6 +257,7 @@ TEST(TransformationPushIdThroughVariableTest, IsApplicable) { TEST(TransformationPushIdThroughVariableTest, Apply) { std::string reference_shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %92 %52 %53 @@ -281,7 +282,6 @@ TEST(TransformationPushIdThroughVariableTest, Apply) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -419,6 +419,7 @@ TEST(TransformationPushIdThroughVariableTest, Apply) { std::string variant_shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %92 %52 %53 %109 %111 @@ -443,7 +444,6 @@ TEST(TransformationPushIdThroughVariableTest, Apply) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -519,6 +519,7 @@ TEST(TransformationPushIdThroughVariableTest, Apply) { TEST(TransformationPushIdThroughVariableTest, AddSynonymsForRelevantIds) { std::string reference_shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %92 %52 %53 @@ -543,7 +544,6 @@ TEST(TransformationPushIdThroughVariableTest, AddSynonymsForRelevantIds) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -620,6 +620,7 @@ TEST(TransformationPushIdThroughVariableTest, AddSynonymsForRelevantIds) { TEST(TransformationPushIdThroughVariableTest, DontAddSynonymsForIrrelevantIds) { std::string reference_shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %92 %52 %53 @@ -644,7 +645,6 @@ TEST(TransformationPushIdThroughVariableTest, DontAddSynonymsForIrrelevantIds) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 diff --git a/third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp index c0739c3bae..b33dd48ca2 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp @@ -1796,27 +1796,8 @@ TEST(TransformationReplaceIdWithSynonymTest, IncompatibleTypes) { .IsApplicable(context.get(), transformation_context)); } -// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4346): This test -// should be updated to cover more atomic operations, and once the issue is -// fixed the test should be enabled. TEST(TransformationReplaceIdWithSynonymTest, - DISABLED_AtomicScopeAndMemorySemanticsMustBeConstant) { - // The following SPIR-V came from this GLSL, edited to add some synonyms: - // - // #version 320 es - // - // #extension GL_KHR_memory_scope_semantics : enable - // - // layout(set = 0, binding = 0) buffer Buf { - // int x; - // }; - // - // void main() { - // int tmp = atomicLoad(x, - // gl_ScopeWorkgroup, - // gl_StorageSemanticsBuffer, - // gl_SemanticsRelaxed); - // } + AtomicScopeAndMemorySemanticsMustBeConstant) { const std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -1832,15 +1813,19 @@ TEST(TransformationReplaceIdWithSynonymTest, %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 + %17 = OpTypeInt 32 0 %7 = OpTypePointer Function %6 %9 = OpTypeStruct %6 %10 = OpTypePointer StorageBuffer %9 %11 = OpVariable %10 StorageBuffer + %86 = OpTypeStruct %17 + %87 = OpTypePointer Workgroup %86 + %88 = OpVariable %87 Workgroup %12 = OpConstant %6 0 %13 = OpTypePointer StorageBuffer %6 %15 = OpConstant %6 2 %16 = OpConstant %6 64 - %17 = OpTypeInt 32 0 + %89 = OpTypePointer Workgroup %17 %18 = OpConstant %17 1 %19 = OpConstant %17 0 %20 = OpConstant %17 64 @@ -1850,8 +1835,23 @@ TEST(TransformationReplaceIdWithSynonymTest, %100 = OpCopyObject %6 %15 ; A non-constant version of %15 %101 = OpCopyObject %17 %20 ; A non-constant version of %20 %14 = OpAccessChain %13 %11 %12 + %90 = OpAccessChain %89 %88 %19 %21 = OpAtomicLoad %6 %14 %15 %20 + %22 = OpAtomicExchange %6 %14 %15 %20 %16 + %23 = OpAtomicCompareExchange %6 %14 %15 %20 %12 %16 %15 + %24 = OpAtomicIIncrement %6 %14 %15 %20 + %25 = OpAtomicIDecrement %6 %14 %15 %20 + %26 = OpAtomicIAdd %6 %14 %15 %20 %16 + %27 = OpAtomicISub %6 %14 %15 %20 %16 + %28 = OpAtomicSMin %6 %14 %15 %20 %16 + %29 = OpAtomicUMin %17 %90 %15 %20 %18 + %30 = OpAtomicSMax %6 %14 %15 %20 %15 + %31 = OpAtomicUMax %17 %90 %15 %20 %18 + %32 = OpAtomicAnd %6 %14 %15 %20 %16 + %33 = OpAtomicOr %6 %14 %15 %20 %16 + %34 = OpAtomicXor %6 %14 %15 %20 %16 OpStore %8 %21 + OpAtomicStore %14 %15 %20 %12 OpReturn OpFunctionEnd )"; @@ -1872,7 +1872,7 @@ TEST(TransformationReplaceIdWithSynonymTest, // Tell the fact manager that %101 and %20 are synonymous transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(101, {}), MakeDataDescriptor(20, {})); - + // OpAtomicLoad const auto& scope_operand = MakeIdUseDescriptorFromUse( context.get(), context->get_def_use_mgr()->GetDef(21), 1); ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand, 100) @@ -1882,6 +1882,148 @@ TEST(TransformationReplaceIdWithSynonymTest, context.get(), context->get_def_use_mgr()->GetDef(21), 2); ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand, 101) .IsApplicable(context.get(), transformation_context)); + // OpAtomicExchange. + const auto& scope_operand2 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(22), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand2, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand2 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(22), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand2, 101) + .IsApplicable(context.get(), transformation_context)); + // OpAtomicCompareExchange. + const auto& scope_operand3 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(23), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand3, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_equal_operand3 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(23), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_equal_operand3, 101) + .IsApplicable(context.get(), transformation_context)); + const auto& semantics_unequal_operand3 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(23), 3); + ASSERT_FALSE( + TransformationReplaceIdWithSynonym(semantics_unequal_operand3, 101) + .IsApplicable(context.get(), transformation_context)); + // OpAtomicIIncrement. + const auto& scope_operand4 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(24), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand4, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand4 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(24), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand4, 101) + .IsApplicable(context.get(), transformation_context)); + + // OpAtomicIDecrement. + const auto& scope_operand5 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(25), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand5, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand5 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(25), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand5, 101) + .IsApplicable(context.get(), transformation_context)); + + // OpAtomicIAdd. + const auto& scope_operand6 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(26), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand6, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand6 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(26), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand6, 101) + .IsApplicable(context.get(), transformation_context)); + // OpAtomicISub + const auto& scope_operand8 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(27), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand8, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand8 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(27), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand8, 101) + .IsApplicable(context.get(), transformation_context)); + + // OpAtomicSMin + const auto& scope_operand9 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(28), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand9, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand9 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(28), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand9, 101) + .IsApplicable(context.get(), transformation_context)); + // OpAtomicUMin + const auto& scope_operand10 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(29), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand10, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand10 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(29), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand10, 101) + .IsApplicable(context.get(), transformation_context)); + + // OpAtomicSMax + const auto& scope_operand11 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(30), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand11, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand11 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(30), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand11, 101) + .IsApplicable(context.get(), transformation_context)); + // OpAtomicUMax + const auto& scope_operand12 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(31), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand12, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand12 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(31), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand12, 101) + .IsApplicable(context.get(), transformation_context)); + + // OpAtomicAnd + const auto& scope_operand13 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(32), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand13, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand13 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(32), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand13, 101) + .IsApplicable(context.get(), transformation_context)); + + // OpAtomicOr + const auto& scope_operand14 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(33), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand14, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand14 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(33), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand14, 101) + .IsApplicable(context.get(), transformation_context)); + + // OpAtomicXor + const auto& scope_operand15 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(34), 1); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(scope_operand15, 100) + .IsApplicable(context.get(), transformation_context)); + + const auto& semantics_operand15 = MakeIdUseDescriptorFromUse( + context.get(), context->get_def_use_mgr()->GetDef(34), 2); + ASSERT_FALSE(TransformationReplaceIdWithSynonym(semantics_operand15, 101) + .IsApplicable(context.get(), transformation_context)); } // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4345): Improve this @@ -2031,65 +2173,6 @@ TEST(TransformationReplaceIdWithSynonymTest, ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } -// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4345): Improve this -// test so that it covers more atomic operations, and enable the test once the -// issue is fixed. -TEST(TransformationReplaceIdWithSynonymTest, DISABLED_TypesAreCompatible) { - const std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" - OpExecutionMode %4 OriginUpperLeft - OpSource ESSL 320 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %9 = OpTypeInt 32 0 - %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); - spvtools::ValidatorOptions validator_options; - ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, - kConsoleMessageConsumer)); - - const uint32_t int_type = 6; // The id of OpTypeInt 32 1 - const uint32_t uint_type = 9; // The id of OpTypeInt 32 0 - - // OpAtomicLoad -#ifndef NDEBUG - ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible( - context.get(), SpvOpAtomicLoad, 0, int_type, uint_type), - "Invalid operand index"); -#endif - ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible( - context.get(), SpvOpAtomicLoad, 1, int_type, uint_type)); - ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible( - context.get(), SpvOpAtomicLoad, 2, int_type, uint_type)); - - // OpAtomicExchange -#ifndef NDEBUG - ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible( - context.get(), SpvOpAtomicExchange, 0, int_type, uint_type), - "Invalid operand index"); -#endif - ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible( - context.get(), SpvOpAtomicExchange, 1, int_type, uint_type)); - ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible( - context.get(), SpvOpAtomicExchange, 2, int_type, uint_type)); - ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible( - context.get(), SpvOpAtomicExchange, 2, int_type, uint_type)); - - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4345): Similar for - // other atomic instructions -} - } // namespace } // namespace fuzz } // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_store_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_store_test.cpp index 93257d0d0e..dd653e28d9 100644 --- a/third_party/spirv-tools/test/fuzz/transformation_store_test.cpp +++ b/third_party/spirv-tools/test/fuzz/transformation_store_test.cpp @@ -26,6 +26,7 @@ namespace { TEST(TransformationStoreTest, BasicTest) { std::string shader = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %92 %52 %53 @@ -50,7 +51,6 @@ TEST(TransformationStoreTest, BasicTest) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -148,90 +148,107 @@ TEST(TransformationStoreTest, BasicTest) { // 61 - undefined // Bad: attempt to store to 11 from outside its function - ASSERT_FALSE(TransformationStore( - 11, 80, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(11, false, 0, 0, 80, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: pointer is not available - ASSERT_FALSE(TransformationStore( - 81, 80, MakeInstructionDescriptor(45, SpvOpCopyObject, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(81, false, 0, 0, 80, + MakeInstructionDescriptor(45, SpvOpCopyObject, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: attempt to insert before OpVariable - ASSERT_FALSE(TransformationStore( - 52, 24, MakeInstructionDescriptor(27, SpvOpVariable, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(52, false, 0, 0, 24, + MakeInstructionDescriptor(27, SpvOpVariable, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: pointer id does not exist - ASSERT_FALSE(TransformationStore( - 1000, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(1000, false, 0, 0, 24, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: pointer id exists but does not have a type - ASSERT_FALSE(TransformationStore( - 5, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(5, false, 0, 0, 24, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: pointer id exists and has a type, but is not a pointer - ASSERT_FALSE(TransformationStore( - 24, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(24, false, 0, 0, 24, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: attempt to store to a null pointer - ASSERT_FALSE(TransformationStore( - 60, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(60, false, 0, 0, 24, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: attempt to store to an undefined pointer - ASSERT_FALSE(TransformationStore( - 61, 21, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(61, false, 0, 0, 21, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: %82 is not available at the program point ASSERT_FALSE( - TransformationStore(82, 80, MakeInstructionDescriptor(37, SpvOpReturn, 0)) + TransformationStore(82, false, 0, 0, 80, + MakeInstructionDescriptor(37, SpvOpReturn, 0)) .IsApplicable(context.get(), transformation_context)); // Bad: value id does not exist - ASSERT_FALSE(TransformationStore( - 27, 1000, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(27, false, 0, 0, 1000, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: value id exists but does not have a type - ASSERT_FALSE(TransformationStore( - 27, 15, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(27, false, 0, 0, 15, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: value id exists but has the wrong type - ASSERT_FALSE(TransformationStore( - 27, 14, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(27, false, 0, 0, 14, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: attempt to store to read-only variable - ASSERT_FALSE(TransformationStore( - 92, 93, MakeInstructionDescriptor(40, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(92, false, 0, 0, 93, + MakeInstructionDescriptor(40, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: value is not available - ASSERT_FALSE(TransformationStore( - 27, 95, MakeInstructionDescriptor(40, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(27, false, 0, 0, 95, + MakeInstructionDescriptor(40, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); // Bad: variable being stored to does not have an irrelevant pointee value, // and the store is not in a dead block. - ASSERT_FALSE(TransformationStore( - 20, 95, MakeInstructionDescriptor(45, SpvOpCopyObject, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(20, false, 0, 0, 95, + MakeInstructionDescriptor(45, SpvOpCopyObject, 0)) + .IsApplicable(context.get(), transformation_context)); // The described instruction does not exist. - ASSERT_FALSE(TransformationStore( - 27, 80, MakeInstructionDescriptor(1000, SpvOpAccessChain, 0)) - .IsApplicable(context.get(), transformation_context)); + ASSERT_FALSE( + TransformationStore(27, false, 0, 0, 80, + MakeInstructionDescriptor(1000, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); { // Store to irrelevant variable from dead block. TransformationStore transformation( - 27, 80, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)); + 27, false, 0, 0, 80, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -243,7 +260,8 @@ TEST(TransformationStoreTest, BasicTest) { { // Store to irrelevant variable from live block. TransformationStore transformation( - 11, 95, MakeInstructionDescriptor(95, SpvOpReturnValue, 0)); + 11, false, 0, 0, 95, + MakeInstructionDescriptor(95, SpvOpReturnValue, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -255,7 +273,8 @@ TEST(TransformationStoreTest, BasicTest) { { // Store to irrelevant variable from live block. TransformationStore transformation( - 46, 80, MakeInstructionDescriptor(95, SpvOpReturnValue, 0)); + 46, false, 0, 0, 80, + MakeInstructionDescriptor(95, SpvOpReturnValue, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -267,7 +286,8 @@ TEST(TransformationStoreTest, BasicTest) { { // Store to irrelevant variable from live block. TransformationStore transformation( - 16, 21, MakeInstructionDescriptor(95, SpvOpReturnValue, 0)); + 16, false, 0, 0, 21, + MakeInstructionDescriptor(95, SpvOpReturnValue, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -279,7 +299,8 @@ TEST(TransformationStoreTest, BasicTest) { { // Store to non-irrelevant variable from dead block. TransformationStore transformation( - 53, 21, MakeInstructionDescriptor(38, SpvOpAccessChain, 0)); + 53, false, 0, 0, 21, + MakeInstructionDescriptor(38, SpvOpAccessChain, 0)); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation, context.get(), @@ -290,6 +311,7 @@ TEST(TransformationStoreTest, BasicTest) { std::string after_transformation = R"( OpCapability Shader + OpCapability VariablePointers %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %92 %52 %53 @@ -314,7 +336,6 @@ TEST(TransformationStoreTest, BasicTest) { %34 = OpTypeBool %35 = OpConstantFalse %34 %60 = OpConstantNull %50 - %61 = OpUndef %51 %52 = OpVariable %50 Private %53 = OpVariable %51 Private %80 = OpConstantComposite %8 %21 %24 @@ -414,16 +435,190 @@ TEST(TransformationStoreTest, DoNotAllowStoresToReadOnlyMemory) { transformation_context.GetFactManager()->AddFactBlockIsDead(5); ASSERT_FALSE( - TransformationStore(15, 13, MakeInstructionDescriptor(27, SpvOpReturn, 0)) + TransformationStore(15, false, 0, 0, 13, + MakeInstructionDescriptor(27, SpvOpReturn, 0)) .IsApplicable(context.get(), transformation_context)); ASSERT_FALSE( - TransformationStore(19, 50, MakeInstructionDescriptor(27, SpvOpReturn, 0)) + TransformationStore(19, false, 0, 0, 50, + MakeInstructionDescriptor(27, SpvOpReturn, 0)) .IsApplicable(context.get(), transformation_context)); ASSERT_FALSE( - TransformationStore(27, 50, MakeInstructionDescriptor(27, SpvOpReturn, 0)) + TransformationStore(27, false, 0, 0, 50, + MakeInstructionDescriptor(27, SpvOpReturn, 0)) .IsApplicable(context.get(), transformation_context)); } +TEST(TransformationStoreTest, SupportAtomicStore) { + const std::string shader = R"( + OpCapability Shader + OpCapability Int8 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 8 1 + %9 = OpTypeInt 32 0 + %26 = OpTypeFloat 32 + %8 = OpTypeStruct %6 + %10 = OpTypePointer StorageBuffer %8 + %11 = OpVariable %10 StorageBuffer + %19 = OpConstant %26 0 + %18 = OpConstant %9 1 + %12 = OpConstant %6 0 + %13 = OpTypePointer StorageBuffer %6 + %15 = OpConstant %6 4 + %16 = OpConstant %6 7 + %17 = OpConstant %7 4 + %20 = OpConstant %9 64 + %21 = OpConstant %6 15 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %14 = OpAccessChain %13 %11 %12 + %24 = OpAccessChain %13 %11 %12 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( + 14); + + // Bad: id 100 of memory scope instruction does not exist. + ASSERT_FALSE( + TransformationStore(14, true, 100, 20, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: id 100 of memory semantics instruction does not exist. + ASSERT_FALSE( + TransformationStore(14, true, 15, 100, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: memory scope should be |OpConstant| opcode. + ASSERT_FALSE( + TransformationStore(14, true, 5, 20, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: memory semantics should be |OpConstant| opcode. + ASSERT_FALSE( + TransformationStore(14, true, 15, 5, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: The memory scope instruction must have an Integer operand. + ASSERT_FALSE( + TransformationStore(14, true, 15, 19, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: The memory memory semantics instruction must have an Integer operand. + ASSERT_FALSE( + TransformationStore(14, true, 19, 20, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: Integer size of the memory scope must be equal to 32 bits. + ASSERT_FALSE( + TransformationStore(14, true, 17, 20, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: Integer size of memory semantics must be equal to 32 bits. + ASSERT_FALSE( + TransformationStore(14, true, 15, 17, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: memory scope value must be 4 (SpvScopeInvocation). + ASSERT_FALSE( + TransformationStore(14, true, 16, 20, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: memory semantics value must be either: + // 64 (SpvMemorySemanticsUniformMemoryMask) + // 256 (SpvMemorySemanticsWorkgroupMemoryMask) + ASSERT_FALSE( + TransformationStore(14, true, 15, 16, 21, + MakeInstructionDescriptor(24, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + // Bad: The described instruction does not exist + ASSERT_FALSE( + TransformationStore(14, true, 15, 20, 21, + MakeInstructionDescriptor(150, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: Can't insert OpAccessChain before the id 15 of memory scope. + ASSERT_FALSE( + TransformationStore(14, true, 15, 20, 21, + MakeInstructionDescriptor(15, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Bad: Can't insert OpAccessChain before the id 20 of memory semantics. + ASSERT_FALSE( + TransformationStore(14, true, 15, 20, 21, + MakeInstructionDescriptor(20, SpvOpAccessChain, 0)) + .IsApplicable(context.get(), transformation_context)); + + // Successful transformations. + { + TransformationStore transformation( + 14, true, 15, 20, 21, MakeInstructionDescriptor(24, SpvOpReturn, 0)); + ASSERT_TRUE( + transformation.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation, context.get(), + &transformation_context); + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( + context.get(), validator_options, kConsoleMessageConsumer)); + } + + const std::string after_transformation = R"( + OpCapability Shader + OpCapability Int8 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 8 1 + %9 = OpTypeInt 32 0 + %26 = OpTypeFloat 32 + %8 = OpTypeStruct %6 + %10 = OpTypePointer StorageBuffer %8 + %11 = OpVariable %10 StorageBuffer + %19 = OpConstant %26 0 + %18 = OpConstant %9 1 + %12 = OpConstant %6 0 + %13 = OpTypePointer StorageBuffer %6 + %15 = OpConstant %6 4 + %16 = OpConstant %6 7 + %17 = OpConstant %7 4 + %20 = OpConstant %9 64 + %21 = OpConstant %6 15 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %14 = OpAccessChain %13 %11 %12 + %24 = OpAccessChain %13 %11 %12 + OpAtomicStore %14 %15 %20 %21 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + } // namespace } // namespace fuzz } // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_wrap_vector_synonym_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_wrap_vector_synonym_test.cpp new file mode 100644 index 0000000000..0d1009b313 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_wrap_vector_synonym_test.cpp @@ -0,0 +1,1553 @@ +// Copyright (c) 2021 Shiyu Liu +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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_wrap_vector_synonym.h" + +#include "gtest/gtest.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationWrapVectorSynonym, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %97 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 -5 + %12 = OpTypeVector %6 2 + %13 = OpTypePointer Function %12 + %18 = OpTypeInt 32 0 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 8 + %23 = OpConstant %18 2 + %24 = OpTypeVector %18 3 + %25 = OpTypePointer Function %24 + %31 = OpTypeFloat 32 + %32 = OpTypePointer Function %31 + %34 = OpConstant %31 3.29999995 + %36 = OpConstant %31 1.10000002 + %37 = OpTypeVector %31 4 + %38 = OpTypePointer Function %37 + %96 = OpTypePointer Input %31 + %97 = OpVariable %96 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %33 = OpVariable %32 Function + %35 = OpVariable %32 Function + %39 = OpVariable %38 Function + %47 = OpVariable %7 Function + %51 = OpVariable %7 Function + %55 = OpVariable %7 Function + %59 = OpVariable %7 Function + %63 = OpVariable %19 Function + %67 = OpVariable %19 Function + %71 = OpVariable %19 Function + %75 = OpVariable %19 Function + %79 = OpVariable %32 Function + %83 = OpVariable %32 Function + %87 = OpVariable %32 Function + %91 = OpVariable %32 Function + OpStore %8 %9 + OpStore %10 %11 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpCompositeConstruct %12 %15 %16 + OpStore %14 %17 + OpStore %20 %21 + OpStore %22 %23 + %27 = OpLoad %18 %20 + %28 = OpLoad %18 %20 + %29 = OpLoad %18 %22 + %30 = OpCompositeConstruct %24 %27 %28 %29 + OpStore %26 %30 + OpStore %33 %34 + OpStore %35 %36 + %40 = OpLoad %31 %33 + %41 = OpLoad %31 %33 + %42 = OpLoad %31 %35 + %43 = OpLoad %31 %35 + %44 = OpCompositeConstruct %37 %40 %41 %42 %43 + %45 = OpLoad %37 %39 + %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 + OpStore %39 %46 + %48 = OpLoad %6 %8 + %49 = OpLoad %6 %10 + %100 = OpCompositeConstruct %12 %48 %48 + %101 = OpCompositeConstruct %12 %49 %49 + %50 = OpIAdd %6 %48 %49 + OpStore %47 %50 + %52 = OpLoad %6 %8 + %53 = OpLoad %6 %10 + %54 = OpISub %6 %52 %53 + OpStore %51 %54 + %56 = OpLoad %6 %8 + %57 = OpLoad %6 %10 + %58 = OpIMul %6 %56 %57 + OpStore %55 %58 + %60 = OpLoad %6 %8 + %61 = OpLoad %6 %10 + %62 = OpSDiv %6 %60 %61 + OpStore %59 %62 + %64 = OpLoad %18 %20 + %65 = OpLoad %18 %22 + %66 = OpIAdd %18 %64 %65 + OpStore %63 %66 + %68 = OpLoad %18 %20 + %69 = OpLoad %18 %22 + %70 = OpISub %18 %68 %69 + OpStore %67 %70 + %72 = OpLoad %18 %20 + %73 = OpLoad %18 %22 + %74 = OpIMul %18 %72 %73 + OpStore %71 %74 + %76 = OpLoad %18 %20 + %77 = OpLoad %18 %22 + %78 = OpUDiv %18 %76 %77 + OpStore %75 %78 + %80 = OpLoad %31 %33 + %81 = OpLoad %31 %35 + %82 = OpFAdd %31 %80 %81 + OpStore %79 %82 + %84 = OpLoad %31 %33 + %85 = OpLoad %31 %35 + %86 = OpFSub %31 %84 %85 + OpStore %83 %86 + %88 = OpLoad %31 %33 + %89 = OpLoad %31 %35 + %90 = OpFMul %31 %88 %89 + OpStore %87 %90 + %92 = OpLoad %31 %33 + %93 = OpLoad %31 %35 + %94 = OpFDiv %31 %92 %93 + OpStore %91 %94 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + + // Check context validity. + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + // Vec Type Id | Vector Type | Element Type id | Element Type | + // ------------+----------------+------------------+-----------------+ + // 12 | vec2 | 6 | int32 | + // 24 | vec3 | 18 | uint32 | + // 37 | vec4 | 31 | float | + + // Instruction Id | Opcode | Type Id | constant id 1 | constant id 2 | + // ---------------+---------+---------+---------------+---------------+ + // 50 | OpIAdd | 6 | 48 | 49 | + // 54 | OpISub | 6 | 52 | 53 | + // 58 | OpIMul | 6 | 56 | 57 | + // 62 | OpSDiv | 6 | 60 | 61 | + // 66 | OpIAdd | 18 | 64 | 65 | + // 70 | OpISub | 18 | 68 | 69 | + // 74 | OpIMul | 18 | 72 | 73 | + // 78 | OpUDiv | 18 | 76 | 77 | + // 82 | OpFAdd | 31 | 80 | 81 | + // 86 | OpFSub | 31 | 84 | 85 | + // 90 | OpFMul | 31 | 88 | 89 | + // 94 | OpFDiv | 31 | 92 | 93 | + + // Assert that the target scalar instruction result id is relevant. + ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50)); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {})); + + // The following are all invalid use. + { + // Bad: Instruction id does not exist. + TransformationWrapVectorSynonym wrap_add_int_bad1(103, 100, 101, 102, 1); + ASSERT_FALSE( + wrap_add_int_bad1.IsApplicable(context.get(), transformation_context)); + + // Bad: Instruction id given is not of a valid arithmetic operation typed + // instruction. + TransformationWrapVectorSynonym wrap_add_int_bad2(80, 100, 101, 102, 1); + ASSERT_FALSE( + wrap_add_int_bad1.IsApplicable(context.get(), transformation_context)); + + // Bad: the id for the first vector does not exist. + TransformationWrapVectorSynonym wrap_add_int_bad3(50, 105, 101, 102, 1); + ASSERT_FALSE( + wrap_add_int_bad3.IsApplicable(context.get(), transformation_context)); + + // Bad: the id for the second vector does not exist. + TransformationWrapVectorSynonym wrap_add_int_bad4(50, 100, 105, 102, 1); + ASSERT_FALSE( + wrap_add_int_bad4.IsApplicable(context.get(), transformation_context)); + + // Bad: vector id is not fresh. + TransformationWrapVectorSynonym wrap_add_int_bad6(50, 100, 101, 94, 1); + ASSERT_FALSE( + wrap_add_int_bad6.IsApplicable(context.get(), transformation_context)); + + // Bad: The position goes out of bound for the given vector type. + TransformationWrapVectorSynonym wrap_add_int_bad8(50, 100, 101, 102, 2); + ASSERT_FALSE( + wrap_add_int_bad8.IsApplicable(context.get(), transformation_context)); + + // Bad: The original instruction is not a valid scalar operation + // instruction. + TransformationWrapVectorSynonym wrap_add_int(27, 100, 101, 102, 1); + ASSERT_FALSE( + wrap_add_int.IsApplicable(context.get(), transformation_context)); + } + + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_add_int(50, 100, 101, 102, 1); + ASSERT_TRUE(wrap_add_int.IsApplicable(context.get(), transformation_context)); + // Insert an arithmetic instruction of the same type to add two vectors. + ApplyAndCheckFreshIds(wrap_add_int, context.get(), &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should be + // synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {}))); + + // After applying transformations, the instruction: + // + // %102 = OpIAdd %12 %100 %101 + // + // should be added before: + // + // %50 = OpIAdd %6 %48 %49 + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %97 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 -5 + %12 = OpTypeVector %6 2 + %13 = OpTypePointer Function %12 + %18 = OpTypeInt 32 0 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 8 + %23 = OpConstant %18 2 + %24 = OpTypeVector %18 3 + %25 = OpTypePointer Function %24 + %31 = OpTypeFloat 32 + %32 = OpTypePointer Function %31 + %34 = OpConstant %31 3.29999995 + %36 = OpConstant %31 1.10000002 + %37 = OpTypeVector %31 4 + %38 = OpTypePointer Function %37 + %96 = OpTypePointer Input %31 + %97 = OpVariable %96 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %33 = OpVariable %32 Function + %35 = OpVariable %32 Function + %39 = OpVariable %38 Function + %47 = OpVariable %7 Function + %51 = OpVariable %7 Function + %55 = OpVariable %7 Function + %59 = OpVariable %7 Function + %63 = OpVariable %19 Function + %67 = OpVariable %19 Function + %71 = OpVariable %19 Function + %75 = OpVariable %19 Function + %79 = OpVariable %32 Function + %83 = OpVariable %32 Function + %87 = OpVariable %32 Function + %91 = OpVariable %32 Function + OpStore %8 %9 + OpStore %10 %11 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpCompositeConstruct %12 %15 %16 + OpStore %14 %17 + OpStore %20 %21 + OpStore %22 %23 + %27 = OpLoad %18 %20 + %28 = OpLoad %18 %20 + %29 = OpLoad %18 %22 + %30 = OpCompositeConstruct %24 %27 %28 %29 + OpStore %26 %30 + OpStore %33 %34 + OpStore %35 %36 + %40 = OpLoad %31 %33 + %41 = OpLoad %31 %33 + %42 = OpLoad %31 %35 + %43 = OpLoad %31 %35 + %44 = OpCompositeConstruct %37 %40 %41 %42 %43 + %45 = OpLoad %37 %39 + %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 + OpStore %39 %46 + %48 = OpLoad %6 %8 + %49 = OpLoad %6 %10 + %100 = OpCompositeConstruct %12 %48 %48 + %101 = OpCompositeConstruct %12 %49 %49 + %102 = OpIAdd %12 %100 %101 + %50 = OpIAdd %6 %48 %49 + OpStore %47 %50 + %52 = OpLoad %6 %8 + %53 = OpLoad %6 %10 + %54 = OpISub %6 %52 %53 + OpStore %51 %54 + %56 = OpLoad %6 %8 + %57 = OpLoad %6 %10 + %58 = OpIMul %6 %56 %57 + OpStore %55 %58 + %60 = OpLoad %6 %8 + %61 = OpLoad %6 %10 + %62 = OpSDiv %6 %60 %61 + OpStore %59 %62 + %64 = OpLoad %18 %20 + %65 = OpLoad %18 %22 + %66 = OpIAdd %18 %64 %65 + OpStore %63 %66 + %68 = OpLoad %18 %20 + %69 = OpLoad %18 %22 + %70 = OpISub %18 %68 %69 + OpStore %67 %70 + %72 = OpLoad %18 %20 + %73 = OpLoad %18 %22 + %74 = OpIMul %18 %72 %73 + OpStore %71 %74 + %76 = OpLoad %18 %20 + %77 = OpLoad %18 %22 + %78 = OpUDiv %18 %76 %77 + OpStore %75 %78 + %80 = OpLoad %31 %33 + %81 = OpLoad %31 %35 + %82 = OpFAdd %31 %80 %81 + OpStore %79 %82 + %84 = OpLoad %31 %33 + %85 = OpLoad %31 %35 + %86 = OpFSub %31 %84 %85 + OpStore %83 %86 + %88 = OpLoad %31 %33 + %89 = OpLoad %31 %35 + %90 = OpFMul %31 %88 %89 + OpStore %87 %90 + %92 = OpLoad %31 %33 + %93 = OpLoad %31 %35 + %94 = OpFDiv %31 %92 %93 + OpStore %91 %94 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationWrapVectorSynonym, OperationSupportTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %97 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 -5 + %12 = OpTypeVector %6 2 + %13 = OpTypePointer Function %12 + %18 = OpTypeInt 32 0 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 8 + %23 = OpConstant %18 2 + %24 = OpTypeVector %18 3 + %25 = OpTypePointer Function %24 + %31 = OpTypeFloat 32 + %32 = OpTypePointer Function %31 + %34 = OpConstant %31 3.29999995 + %36 = OpConstant %31 1.10000002 + %37 = OpTypeVector %31 4 + %38 = OpTypePointer Function %37 + %96 = OpTypePointer Input %31 + %97 = OpVariable %96 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %33 = OpVariable %32 Function + %35 = OpVariable %32 Function + %39 = OpVariable %38 Function + %47 = OpVariable %7 Function + %51 = OpVariable %7 Function + %55 = OpVariable %7 Function + %59 = OpVariable %7 Function + %63 = OpVariable %19 Function + %67 = OpVariable %19 Function + %71 = OpVariable %19 Function + %75 = OpVariable %19 Function + %79 = OpVariable %32 Function + %83 = OpVariable %32 Function + %87 = OpVariable %32 Function + %91 = OpVariable %32 Function + OpStore %8 %9 + OpStore %10 %11 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpCompositeConstruct %12 %15 %16 + OpStore %14 %17 + OpStore %20 %21 + OpStore %22 %23 + %27 = OpLoad %18 %20 + %28 = OpLoad %18 %20 + %29 = OpLoad %18 %22 + %30 = OpCompositeConstruct %24 %27 %28 %29 + OpStore %26 %30 + OpStore %33 %34 + OpStore %35 %36 + %40 = OpLoad %31 %33 + %41 = OpLoad %31 %33 + %42 = OpLoad %31 %35 + %43 = OpLoad %31 %35 + %44 = OpCompositeConstruct %37 %40 %41 %42 %43 + %45 = OpLoad %37 %39 + %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 + OpStore %39 %46 + %48 = OpLoad %6 %8 + %49 = OpLoad %6 %10 + %50 = OpIAdd %6 %48 %49 + OpStore %47 %50 + %52 = OpLoad %6 %8 + %53 = OpLoad %6 %10 + %100 = OpCompositeConstruct %12 %52 %52 + %101 = OpCompositeConstruct %12 %53 %53 + %54 = OpISub %6 %52 %53 + OpStore %51 %54 + %56 = OpLoad %6 %8 + %57 = OpLoad %6 %10 + %103 = OpCompositeConstruct %12 %56 %56 + %104 = OpCompositeConstruct %12 %57 %57 + %58 = OpIMul %6 %56 %57 + OpStore %55 %58 + %60 = OpLoad %6 %8 + %61 = OpLoad %6 %10 + %62 = OpSDiv %6 %60 %61 + OpStore %59 %62 + %64 = OpLoad %18 %20 + %65 = OpLoad %18 %22 + %106 = OpCompositeConstruct %24 %64 %64 %64 + %107 = OpCompositeConstruct %24 %65 %65 %65 + %66 = OpIAdd %18 %64 %65 + OpStore %63 %66 + %68 = OpLoad %18 %20 + %69 = OpLoad %18 %22 + %109 = OpCompositeConstruct %24 %68 %68 %68 + %110 = OpCompositeConstruct %24 %69 %69 %69 + %70 = OpISub %18 %68 %69 + OpStore %67 %70 + %72 = OpLoad %18 %20 + %73 = OpLoad %18 %22 + %112 = OpCompositeConstruct %24 %72 %72 %72 + %113 = OpCompositeConstruct %24 %73 %73 %73 + %74 = OpIMul %18 %72 %73 + OpStore %71 %74 + %76 = OpLoad %18 %20 + %77 = OpLoad %18 %22 + %78 = OpUDiv %18 %76 %77 + OpStore %75 %78 + %80 = OpLoad %31 %33 + %81 = OpLoad %31 %35 + %115 = OpCompositeConstruct %37 %80 %80 %80 %80 + %116 = OpCompositeConstruct %37 %81 %81 %81 %81 + %82 = OpFAdd %31 %80 %81 + OpStore %79 %82 + %84 = OpLoad %31 %33 + %85 = OpLoad %31 %35 + %118 = OpCompositeConstruct %37 %84 %84 %84 %84 + %119 = OpCompositeConstruct %37 %85 %85 %85 %85 + %86 = OpFSub %31 %84 %85 + OpStore %83 %86 + %88 = OpLoad %31 %33 + %89 = OpLoad %31 %35 + %121 = OpCompositeConstruct %37 %88 %88 %88 %88 + %122 = OpCompositeConstruct %37 %89 %89 %89 %89 + %90 = OpFMul %31 %88 %89 + OpStore %87 %90 + %92 = OpLoad %31 %33 + %93 = OpLoad %31 %35 + %94 = OpFDiv %31 %92 %93 + OpStore %91 %94 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + { + // Add synonym facts between the vector operands at pos and the operands to + // the scalar instruction. + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(100, {1}), MakeDataDescriptor(52, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(101, {1}), MakeDataDescriptor(53, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(103, {0}), MakeDataDescriptor(56, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(104, {0}), MakeDataDescriptor(57, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(106, {2}), MakeDataDescriptor(64, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(107, {2}), MakeDataDescriptor(65, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(109, {2}), MakeDataDescriptor(68, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(110, {2}), MakeDataDescriptor(69, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(112, {1}), MakeDataDescriptor(72, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(113, {1}), MakeDataDescriptor(73, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(115, {2}), MakeDataDescriptor(80, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(116, {2}), MakeDataDescriptor(81, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(118, {3}), MakeDataDescriptor(84, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(119, {3}), MakeDataDescriptor(85, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(121, {1}), MakeDataDescriptor(88, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(122, {1}), MakeDataDescriptor(89, {})); + } + + // Test OpISub for signed integer. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_sub_int(54, 100, 101, 102, 1); + ASSERT_TRUE( + wrap_sub_int.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_sub_int, context.get(), &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(102, {1}), MakeDataDescriptor(54, {}))); + } + + // Test OpIMul for signed integer. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_mul_int(58, 103, 104, 105, 0); + ASSERT_TRUE( + wrap_mul_int.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_mul_int, context.get(), &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(105, {0}), MakeDataDescriptor(58, {}))); + } + + // Test OpIAdd for unsigned integer. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_add_uint(66, 106, 107, 108, 2); + ASSERT_TRUE( + wrap_add_uint.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_add_uint, context.get(), + &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(108, {2}), MakeDataDescriptor(66, {}))); + } + + // Test OpISub for signed integer. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_sub_uint(70, 109, 110, 111, 2); + ASSERT_TRUE( + wrap_sub_uint.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_sub_uint, context.get(), + &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(111, {2}), MakeDataDescriptor(70, {}))); + } + + // Test OpIMul for signed integer. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_mul_uint(74, 112, 113, 114, 1); + ASSERT_TRUE( + wrap_mul_uint.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_mul_uint, context.get(), + &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(114, {1}), MakeDataDescriptor(74, {}))); + } + + // Test OpFAdd for float. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_add_float(82, 115, 116, 117, 2); + ASSERT_TRUE( + wrap_add_float.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_add_float, context.get(), + &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(117, {2}), MakeDataDescriptor(82, {}))); + } + + // Test OpFSub for float. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_add_float(86, 118, 119, 120, 3); + ASSERT_TRUE( + wrap_add_float.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_add_float, context.get(), + &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(120, {3}), MakeDataDescriptor(86, {}))); + } + + // Test OpFMul for float. + { + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_mul_float(90, 121, 122, 123, 1); + ASSERT_TRUE( + wrap_mul_float.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(wrap_mul_float, context.get(), + &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(123, {1}), MakeDataDescriptor(90, {}))); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %97 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 -5 + %12 = OpTypeVector %6 2 + %13 = OpTypePointer Function %12 + %18 = OpTypeInt 32 0 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 8 + %23 = OpConstant %18 2 + %24 = OpTypeVector %18 3 + %25 = OpTypePointer Function %24 + %31 = OpTypeFloat 32 + %32 = OpTypePointer Function %31 + %34 = OpConstant %31 3.29999995 + %36 = OpConstant %31 1.10000002 + %37 = OpTypeVector %31 4 + %38 = OpTypePointer Function %37 + %96 = OpTypePointer Input %31 + %97 = OpVariable %96 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %33 = OpVariable %32 Function + %35 = OpVariable %32 Function + %39 = OpVariable %38 Function + %47 = OpVariable %7 Function + %51 = OpVariable %7 Function + %55 = OpVariable %7 Function + %59 = OpVariable %7 Function + %63 = OpVariable %19 Function + %67 = OpVariable %19 Function + %71 = OpVariable %19 Function + %75 = OpVariable %19 Function + %79 = OpVariable %32 Function + %83 = OpVariable %32 Function + %87 = OpVariable %32 Function + %91 = OpVariable %32 Function + OpStore %8 %9 + OpStore %10 %11 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpCompositeConstruct %12 %15 %16 + OpStore %14 %17 + OpStore %20 %21 + OpStore %22 %23 + %27 = OpLoad %18 %20 + %28 = OpLoad %18 %20 + %29 = OpLoad %18 %22 + %30 = OpCompositeConstruct %24 %27 %28 %29 + OpStore %26 %30 + OpStore %33 %34 + OpStore %35 %36 + %40 = OpLoad %31 %33 + %41 = OpLoad %31 %33 + %42 = OpLoad %31 %35 + %43 = OpLoad %31 %35 + %44 = OpCompositeConstruct %37 %40 %41 %42 %43 + %45 = OpLoad %37 %39 + %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 + OpStore %39 %46 + %48 = OpLoad %6 %8 + %49 = OpLoad %6 %10 + %50 = OpIAdd %6 %48 %49 + OpStore %47 %50 + %52 = OpLoad %6 %8 + %53 = OpLoad %6 %10 + %100 = OpCompositeConstruct %12 %52 %52 + %101 = OpCompositeConstruct %12 %53 %53 + %102 = OpISub %12 %100 %101 + %54 = OpISub %6 %52 %53 + OpStore %51 %54 + %56 = OpLoad %6 %8 + %57 = OpLoad %6 %10 + %103 = OpCompositeConstruct %12 %56 %56 + %104 = OpCompositeConstruct %12 %57 %57 + %105 = OpIMul %12 %103 %104 + %58 = OpIMul %6 %56 %57 + OpStore %55 %58 + %60 = OpLoad %6 %8 + %61 = OpLoad %6 %10 + %62 = OpSDiv %6 %60 %61 + OpStore %59 %62 + %64 = OpLoad %18 %20 + %65 = OpLoad %18 %22 + %106 = OpCompositeConstruct %24 %64 %64 %64 + %107 = OpCompositeConstruct %24 %65 %65 %65 + %108 = OpIAdd %24 %106 %107 + %66 = OpIAdd %18 %64 %65 + OpStore %63 %66 + %68 = OpLoad %18 %20 + %69 = OpLoad %18 %22 + %109 = OpCompositeConstruct %24 %68 %68 %68 + %110 = OpCompositeConstruct %24 %69 %69 %69 + %111 = OpISub %24 %109 %110 + %70 = OpISub %18 %68 %69 + OpStore %67 %70 + %72 = OpLoad %18 %20 + %73 = OpLoad %18 %22 + %112 = OpCompositeConstruct %24 %72 %72 %72 + %113 = OpCompositeConstruct %24 %73 %73 %73 + %114 = OpIMul %24 %112 %113 + %74 = OpIMul %18 %72 %73 + OpStore %71 %74 + %76 = OpLoad %18 %20 + %77 = OpLoad %18 %22 + %78 = OpUDiv %18 %76 %77 + OpStore %75 %78 + %80 = OpLoad %31 %33 + %81 = OpLoad %31 %35 + %115 = OpCompositeConstruct %37 %80 %80 %80 %80 + %116 = OpCompositeConstruct %37 %81 %81 %81 %81 + %117 = OpFAdd %37 %115 %116 + %82 = OpFAdd %31 %80 %81 + OpStore %79 %82 + %84 = OpLoad %31 %33 + %85 = OpLoad %31 %35 + %118 = OpCompositeConstruct %37 %84 %84 %84 %84 + %119 = OpCompositeConstruct %37 %85 %85 %85 %85 + %120 = OpFSub %37 %118 %119 + %86 = OpFSub %31 %84 %85 + OpStore %83 %86 + %88 = OpLoad %31 %33 + %89 = OpLoad %31 %35 + %121 = OpCompositeConstruct %37 %88 %88 %88 %88 + %122 = OpCompositeConstruct %37 %89 %89 %89 %89 + %123 = OpFMul %37 %121 %122 + %90 = OpFMul %31 %88 %89 + OpStore %87 %90 + %92 = OpLoad %31 %33 + %93 = OpLoad %31 %35 + %94 = OpFDiv %31 %92 %93 + OpStore %91 %94 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationWrapVectorSynonym, DivSupportTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %97 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 -5 + %12 = OpTypeVector %6 2 + %13 = OpTypePointer Function %12 + %18 = OpTypeInt 32 0 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 8 + %23 = OpConstant %18 2 + %24 = OpTypeVector %18 3 + %25 = OpTypePointer Function %24 + %31 = OpTypeFloat 32 + %32 = OpTypePointer Function %31 + %34 = OpConstant %31 3.29999995 + %36 = OpConstant %31 1.10000002 + %37 = OpTypeVector %31 4 + %38 = OpTypePointer Function %37 + %96 = OpTypePointer Input %31 + %97 = OpVariable %96 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %33 = OpVariable %32 Function + %35 = OpVariable %32 Function + %39 = OpVariable %38 Function + %47 = OpVariable %7 Function + %51 = OpVariable %7 Function + %55 = OpVariable %7 Function + %59 = OpVariable %7 Function + %63 = OpVariable %19 Function + %67 = OpVariable %19 Function + %71 = OpVariable %19 Function + %75 = OpVariable %19 Function + %79 = OpVariable %32 Function + %83 = OpVariable %32 Function + %87 = OpVariable %32 Function + %91 = OpVariable %32 Function + OpStore %8 %9 + OpStore %10 %11 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpCompositeConstruct %12 %15 %16 + OpStore %14 %17 + OpStore %20 %21 + OpStore %22 %23 + %27 = OpLoad %18 %20 + %28 = OpLoad %18 %20 + %29 = OpLoad %18 %22 + %30 = OpCompositeConstruct %24 %27 %28 %29 + OpStore %26 %30 + OpStore %33 %34 + OpStore %35 %36 + %40 = OpLoad %31 %33 + %41 = OpLoad %31 %33 + %42 = OpLoad %31 %35 + %43 = OpLoad %31 %35 + %44 = OpCompositeConstruct %37 %40 %41 %42 %43 + %45 = OpLoad %37 %39 + %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 + OpStore %39 %46 + %48 = OpLoad %6 %8 + %49 = OpLoad %6 %10 + %50 = OpIAdd %6 %48 %49 + OpStore %47 %50 + %52 = OpLoad %6 %8 + %53 = OpLoad %6 %10 + %54 = OpISub %6 %52 %53 + OpStore %51 %54 + %56 = OpLoad %6 %8 + %57 = OpLoad %6 %10 + %58 = OpIMul %6 %56 %57 + OpStore %55 %58 + %60 = OpLoad %6 %8 + %61 = OpLoad %6 %10 + %100 = OpCompositeConstruct %12 %60 %60 + %101 = OpCompositeConstruct %12 %61 %61 + %62 = OpSDiv %6 %60 %61 + OpStore %59 %62 + %64 = OpLoad %18 %20 + %65 = OpLoad %18 %22 + %66 = OpIAdd %18 %64 %65 + OpStore %63 %66 + %68 = OpLoad %18 %20 + %69 = OpLoad %18 %22 + %70 = OpISub %18 %68 %69 + OpStore %67 %70 + %72 = OpLoad %18 %20 + %73 = OpLoad %18 %22 + %74 = OpIMul %18 %72 %73 + OpStore %71 %74 + %76 = OpLoad %18 %20 + %77 = OpLoad %18 %22 + %102 = OpCompositeConstruct %24 %76 %76 %76 + %103 = OpCompositeConstruct %24 %77 %77 %77 + %78 = OpUDiv %18 %76 %77 + OpStore %75 %78 + %80 = OpLoad %31 %33 + %81 = OpLoad %31 %35 + %82 = OpFAdd %31 %80 %81 + OpStore %79 %82 + %84 = OpLoad %31 %33 + %85 = OpLoad %31 %35 + %86 = OpFSub %31 %84 %85 + OpStore %83 %86 + %88 = OpLoad %31 %33 + %89 = OpLoad %31 %35 + %90 = OpFMul %31 %88 %89 + OpStore %87 %90 + %92 = OpLoad %31 %33 + %93 = OpLoad %31 %35 + %104 = OpCompositeConstruct %37 %92 %92 %92 %92 + %105 = OpCompositeConstruct %37 %93 %93 %93 %93 + %94 = OpFDiv %31 %92 %93 + OpStore %91 %94 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(100, {1}), MakeDataDescriptor(60, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(101, {1}), MakeDataDescriptor(61, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(102, {1}), MakeDataDescriptor(76, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(103, {1}), MakeDataDescriptor(77, {})); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(104, {1}), MakeDataDescriptor(92, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(105, {1}), MakeDataDescriptor(93, {})); + + // Div operations are not currently supported. + { + TransformationWrapVectorSynonym wrap_div_bad1(62, 100, 101, 106, 1); + ASSERT_FALSE( + wrap_div_bad1.IsApplicable(context.get(), transformation_context)); + + TransformationWrapVectorSynonym wrap_div_bad2(78, 102, 103, 106, 1); + ASSERT_FALSE( + wrap_div_bad2.IsApplicable(context.get(), transformation_context)); + + TransformationWrapVectorSynonym wrap_div_bad3(94, 104, 105, 106, 1); + ASSERT_FALSE( + wrap_div_bad3.IsApplicable(context.get(), transformation_context)); + } +} + +TEST(TransformationWrapVectorSynonym, AdditionalWidthSupportTest) { + std::string shader = R"( + OpCapability Shader + OpCapability Int64 + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %97 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 64 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 -5 + %12 = OpTypeVector %6 2 + %13 = OpTypePointer Function %12 + %18 = OpTypeInt 64 0 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 8 + %23 = OpConstant %18 2 + %24 = OpTypeVector %18 3 + %25 = OpTypePointer Function %24 + %31 = OpTypeFloat 64 + %32 = OpTypePointer Function %31 + %34 = OpConstant %31 3.29999995 + %36 = OpConstant %31 1.10000002 + %37 = OpTypeVector %31 4 + %38 = OpTypePointer Function %37 + %96 = OpTypePointer Input %31 + %97 = OpVariable %96 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %33 = OpVariable %32 Function + %35 = OpVariable %32 Function + %39 = OpVariable %38 Function + %47 = OpVariable %7 Function + %51 = OpVariable %7 Function + %55 = OpVariable %7 Function + %59 = OpVariable %7 Function + %63 = OpVariable %19 Function + %67 = OpVariable %19 Function + %71 = OpVariable %19 Function + %75 = OpVariable %19 Function + %79 = OpVariable %32 Function + %83 = OpVariable %32 Function + %87 = OpVariable %32 Function + %91 = OpVariable %32 Function + OpStore %8 %9 + OpStore %10 %11 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpCompositeConstruct %12 %15 %16 + OpStore %14 %17 + OpStore %20 %21 + OpStore %22 %23 + %27 = OpLoad %18 %20 + %28 = OpLoad %18 %20 + %29 = OpLoad %18 %22 + %30 = OpCompositeConstruct %24 %27 %28 %29 + OpStore %26 %30 + OpStore %33 %34 + OpStore %35 %36 + %40 = OpLoad %31 %33 + %41 = OpLoad %31 %33 + %42 = OpLoad %31 %35 + %43 = OpLoad %31 %35 + %44 = OpCompositeConstruct %37 %40 %41 %42 %43 + %45 = OpLoad %37 %39 + %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 + OpStore %39 %46 + %48 = OpLoad %6 %8 + %49 = OpLoad %6 %10 + %100 = OpCompositeConstruct %12 %48 %48 + %101 = OpCompositeConstruct %12 %49 %49 + %50 = OpIAdd %6 %48 %49 + OpStore %47 %50 + %52 = OpLoad %6 %8 + %53 = OpLoad %6 %10 + %54 = OpISub %6 %52 %53 + OpStore %51 %54 + %56 = OpLoad %6 %8 + %57 = OpLoad %6 %10 + %58 = OpIMul %6 %56 %57 + OpStore %55 %58 + %60 = OpLoad %6 %8 + %61 = OpLoad %6 %10 + %62 = OpSDiv %6 %60 %61 + OpStore %59 %62 + %64 = OpLoad %18 %20 + %65 = OpLoad %18 %22 + %66 = OpIAdd %18 %64 %65 + OpStore %63 %66 + %68 = OpLoad %18 %20 + %69 = OpLoad %18 %22 + %103 = OpCompositeConstruct %24 %68 %68 %68 + %104 = OpCompositeConstruct %24 %69 %69 %69 + %70 = OpISub %18 %68 %69 + OpStore %67 %70 + %72 = OpLoad %18 %20 + %73 = OpLoad %18 %22 + %74 = OpIMul %18 %72 %73 + OpStore %71 %74 + %76 = OpLoad %18 %20 + %77 = OpLoad %18 %22 + %78 = OpUDiv %18 %76 %77 + OpStore %75 %78 + %80 = OpLoad %31 %33 + %81 = OpLoad %31 %35 + %82 = OpFAdd %31 %80 %81 + OpStore %79 %82 + %84 = OpLoad %31 %33 + %85 = OpLoad %31 %35 + %86 = OpFSub %31 %84 %85 + OpStore %83 %86 + %88 = OpLoad %31 %33 + %89 = OpLoad %31 %35 + %106 = OpCompositeConstruct %37 %88 %88 %88 %88 + %107 = OpCompositeConstruct %37 %89 %89 %89 %89 + %90 = OpFMul %31 %88 %89 + OpStore %87 %90 + %92 = OpLoad %31 %33 + %93 = OpLoad %31 %35 + %94 = OpFDiv %31 %92 %93 + OpStore %91 %94 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + + // Check context validity. + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + // Vec Type Id | Vector Type | Element Type id | Element Type | + // ------------+----------------+------------------+-----------------+ + // 12 | vec2 | 6 | int64 | + // 24 | vec3 | 18 | uint64 | + // 37 | vec4 | 31 | float64 | + + // Test support for 64-bit signed int. + { + // Assert that the target scalar instruction result id is relevant. + ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50)); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {})); + + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_add_int64(50, 100, 101, 102, 1); + ASSERT_TRUE( + wrap_add_int64.IsApplicable(context.get(), transformation_context)); + // Insert an arithmetic instruction of the same type to add two vectors. + ApplyAndCheckFreshIds(wrap_add_int64, context.get(), + &transformation_context); + + // |instruction_id| and id at |scalar_position of the result vector should + // be synonyms. + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {}))); + } + + // Test support for 64-bit unsigned int. + { + ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(70)); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(103, {2}), MakeDataDescriptor(68, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(104, {2}), MakeDataDescriptor(69, {})); + + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_sub_uint64(70, 103, 104, 105, 2); + ASSERT_TRUE( + wrap_sub_uint64.IsApplicable(context.get(), transformation_context)); + + ApplyAndCheckFreshIds(wrap_sub_uint64, context.get(), + &transformation_context); + + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(105, {2}), MakeDataDescriptor(70, {}))); + } + + // Test support for 64-bit float. + { + ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(90)); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(106, {3}), MakeDataDescriptor(88, {})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(107, {3}), MakeDataDescriptor(89, {})); + + // Good: The following transformation should be applicable. + TransformationWrapVectorSynonym wrap_mul_float64(90, 106, 107, 108, 3); + ASSERT_TRUE( + wrap_mul_float64.IsApplicable(context.get(), transformation_context)); + + ApplyAndCheckFreshIds(wrap_mul_float64, context.get(), + &transformation_context); + + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(108, {3}), MakeDataDescriptor(90, {}))); + } + + std::string after_transformation = R"( + OpCapability Shader + OpCapability Int64 + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %97 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 64 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 -5 + %12 = OpTypeVector %6 2 + %13 = OpTypePointer Function %12 + %18 = OpTypeInt 64 0 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 8 + %23 = OpConstant %18 2 + %24 = OpTypeVector %18 3 + %25 = OpTypePointer Function %24 + %31 = OpTypeFloat 64 + %32 = OpTypePointer Function %31 + %34 = OpConstant %31 3.29999995 + %36 = OpConstant %31 1.10000002 + %37 = OpTypeVector %31 4 + %38 = OpTypePointer Function %37 + %96 = OpTypePointer Input %31 + %97 = OpVariable %96 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %33 = OpVariable %32 Function + %35 = OpVariable %32 Function + %39 = OpVariable %38 Function + %47 = OpVariable %7 Function + %51 = OpVariable %7 Function + %55 = OpVariable %7 Function + %59 = OpVariable %7 Function + %63 = OpVariable %19 Function + %67 = OpVariable %19 Function + %71 = OpVariable %19 Function + %75 = OpVariable %19 Function + %79 = OpVariable %32 Function + %83 = OpVariable %32 Function + %87 = OpVariable %32 Function + %91 = OpVariable %32 Function + OpStore %8 %9 + OpStore %10 %11 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpCompositeConstruct %12 %15 %16 + OpStore %14 %17 + OpStore %20 %21 + OpStore %22 %23 + %27 = OpLoad %18 %20 + %28 = OpLoad %18 %20 + %29 = OpLoad %18 %22 + %30 = OpCompositeConstruct %24 %27 %28 %29 + OpStore %26 %30 + OpStore %33 %34 + OpStore %35 %36 + %40 = OpLoad %31 %33 + %41 = OpLoad %31 %33 + %42 = OpLoad %31 %35 + %43 = OpLoad %31 %35 + %44 = OpCompositeConstruct %37 %40 %41 %42 %43 + %45 = OpLoad %37 %39 + %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 + OpStore %39 %46 + %48 = OpLoad %6 %8 + %49 = OpLoad %6 %10 + %100 = OpCompositeConstruct %12 %48 %48 + %101 = OpCompositeConstruct %12 %49 %49 + %102 = OpIAdd %12 %100 %101 + %50 = OpIAdd %6 %48 %49 + OpStore %47 %50 + %52 = OpLoad %6 %8 + %53 = OpLoad %6 %10 + %54 = OpISub %6 %52 %53 + OpStore %51 %54 + %56 = OpLoad %6 %8 + %57 = OpLoad %6 %10 + %58 = OpIMul %6 %56 %57 + OpStore %55 %58 + %60 = OpLoad %6 %8 + %61 = OpLoad %6 %10 + %62 = OpSDiv %6 %60 %61 + OpStore %59 %62 + %64 = OpLoad %18 %20 + %65 = OpLoad %18 %22 + %66 = OpIAdd %18 %64 %65 + OpStore %63 %66 + %68 = OpLoad %18 %20 + %69 = OpLoad %18 %22 + %103 = OpCompositeConstruct %24 %68 %68 %68 + %104 = OpCompositeConstruct %24 %69 %69 %69 + %105 = OpISub %24 %103 %104 + %70 = OpISub %18 %68 %69 + OpStore %67 %70 + %72 = OpLoad %18 %20 + %73 = OpLoad %18 %22 + %74 = OpIMul %18 %72 %73 + OpStore %71 %74 + %76 = OpLoad %18 %20 + %77 = OpLoad %18 %22 + %78 = OpUDiv %18 %76 %77 + OpStore %75 %78 + %80 = OpLoad %31 %33 + %81 = OpLoad %31 %35 + %82 = OpFAdd %31 %80 %81 + OpStore %79 %82 + %84 = OpLoad %31 %33 + %85 = OpLoad %31 %35 + %86 = OpFSub %31 %84 %85 + OpStore %83 %86 + %88 = OpLoad %31 %33 + %89 = OpLoad %31 %35 + %106 = OpCompositeConstruct %37 %88 %88 %88 %88 + %107 = OpCompositeConstruct %37 %89 %89 %89 %89 + %108 = OpFMul %37 %106 %107 + %90 = OpFMul %31 %88 %89 + OpStore %87 %90 + %92 = OpLoad %31 %33 + %93 = OpLoad %31 %35 + %94 = OpFDiv %31 %92 %93 + OpStore %91 %94 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationWrapVectorSynonym, DifferentVectorSignedness) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 1 + %11 = OpConstant %6 0 + %12 = OpConstantComposite %7 %10 %11 + %14 = OpTypeInt 32 0 + %15 = OpTypeVector %14 2 + %18 = OpConstant %14 3 + %19 = OpConstant %14 0 + %20 = OpConstantComposite %15 %18 %19 + %21 = OpConstantComposite %15 %19 %18 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %100 = OpIAdd %14 %10 %18 + %101 = OpIAdd %6 %10 %18 + %102 = OpIAdd %6 %18 %19 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + + // Check context validity. + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(18, {}), MakeDataDescriptor(20, {0})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(19, {}), MakeDataDescriptor(21, {0})); + + { + TransformationWrapVectorSynonym transformation1(100, 12, 20, 200, 0); + ASSERT_TRUE( + transformation1.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation1, context.get(), + &transformation_context); + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(200, {0}), MakeDataDescriptor(100, {}))); + } + + { + TransformationWrapVectorSynonym transformation2(101, 12, 20, 201, 0); + ASSERT_TRUE( + transformation2.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation2, context.get(), + &transformation_context); + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(201, {0}), MakeDataDescriptor(101, {}))); + } + + { + TransformationWrapVectorSynonym transformation3(102, 20, 21, 202, 0); + ASSERT_TRUE( + transformation3.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation3, context.get(), + &transformation_context); + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(202, {0}), MakeDataDescriptor(102, {}))); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 1 + %11 = OpConstant %6 0 + %12 = OpConstantComposite %7 %10 %11 + %14 = OpTypeInt 32 0 + %15 = OpTypeVector %14 2 + %18 = OpConstant %14 3 + %19 = OpConstant %14 0 + %20 = OpConstantComposite %15 %18 %19 + %21 = OpConstantComposite %15 %19 %18 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %200 = OpIAdd %15 %12 %20 + %100 = OpIAdd %14 %10 %18 + %201 = OpIAdd %7 %12 %20 + %101 = OpIAdd %6 %10 %18 + %202 = OpIAdd %7 %20 %21 + %102 = OpIAdd %6 %18 %19 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationWrapVectorSynonym, SignednessDoesNotMatchResultType) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 1 + %11 = OpConstant %6 0 + %12 = OpConstantComposite %7 %10 %11 + %13 = OpConstantComposite %7 %11 %10 + %14 = OpTypeInt 32 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %100 = OpIAdd %14 %10 %11 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + + // Check context validity. + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0})); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(11, {}), MakeDataDescriptor(13, {0})); + + ASSERT_FALSE(TransformationWrapVectorSynonym(100, 12, 13, 200, 0) + .IsApplicable(context.get(), transformation_context)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzzers/BUILD.gn b/third_party/spirv-tools/test/fuzzers/BUILD.gn index ec09b2b067..2aef4e8f22 100644 --- a/third_party/spirv-tools/test/fuzzers/BUILD.gn +++ b/third_party/spirv-tools/test/fuzzers/BUILD.gn @@ -48,6 +48,7 @@ template("spvtools_fuzzer") { source_set(target_name) { testonly = true sources = invoker.sources + sources += [ "random_generator.cpp" ] deps = [ "../..:spvtools", "../..:spvtools_opt", diff --git a/third_party/spirv-tools/test/fuzzers/CMakeLists.txt b/third_party/spirv-tools/test/fuzzers/CMakeLists.txt new file mode 100644 index 0000000000..50c458957e --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (c) 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +function(add_spvtools_libfuzzer_target) + set(one_value_args TARGET) + set(multi_value_args SRCS LIBS) + cmake_parse_arguments( + ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN}) + + add_executable(${ARG_TARGET} ${ARG_SRCS}) + spvtools_default_compile_options(${ARG_TARGET}) + target_link_libraries(${ARG_TARGET} PRIVATE ${ARG_LIBS}) + target_include_directories(${ARG_TARGET} PRIVATE + ${spirv-tools_SOURCE_DIR} + ${spirv-tools_BINARY_DIR} + ) + set_property(TARGET ${ARG_TARGET} PROPERTY FOLDER "SPIRV-Tools libFuzzer targets") + if(NOT ${SPIRV_LIB_FUZZING_ENGINE_LINK_OPTIONS} STREQUAL "") + # This is set when the fuzzers are being built by OSS-Fuzz. In this case the + # variable provides the necessary linker flags, and OSS-Fuzz will take care + # of passing suitable compiler flags. + target_link_options(${ARG_TARGET} PRIVATE ${SPIRV_LIB_FUZZING_ENGINE_LINK_OPTIONS}) + else() + # When the fuzzers are being built outside of OSS-Fuzz, standard libFuzzer + # arguments to enable fuzzing are used. + target_compile_options(${ARG_TARGET} PRIVATE "-fsanitize=fuzzer") + target_link_options(${ARG_TARGET} PRIVATE "-fsanitize=fuzzer") + endif() +endfunction() + +if (${SPIRV_BUILD_LIBFUZZER_TARGETS}) + if(NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + message(FATAL_ERROR "The libFuzzer targets are only supported with the Clang compiler. Compiler '${CMAKE_CXX_COMPILER_ID}' is not supported!") + endif() + add_spvtools_libfuzzer_target(TARGET spvtools_as_fuzzer SRCS spvtools_as_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_libfuzzer_target(TARGET spvtools_binary_parser_fuzzer SRCS spvtools_binary_parser_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_libfuzzer_target(TARGET spvtools_dis_fuzzer SRCS spvtools_dis_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_libfuzzer_target(TARGET spvtools_opt_legalization_fuzzer SRCS spvtools_opt_legalization_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_libfuzzer_target(TARGET spvtools_opt_performance_fuzzer SRCS spvtools_opt_performance_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_libfuzzer_target(TARGET spvtools_opt_size_fuzzer SRCS spvtools_opt_size_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_libfuzzer_target(TARGET spvtools_val_fuzzer SRCS spvtools_val_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + if (${SPIRV_BUILD_FUZZER}) + add_spvtools_libfuzzer_target(TARGET spvtools_fuzz_fuzzer SRCS spvtools_fuzz_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-fuzz ${SPIRV_TOOLS_FULL_VISIBILITY}) + endif() +endif() diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_000.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_000.spv new file mode 100644 index 0000000000000000000000000000000000000000..c203cec416b12f15eeafbb8dfb4002356c5a707e GIT binary patch literal 7968 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_003.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_003.spv new file mode 100644 index 0000000000000000000000000000000000000000..c0e0a298b2dcda5e3b2b9846712745244bce77c2 GIT binary patch literal 13336 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 S-q-m&`@X-8JAI8v literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_004.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_004.spv new file mode 100644 index 0000000000000000000000000000000000000000..f1afc72502a33bdf4bd20ce4b46f6bd5c73efed7 GIT binary patch literal 12368 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_005.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_005.spv new file mode 100644 index 0000000000000000000000000000000000000000..c6bf437de82336ad150fd0083e5ff8c0de9cf035 GIT binary patch literal 2416 zcmZ9N*G?5t6ov7qOwDSg;-oR_u-HF(edYi(Z&ujENUs_!ho|kr&X% zu_h*d-9diJ z&b>QTEJ_Mhp_;{LX0g{|wfg1{J+D-27qfbVlE;%{ zuO=qPM+e8uD`4p|rwAlxmyse}^j)J9qt8g_fB9l??D@l|)jVf#&8~V$(qHa9-9J1z zHu)q;&JeS|t1aDAf-}96Ayw+f@da~xS zw-TMlE?x?IwR zy#A7^m)2hjwwC?n-Irmkp3v9hM1Av@W9F=3V$UUJU6I9&Ijg>Bqc&=<1iQj-0Kabe zxN$kE#$3EfQ8HDX!I@TJl}cqg@|y9#ef==)`K<=4@r*pP7Ix3lxO0SWEb`O)nL66e zgzDB}#+*+R2Up6)g4@S?;$8Y|F7NgiUMu@CPQ`Owhxz>8hi876S)8*ClMCH?aOgbi z&}{(Ag>GX`=N*J@6Ikvy{Wr5ahx>P`+HVV{#@V)F+pysD?IYKYAib>UD#y zDHrt)fummj4i6KTi`*k%^Nq*sN5L_>&z_&X2jAJ%#7xJ)&ZIW#9tZbeauGWLHg2yt zzYMm&+URu#tX3{!XTiqv{mZ3 z-x2jO`vtICxtRSTIA&L$pZyZPytPAr860}!dHof9dFw>at6=NMz0dBy59};*G4D07 zar;H?b+FGQ7r8gU#_bWgH^IxW^iI;>+%0_PEMn%w{I|2X@40dFqRt&~6XqNdy9+jM z?U?Hx*gA6Y8@~^>pWjRQ$bSHK7Wuf>ez3je;<*OEK8IZN@!R4%I)LTBVSW!jbC!+l zgP0nhC%!8~S*)4;Q>GgRtCjo7{{kcIF26H!53vg7cSd{!O@ZC#vA23THNll;aBBW? H3SHPg<7|(* literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_006.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_006.spv new file mode 100644 index 0000000000000000000000000000000000000000..d0d4a70056169dafa873e43f1bc8e5c54a68840c GIT binary patch literal 2728 zcmZvdX;V~J5QdKoAkjozK@-#gT#~3HDi9Jy!38uyMak-hBb$T3B*PHDT2}dk{FcgZ z(4UjUq$*WD&z;-WEz3)_{r21I>2ttROaJDSHl+@JeoxJBM{0pdX=`fF^yJjc)WCXU zeqeCuOCz?WQWj`TXWE=v(JjborMjj=uiSQ!JPkmltkxJwZFr0EZS*l`X=QezURk8gJM&|fV!oXFG2eNL`P%0D>37BhnU&HmvbKPGnZX&wUEmMV%~*SNq05N1?WNs~_?f>KZLIafzYpyBW44cTyNCEsz{bj%--C81^3LY| zW48TZYs)#Cws#;Gz1)9swu5<0^e$uj*{c`r9%HZC?p!YF^?}`mwsSV$#?$j*AA;k1 zYahmV_44KDFj=12+5CJ1ud$AxojuO!S^tGUn)}s%u>tq`DdKL;`3(6Sc|l#@$uUH~ zyZxJb$I<%z{=?R)&Dx_E!yW4sODnfDUE5AiO2N9OpJokblvL*RH%#`wEpjBh;d^B1u9 zSw>>!+hF;)&pY6_&oVgT?t=Bjecl7h74P#tw)OP6$62(Wd(`&;sUXfJj<@&_>|68= zMZY<)eDs?K%N<4{Zvkvx9};f0?QTi9$}kz5Q)4hSU&QW!E)wJ6Wxh^j5voi z_4gy*Z!21#d-u$q&vV9{E8utMT!oX5ersU4;+!??cjx>SPCoK}1Ircj>e%KL_qmQO eA9)S1T=9Gx*v?^1{l)X?E1u7D{?GrcBgh-k+roMP literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_007.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_007.spv new file mode 100644 index 0000000000000000000000000000000000000000..7f2f982d28bd2d46acd471e17f245a6d1034ca26 GIT binary patch literal 2668 zcmZ9NX;W245QYaX_euip5{z3e?gS-^`;IYkT}V)I-w;I*gIo*syGvQ+U&*IbDqs9# zNhPUDRi5XZY3h_?y>$26Jw4q$bC0#oZOc;XNZtHrH6<^9MRtLz6U zy*?Ft*JC-Sb)5Gl(la(7o4{q9_D0|gH(_r=noBP7ZboN~L|*3+H5&VsURL;<=;rGu z-vH7W-;K7j)^@H<{(3Lwl0TMh-;~@IdiJi&VeEFKdE|`M_WtDb@5s9Gp0yL{S>}sg zccHtC-;L}5#)N+`bNatVcW>0DZQa#;L)kWdPu9(+y%*{Gb*AQ*9|r9;?~Wd%3-8_9 zUA}|AvA#jtn|uB7xIgUgvi%Qn-=iC^{F5ki?*qO8bL+T<-ZRxtv)4Cx7+9D4Pcj*8>v)5|4{06RzMB%X_AJ^mYo} zJ8-|fXev4xkTT+bo(yPT_j zZF%cbkGY;lcdqU~L9FlO0+5fGi|EE!U&M@|%YV$X`3c>9^1t#W@NL(3*PmK3`7sw5RUOJGw2Rx@6=wF~8@A5v-7qg#4_gf<$ z`5&OmM-5Zx)-VVn<{`R#)bI#hu3E!1cGRFhYIuyUFKU=U_l?L${#kVS%eluV=rP~u zaSqP>_ND(4y*tmR-~lj)F>lBr{|j)|`pqFX56s~k*YEkhn`fX4jPq;NUdWvB@^#Pv a&c$~rXN*1VLAHV15YVsP5B}q{!{C3NkE785 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_008.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_008.spv new file mode 100644 index 0000000000000000000000000000000000000000..c67dc976186d3ac457a0a9bc3bbbf160699af974 GIT binary patch literal 22972 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 R`F(pgQSUZ5>WO_1{{v*m;Wz*Q literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_011.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_011.spv new file mode 100644 index 0000000000000000000000000000000000000000..882bfe6bf0d118c0902b5f7045e354e11facefd8 GIT binary patch literal 5440 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_013.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_013.spv new file mode 100644 index 0000000000000000000000000000000000000000..d7e35b4b0040bb8be1a9c4f9f440a9062b350b09 GIT binary patch literal 2860 zcmZvd=~9$e5Qaa&0ha_++>)RU8h6DNLNqR@0X4WUSzHhVkz{0&0gU;RvQk=lGyd=* zEU(D5%Bnoi%xUWs#i6>o`|b7g*Jo&M+SFPU3yMYj{Zll~@}dc(D3%s2bv`(BWvF|4 zW~}>Q&t5&+isrhbKJ7(ou@K$_Js6ps(x6pr8Im{!kechcjuTYEn){ciW6VTlc%U{i zak5&ijiJ{4O7PLyd-b|4_^EqpxQJ z>K#e9-!l42xOv16C*9eItxq#BhrX-e=5a3isyi1k?W>clzkOME4aDh>KG&icANp6w z&LH%!k)2oQ-ypjXp?4yC_t4iNdw1(Qe|wL+sC!Q_{hjXyNdHdsGF)FV?e^ORc|zY< z*B&3+#TM!7e&`dVJ$%1K=6v?uj3So%MxHGR54(B7wl&4gXWN$L)1Jp|PjS|pYul0H z#OK;}CTu?2E^OAA?+&{Y9`?MK?i4qlZO@#1d7O_ukI8NOvU=jVZGX}OZ`eADGWY?= z@8BC z5o`PrbYs4Q+|3JQ_09ApOx&{o>L;)7>U+qy=I?>=`X7SCpW~x`7&3?WB{28-2T0uW zG+{@O#eJJo$q$=~oD z^cjNm^V^++&O_R~-v!86Z5JVJFUj2ozXWObH|s5Py$sjx`G~Il3M6h#W#?_)tB`d) zFH*j1$l}&}$EI9|d(5TnXGqLk%8~0AWOMoL{!96PMHX*|F0)DA^EXI5e4R(+lgB)6 zBp>@VCa-l9UArgda0^*H`o67^W8d0_Au;<_j=t|8o6ElA8;&5~f%3jb(Z$2pz9XMJ z`o5cdyo)h;tub`%)_Rs^G>$Cp|A*-59qG*dm-#?M{H~ufE2E|>bk+pkbuV;|OJ0ai6EZi86_tCB{ZY|~5Yj~^vm|AolvpV*K-=zlc^x`zM& literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_014.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_014.spv new file mode 100644 index 0000000000000000000000000000000000000000..abf5488963cde99ed26e5c56dab7c2c9e9406b10 GIT binary patch literal 1772 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 D(b&?P literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_016.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_016.spv new file mode 100644 index 0000000000000000000000000000000000000000..a7cef28a15eb74ab11e3318aac5f17fbc1edc379 GIT binary patch literal 4044 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_018.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_018.spv new file mode 100644 index 0000000000000000000000000000000000000000..c7bf440c2e2c42ed990850ab59aab9a8b17e737f GIT binary patch literal 16524 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

cdb*Cmf(sdt~jU28!O*Xg& zZN8`I)3wP(U9e-HkPkgue^QuSp3@of?Ij&QZ1^#!TZzZ!dz~p<6wkfdXKQir^=VGG z5r)fR#eFB=S<;Isj=Mm|kF#=a`bE0Gr{qh2o~x&Y;XGH^;E4BKa&C0qk9I(7WJkL0^Rm@wyY6nX!MQH_?%L#{F4(az$d8__zbH&D&*>iW?IRsOZ1^#! zdy2>Ad)-U8D4u(@&)(wTJ*WE!!x8JaeT9oDj=Mm|kF#=a`bE0Gm*h)-o~xII;Y!-R zOE}_vmz*1&_ah(D`CgGP=XbtWh2fkJ8yxYT3Et2B?b^+VJ!M<*RBroRcKs?Ej81+?~q#vE*vihU0$i^R6&H z{;k!?2d=5^<>nN3usC9|eXTl&NV51h1KS$ywc5-g*ty@654k;C>triRhsTHC-Fk8G z^E3mWOWz<2=RIFN;CHAvY%Ft!B~Gnw;to$7uJiQ&Dfv?J2r0zlkG;79xUVM3#&3Z$ U(Ld*~t%dxe4WA$M!nkuDk2@t{ZN5 zce~xa=H~Br=f3zob9s*EJ@uXQz32Wf54Ln4y+u`Zt9tS0$!=BsY*lr~Q&oMcp0%Dc zZ^68=Yt}9uJ8{xD6Z%&zb)Go`sx7Kkba!Ocq8051jOrT*(oX|WOMTW1ih2+&^Lr5M zLC&i2~gxRV|z|Z}!3^9Vv%%$j=U}%W_FjoLSKHpJ(E2nT(rK-ejeD_a~_}C`n=eF+|7@@7HodbTL-p(?DN6qYs>cq=r+X1`Lr)Y{QGDG z_C;vt)7OT5Fa0iLYmG4Jvx%B;t?K?WKv0r1(yTQ(@ zeu=C_=qboz#5)W|?m?d8l%?o<5#vjcm$}bh$q@XCHG0 zArB(y^AOm0`aImkQFR~V=IghQcqTKhKtF+*N_7$Ps;#Xi$` zQ}sQHtS2H5&ScDQT6qV1YI|>ct5YLio|&5PD<9T8jhw7UY#(#B zL0&+@_s7A;v)506UqF21+xQEJe*1{S_b0(!`Ti6>{o(u5;NFOLv5$P~GcVjZld*7@ zJJ{1ZJ&(4xIyLg;nW+iC@?p(q(AKEK!*sAbm@@+TED|0*2R0tQKi|YrH4nzWfav#J zv3bzo`-sE$SHWHR{u)00;rr|0K8Sa* zk9_MhFWfnkv2d3=*wZ`7i@nvUkuT3oP56}$YrcWDMjakzfaSrQk;pfZ@bE403?w{! z8*JRi_s;lt5dEGjw$FDPTb({9f$d|?_Q>~;^!Yy6cst_v1F?^M>oYIhIg_z)mpj4lYnmDTF!T6sM{hlkf&tDo_ojxak?PJa; zCkr9XUk!ybU` zUF;*@`pgS=&SWgyEI^UGj>5*iG`;gVB<>=_t6vExR3iVz6GM+bH(=Q)!6FvIgT1mgw~94K|)W zeXx!D*vGiGe*1{Sbzg7~@|@E%@^7Mk_>INx50;B7$zDd@0I)vu!jrym?Tnrmu5%}6 z@Q(7}Eb7$ApL3)pe9KSf7zlQb4b2=|f%R>oE_3M1KDRdBoM~J;`y2#z26cEogj{*H z=Wgi1=eR@e zbEGDG%TMNL13O3dISQ;V`!uF6``i)iKHY(HYG$i_M``i<} zC3(*28R2a&{KjIB1AP-RJNujfb_R8LoioNT8jjc|fW2mu@Ib+cKqtoXAu<^V%Q?QNu*vGiGe*1{C&jZ1|$#YK62yavI z8;d;+EEn15bg(}2!jr!2#u+^?yUCrL!8^)>v#3)ef6kGb@GU=?V+Pncvd@`dec7im zec9(hVE5^}?ws1$=Pa-@sKfJI^5of`W6=kr!}B3v|@Se=tI%za~Rlo`W%jJ+{Zq~we{OaoPEv%_aV{MA5#CneHx|1cEEm~l2UwqZ;YnY1xGT2PM;&Gv5z?u&=;Z8=VGw&djjc|fBdD>DIg`-WqtoXGu<`V{5!<+reT-}Cw~sjcya_yj zJm>U`@OCqPW3g`m%SHBiD_Ea-;YnY1nUHFZq*WKXSN8ZNf-@o_Z z^E_kiaJ`7wzKH(Ja4*;yHXxbdK79If&i!D0igb$;Ad}oY3f;@`2CvkowkAeM-*dzCO9H0LA o{NJSx{7-=OMKPdk z#w4bjMAH+~V|wq2Ez#tC|No92?voqmIp2I!&N(x4@4uR=&ZE0!S*NT!|9h-cR(|?t zonf-9XV$g6E?%~J*~GT?jT5I#Jxqr_SykCjpT1eQteUkm(o||})}U3cA4r}JKvm^j zwFGs+n)-Kv>4MM3miaBsI~rQs$LiCa-LtH|rD@yt_J;W_TU%PkZaRF%j!lzhKx3~e z=dCYey|ZjvOIu@mV@vrAU5MTbZezoy()O+GmH4u6_pFC}Yw4`jTT0s+#+tDrlgVt} zo|RnS>Z}*I?ab|^)`rTtd#g9Jw>LI##@>xuynV)%Esf3XW1BWj@`Uc+7h7vfd&x5` zFSWNe?yThK2jAY%w2h^_Uw_sObsNff0JyEr+*R2?@Rqt(aCJ6FpY5B<_3sL!?$h4b z#K|go1`BwM9l~0Fcm)p?PpaTy;>i^}Ts)TLf#^r~#MzDHJk$LwLN&JHN(2cnnSwl&nZSNsn` zr#{>`qw-xdb)VLTwwA5iD^p=z7_IW-#2pMO&Wy9Wd28LG*3#zrEiJ7Zb+!iMSnC^_ z+Z$Rd`gnA5Gg|6Z*#z{)vTs#(2&;j{O=L}Ld1yhmp{d;ql$tkhwW-b!ZTr77L<>1P z16S^Gbw(SLJY6$dS%{ldJ`ZiH#FgivI-@mv#8Li2+~jiH^oT3ZPIY$F9&y!~FJ)8X z&W6gpy?K_^Enc>$uHH8{%a)L35S)*F_E}8bkN)HnPt1<^6UzFyITMKTY$qbd=%+3G)_}9DwstV*ItesN zl}Ee!$z|;weJy&Y#J&z}T_WEpV4gW6skQU#U9HKftoq4$Cv|69&b?1#9fd@0^*Y4I z`1P#%nr{%O#2RGCNPJ_`TestiZQ3Nc0;_U=W{&+8J+9q--_TpH_q>GPL}Pe z4ZRty$4jGUhTc-PKR++>`6KEX!hRlXR^MyI;p z=+O1|+Z?+2{WgcL-EXt{T<)@-bqC^HI(xG?vwb)Vk?+O3q`nieuDua$ml7*~Hlocs z&!$4&T`uyR1D1UW{H=^q&?;g&lT=?Gvmeb~Js>k_m275kv?as2CvDWSu#CnB(E7&{q;xB&f zw;}d*BBHPMHpE=cz4nN`9V{369bos1T)V-MOJD72F6|L}C)ix8=#lTmU5K1daCd{{ z%o*H0Ip_CeC2!?s)_W1-_1C@%@%+`S+TJ9?kw|=ty1@Cwx9C2w-wNOLeu(e7=k#3n zBmEQo0q_9i;{4nXg56I(-tmXP_aoXO&%@v}&m#r>QS>zLW9a6UkGzkAjnfwUzYA<` zZL!xA;DN}>{CE9Huw00-_Ws?7wiA)-a_&7je;ljdApPEp*aPdSJ@P&UUXw`VeIJ}L z+9SvN!I49Iu*2Q!~a>Z{%eu&{{&cGe`i5G z{67iSe;pG3p90J4-=9@IoppQH74bP5nTDTdb-u-mS-T_t9zVw#c|Q%-Cw_xI1GbJm z5N&ZE`8ca}_pIw#KZ^`T>X69!xtx!jpGP-mZ$w+n_!q$1PC+`zw}ADFhSGP$-$LZPqd02t zUvShwtX;o2r!T)XSc}Aa+X+rSd^&@RHK>AgQG@Paxv0Tj=yKMe2dj@Yknf4ec}H>7pcgo5Al9y5oU=E$Sc5)r^5N50oxReT z?guB|k z9mP?D;ozu&Si634&Jp0^yRbK$eE94GF4kaQIQj4ynfs(Y-w#ecW@QxEIQige!0x9l za_tW;zC)wo+CA3d4_mWv+w8!Q(+ss%@n z{5@8W9?b>YBV)ALBRS9EdEy-Nz~)G6J0DIyd=`L6IQi(&60mXd z!5s~DKW&lg7;y0$v=mN0-lJt;W99A9DDEH^Jz5Tyiyj?|E@zKcu=>~|`IU&AwGqcT zR)LE>Iu1@gdbAoW7d@&WuUz!#cyRQ{zk$@FM<;;oQ4ONa9?5wQ&lBf35nSxi8aVmz zISE|s(aCV~;j=dPNqe*oPCoi^3fMULj{H4373_Z6BG+l)Vvp+Jnfb9{D$) zT=b{}mWv*3K$o*e^{hVjNPZ(CXKloBjs|eCN1Nc}qeq*;a?ztP< zdejKEN5*KgM{=IS^ThAf>EQUi5~qLr_aV+_1u~7h9n0DmF~=GB`Zv9Q^B#zFLqb2e zppQ%RrQq?2emZzUqH8}S(ak@xpdXs(`X83-)^-zkD`y+aT8Bifn&9N;QkC`a&52L? zw?+%Rw(#4Q_@(oACcL&@+af$n$g;KolPB{74?`*I+Z~l=U*iNBiZu-PLoP20s%q$5WiU#CiobIp@pwT>VPK zT;>+Xov#9W=EyY*Y_1mKoSUo5zVE#A*PzR7#b$rkvtElnm^J3vxa;8LJMdAz9&D_9 z{CAEU!2DDG&S;PC%8g)cP1s^aZ$g*%zfG9adAJ$f^J|Oq&xTLWe+xFb$bBoiTnk*B z<2H2uDW5}oocVTeGrac5KLWo!1kQNnD~9StFWu{_nH1P)UCQVS3OW4LRDzs_bilGTd2kpLSv}QWN~3-VdUNR`pD?m z6&cMTml5T(g!)i}tOjq^UcWV9R9`Eaej1?VvRVa_YKd0zYw2Uo#^&n$*4oBgskF6@ z2~TDStHp)+)t9Bs(w4p)2x0rxPAC#JuMxBWZTTmGs~EXuy(Y^$okhxA>+~PkIi@JD z4yJSFe)1cT>fPvvka^HUm%~VH_c4U6?i_pjU#64Ygk5Uio9u*jq=MIs?&>1Xx$_z< z^R!zt>wn!g?C;AvGpTMn_KVN62Youq{DXLBX7A1nvt#G%0&;}2cO#wGXO-u_2U!L5 zPet43sxS3CiXOu5RI+=^_MG|0(B-FmZENf6rBff$e%7m8$?k)BoPa#*orolT&ZF&F zxze6IV`mcML_H(V!sVI$!a9Y#O}=yGf%7cF^qKU7d;}t!?NfYS-Vx*0-iy8gbp1Zd zCT@!RIRmP|EHM6)4rh_BKj@z0Ip8eHuhjA$oCoH5Kg_v+bp2*lV}n4SdFuN}>uT$_ zzk9d{?C-O-|1$NRYY3!R@(o8HB7BQ;Ttb&?%sEDoF6S_I8Ti86SN&tGe-+&vbDhmR zIdT){T8zu9*B==$|}F4hm~#;U;?J{wJ|r?%&uH(C6ONQ_oxI9l)CIEpe1-Z?|LI{mM5#oy9b|=jBSX%%JOU z2A)L$>2elhcR&F+i+Y;HyXX6EKW8Z*WA;yp^U+(Xx&W|>EK zIg7C(&}Sd@_xL@F`@mk#k>biU$AcIzAmy4XH{ESz;yy&T{~$2WI!m0n_x=&^{gIR2 z*@fu$yOiFK$LQ{>0T}mwnEwPA^Bdy#!S75Rs0GjY_j|DzeR9*YT8e(efp0nb?2~v; eqpupd#9g=EN~X&R!MJBO%{lw-8vDzn6W|}sdw*yE literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_022.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_022.spv new file mode 100644 index 0000000000000000000000000000000000000000..cd9ab76b4d3eb64f52b36d028696e3401bc2f3f4 GIT binary patch literal 9436 zcmZA62h?3v5e49v1OgZcASE<0fIl^ajs>YI5sgX{#D;+ch*CpTEJ#3_ioN$%B2S$w66^dC-Y|a*|TZ(tQS2ua?Xm?=L(2!mOuHDJZRo*o+I+X z`q@3+yMAK6Kk9@NlS%Y{YvqcyE1>y9erKJ%>WsC=oV#+>MI*mlYgV6mRs%AuAK%(F zt5!t?J7F?8b=mTxPd)v-v(H;InJmj5z8!7I+9DOrkKQR>^}<_a&xX;9BhKD&sEx0( zID0mV?HhHoZ!y^R>^0@nb7gWd6N(fXq2a}v{&-6KneS=}R8?{O#f?-`8$w12Po+(rHE z*OK^f?)Q5KyQArSOXJhK?%OBW-F0969#P z?BGnB`7q0tp8X@%LDBA2AI&5GkwIql;KAq392WL${rr3IZKJIlgWc2ZBJ$DyjK2L~ z(>Elmd$~hIE_)7%+%a-p&T_YhM#Q~=zonkTqQ$L$#TGw2!tWgT$T0Hej)=xBSOMTk?zD zEpqpW{B-jy50*#Ya2B^$&-wMFcXE$lweX3v&9ZOX8|U7f*B}p0<#Es8^6-7nzgMtW zc^n(eS02X&TX={aA2}f+Kixbh2Fo+%VXr#*$2{&Gd(4A9&BM9n;jW7Hs551boU4xI z5q%xcpPt;1X*OdgMP?#qa@UC3XuWn{Cr4X&+H1!7@TBGCW7EF5Pqfu{a7wT^ZU21- zn{Lhb3-%7|xqsvVkP(p<=c+>=^>sXddeV3B@ZgzjCt6rPW~~E zXU87%U{CXKZh2fW!g|!1GDpr;hd%1-c>dPK?mKu+@Jz%^nt!#?*F?<2bE7Rh?KR_k zc+&Fnv1#8tFWTxmcz&=rZT|}fn{Lf74E7G}c~RuWk{K__n=qZs!N5@_0*d zd2Afq^WPdQRvy;{^KBB*r?*90c!<3{@{Wi)>E?N7usmZP_NtSA%;R0L$2{26Je*q| z?y6XiI#cGzx$4kIeI3uAp7b5OJ9s8yCe6RvXuZbsJ<%4P_L^}%JZX9P*tBon8*TL+ zyf0Xsw*UQuO}FL`1bYYed@yo-q%-=VVDT*@-ob~Xua8*j68}hq-#Kva_oKmj+Wftj zkHsg}Gd>=?O@tqZPefbti+wWksfhe^^M5+H`4Xshqwd%@zg{ofyKx;6hG z*gLT2hmjveI-@@h7T-4F9sDF(+)|hLPb2)!fqTC{3)a)-@4fsyKCzzhi(qrikHasc zE&0WM75Q~Ue!BU86Wsj1Z~or~i*k?l-!tWfo_d8$A#^?o6y_XGQi}j2RgWUx`4jV;Vc#GX4vLGTq-TWH| zH~;t@Y!bg%=VxIsU*~7j;N}GIevSe`Ktd)3K5=COV3 zF%R}M59gMLyDHYB&XhTFt~&HlU&r&OCw&Jy1kZ$rnKb`uqxIT6+$!3_(_S;qhbJvB zADi~gj>9*72e%&f)AlbOY`Qh?6l_lI**UUHq%(S(VDW7d_YP);c+A_K(OW!Y9r?AlSFDGKyuyfzEmj`)3Fa%0Q-Uph61#8Y zei3!j<#GRDdB!~KRVV+L#{*)Id9bH>IJZ39Rk0p*rp%FZ)uE62I-Wm0={tB}@Jx7^ zN%OBZTCdH+snHgm_L^}%JZX9P*fje=gH5-l6~VhFk3FYFP9Mcq273cytEOUSjACaF zvA3j4n`Zx6vBh@?_C8h*@tCvqia$8QuRa*3heTU_r)LjwTK(q?Hr@Kq4OXK)=S9ws zyl$xDf?#p8p^h~}+!^{Neqn@P9dKuNZLmA{y_s1r_@Tl4$0f31?1u&OS@k`9@Nw67 z(cqgKU+4A_@%dh#aDQa9r7p2YMflVO$6>$qmv<2?I)KdwVP-RrH}?|b#*W3S%^XVX2~+t;`Dz;BB^tE0>7iNWggd*F_r p6l~!o_T&loCO(aCNg7jKD!(a@?C!0PjE&zm zqBY5-fyT5YO-Tc~9(ljIwXH+1TsxLL6JX`iT5}}j@n+-m%wx`GWo2<^b#tLw-B|~w zae4IG{=0PEM&iVdosHdUWq)t0%8Yrk8*4PS)stkUR9;+pTdh=g^ykwawzk(dKCG@) zHt?5-a?Tc{4OvQ~Fc^b1MNAI1wl?FPW8lzN!^I4C-u{3)Sz$AFks2q^+CA7O(FLTJ zdd@9&FT|$;woUjt~V0%Gn^!0p%$^E=SS zTF>}1DbF9nc>C;3QDHvjcY)<2?#A}ux~SBX;d`-NQ;a){{ey)>d=6}1_HiEV8r=)m zAvRaec>B75*n1zi4{fZRe*3wII3li{$-(R}x4_s-h%r(0$Jhck<1n@eC?MI`SZ5&c z(QlpT8^o4Z%+2~P2Ts0l#CIid$N8?}i~P~NYavhmsP8(Q^P8(=d%2O}j{0tf*qEEm z8wzP}0^+&_HTiCR7Y^U?Z_quocQfXiKMgi#4DqfmQ`NUL z9yobN9WqZ{-`fP@8?_hnjlYk`eTEF8jSie}_IkjW2&#?X8IQPfU>vL?sIdU=X1-7yJ zzJxe?ls7i6)86dGZ&Y@j&iyUqm9eeuy_(_ly$_>^=j?rYiO3lj@5!sc8{dE}{>RBo GBL4wO5Mq=7 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_024.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_024.spv new file mode 100644 index 0000000000000000000000000000000000000000..503627f62141f71c5ee51b523fd39b3150d51484 GIT binary patch literal 9256 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_025.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_025.spv new file mode 100644 index 0000000000000000000000000000000000000000..c4e0aa359f1f5344cabd3673b23d8236581130b6 GIT binary patch literal 7960 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 Gu>S*~z@Od# literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_026.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_026.spv new file mode 100644 index 0000000000000000000000000000000000000000..c5b3cedd33b9fc5f5b160c17432a9fc01c6e2e1e GIT binary patch literal 9680 zcmZ9Q2Y^<^6@?$LOA!!|W>|zqr zj4i#H-V@V%Ppnb%eeZu4hBxl@o^$SX45$n@-h4 z)BI{;)#S`wxr&O_IfiEIYFldc9dp%LW?4hs`j*9;*VUb$=#JG?zhPqpsPTiUp;Zdh|mQ|sE6QPdb!KeqBWc6$BT>Et;d=h#9nF6W)`QNNney1?rJF z`TgMgDz`P&H8(c2w$wLrGk8v?ROB2_1^XVm@6+(R*U%yJy}Y1^9Z`zSfH${p%KOa( z?|zS}vRQCywl?JNRaG_{o{l>Q?xo`S^p0A+aLIzz#Q{{Ao8&KodoM)`?mc7+?)_t1 z$ojlDY+~;Qo7g+SCiXtCiM!w28eNY~uG-V2&?J z@WlzfB*B*^cuRt}Cit>lxQYsXm-yY``&Yf|o*A+$r$es!PA=sAoq`{{D^}s@o_Lqo zoV$04O?-I;=GZ&MrhY{Q=J?74UzOmi6MRjAuTAiE3BEqTHzfGR1mBe4n|I-={0*-LCt6JQG7>CeR{!r7n<=0 z3LMY!!Gb$R%;O=jXV(0O@jeIFYTPyMz_M)1tl*F2ylr;yM{~Y=yvN|~yK(3LcoKKK zCvyJEuKrKv{P}!*=lK-oT^8d%oyWK2`Nnr*t~uh*1B zA64R`OZ@N>A5-FEOMG03k1z2FB|b6Xo|{Pt_gCu9)V`)&^BGk8}n?+#hy#=jF{io zz+EtNj79&mz-he(xLR6IE%G-N`PT5P%f&tO4dV=VgnZI#w*gsY|X)FS`v zBHtRmJ96=G{6kpO`v%y0<`|3q=YZ3CO>nieo?7HL7x~s00hWtL;=N;|-Z#P4Gsjr; zZvm(ETH$JGJ+;U`x5&4K@3vg*d+i+_^zQLL`d-jyZmex~?{ELcwYm5QQ#ojwRv8eZLu=UI_7X2>uj&k?WxISv#2=@8M zT5kfYMJ;1$_J0*`fA`V;p4q=*p3~re1AES5{F`%}@!$59{J+E1t}M>{Kfv};-&$z@ z1Us%V|L?bT{)M%}dSJ$V4s-D8QTyLuHDhz}a?jE|`2S#gW9lo4I{z(n+%E04LbF!n zyqaoQS^-HXeH?zdwopuZXwd?JqZ8o@*C0+Z~v5wf0^K?h1CU@8ILx zeIKy3fR0V4wz#*mN@z@Ky$sp7lIvo4(IX#d=$s68MD4P##u~GTCWQ+>#4iXk#`i>*p6b2dx6#5U+Z;++pK4-8`d4O zo;b!inw<36ErI*&V!eBlYkl+LoT-@?V;lpn^r?L7_bB?Pn^TSNiKgy;dsgJpe<|E& zZp?EdkKguQxE{=U!h=zlys_Rx1*9(#Bo zdG4WojKz2Z(bZxP4}v>SYg$8YPVAv;k9sGNlkQs<-dm&KHs@+=G^XZU#WBul zzn5(HVxH%_@qT|f#w7Z9p4Ilp;yinP4@mgK-~kCYeqh0!pScfV@y)*$?0cjh-;9%~ zrEb2p?TgF`gE`{`}>Wlb_AHe{N6JjW6S_Q ziXImFOmxQ%>&91{Is&8Yx+wpVY zY7aAK*FP7m=G>e|d@s*K<1hbB%yU?`do>@?IXsTVGdmJZJ-*2ofYltsGikqt;OOVv z<>ontYhF~uJxAg=N6xV)X4{6vIqC)W94#g{?!|#<={Y*6#A^y3^FE5cjuZ1f8m{&P znsYR!7Wqqx{AXFyc4EiC)t&_VelG>ve7}t?!_=Io*fE{sQ&{X-9oRink3CyXuDZ`c zY=6gzd8`0Cx0uJVaJ8q=oX1MA&3PDGg{e7?*m2!&xq6Iy9N2N4r_XLD7V}&WcAn}n z&*RBgk9nK`cMNssaU$O4JdB-$saaR-JUnx9b?er^(=)vRZe8`LdosD|TiFNC$0_h< L@am2!_x$`H=G@Je literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_027.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_027.spv new file mode 100644 index 0000000000000000000000000000000000000000..626e606f002804b8459eb902127e22989e9c9240 GIT binary patch literal 9432 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_029.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_029.spv new file mode 100644 index 0000000000000000000000000000000000000000..18e49a5ad4967f0bcf2762075ac73e6079522a81 GIT binary patch literal 2404 zcmYk6YjadZ5QZn&UBX4>l7tXIIUxcfA*ftLBam>(0tOO5bKwS>7Jg`JB{AazLa{>Mt%#aT-#GGOiEkQhOFB&w`Rsy zRu{)loczp)4^krs8nZR^r6#%;`Dx+#3mtmpwt?g+0BYo1lWc0?t;cJ(hXYvkO^ot2C?;(MO=H_|5bj}_jGUhTXjrbSQ0 zyjbkKT=-$Bll@jtX}&!(J^!@3)Ll-g4P$*{w<2vUbGyXvl`v!Lxa8k2VaC>UnM=Gs zTkq_Vb-TfRmdhO0bBVW=FyrktyrYKuYj~iB2Wxm|4G-1ut{NV$;oa-FneXPK%I@c@ z?E#N)w!LWaPVk550vRIOSZ%*=fxQpy_m|gSp!Iv_`bW?`8K*Q++1|a}5o}}2yIY$u zeiYk$WzA;#xUvg$#2)~=#)vG?2NAit43g^*T!EDJo9Pplz>?OfO=vYpoLlcoQk@SiIEufqPa^uHQo+Rc9&F{gRltJZd(w%R@R_Z8ZEbf5Ou zXz#2*>{r|GFXv25pgptpDgL9*mGk3r&i=#t2JK$wsfCzddlc=P5O&N%*nU(0yLH=p z3){2$Ki57(z9Q@LEVHoA?b(VugLd^Ge{l+Z=MeqQ=vg}OY$eyo=L+8Z&Y>}$$GLh< zUz2G2Q~yi-DfD^7rT+q2zuNO1Li_%h<8P`tgBL5#*?dEc_9etz?iE|tzN7ARxkd}PxfffBF4x^Uf)g69C>{^AT2=cwiR zZz0yx_glq%2evPLci;;2ZN%R7#hLoS_WB1g_Bw#bd5;k@2=?4-Rg7=Aaq@mkXV(AZ z6n_5$-y?FyMIU!6-dQcccM;DcZ%l!{hx8%#pnV^aGuAr#+OKM%m3d6q1`D-RJl#nprK uA~)#QnR$d5;|lIESkBns<}1#4 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_030.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_030.spv new file mode 100644 index 0000000000000000000000000000000000000000..ac4ea364a14117695fbd235c98735bdb1c29f8d8 GIT binary patch literal 2568 zcmZvdd2f_e6o)SzrYvPIEiMQ%ttd+^i>y|l73iQ;QC3&VbfJzJI%a5%@h|=$(Zs|L zV&doU8@Z4`e4cmiF>jjQ$;mnAch-CEz3)`|MmMFjA#LXOUFxmfsShNjfz)5{#?0-R z@h2+_}1RcsfMI0cX@MXpJLs#weZRgfw^^PP6P zx$@KD*2xL<3e{8k0n*2w!RiQVof=p z8iM4~UW3X*v50*dbZ=GeA>%#KB|aW zYde|a#MjzRWo$j$yV$I;-X2b8JnZFO&g8iDY-iWxE61J7an=(r+s@~>z{|D^CI7IG zrNQEi-^1p)c^=N)`8r4E9g8No{hnpee)%^wxtkM0hh22_y*VHfKZ;i{4cl#!&Z)_40lU%-w zDf;joPC>p+zc0q?{{bZa3qI;sph-yl5}EB!Ec~w`i~W}UuOW;1rnm7eH^($&UH!C2 z9&vjafj1!Sb;#Vl@9U8GGP?8qFk{b%QU54oqwvUc1KB)&10v51vUueA7+LIT&hrVf zxy0?wnTr{3otu!DHs`N?A;*4-T!qAc&Ddwi;@%5mJR|R$J$fH*L1Ow@!*jb0iR-^H z>o1tvdB}TXAJ%d0fzILQ{pg3hLwDeDXS@%Rx#XVjzxdpR>ns0@D)->`A(!^g;o9Y~ z_b-sG@dwq1;9o*w{s%oLhx%8Lxr|kg*sqa|{WJIf4YHWAzvp}pkj2IRrr%k(%iP)? zLQTlr%8`2x+1zm#=8=aX@i^B7WN~vl3;o61t98t2?#Q`_tk2K6-$%$|{*OkySUKK2 m5x<1&yrcfN$YN1no0##=-THF%I2-2}`C7=vyu_~TUHA_lFPC@# literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_031.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_031.spv new file mode 100644 index 0000000000000000000000000000000000000000..2f8eff690e5c25e5253550b684c718ff89f405ff GIT binary patch literal 6084 zcmZvg2b7k@6^4Iy=|wt3Kv~3sqNqqmng|Puf?`Q*xKvjc7MBIV0xO7O#eyIxB1IGd z1rfwx0W{H6O=4nVVl;`yn3!nnkcfGnf4@1oXOrLaGVgO|zB@B_=KIcB3ky2e%jIh2 z>hoWdTDknMd9Hv+F4rhmH{TYI8at}njLM1Kdh|TO0SDy@^Wz-TG*>TIo3;Q=Eh(L5 zhrPy{;fyl@t}vf#Fb~zCH;%7Eqz+>$D@rCz>N2aedw<6iGJ7sJy?jQ#*BqtOCQh1N zGQMmQ-Y4q+PpmN4z-O}lhX1F(k^T9cb(tZTn^HDzcty#Sq2=Wj6G5`p&NZeTKXY<^ zuXS04?5|?djPkOXm8IqE()Bf|4(Fda2w!Sqey+{^k1HNEeB6Zcvhs@RyiJKsFR3V* zN?Xhb=XX8ENAOIVr!(xYm=VUTmE)c7Fyt?Br)tcza~_&;OP*?m??jH~wEEWMXhBDE9j8L&2xxxeko6WUySR(a~+BMtg)1*2ygKdcfv0WY~7Xyw#MrMACBJ= z_z3*Yz(?Yr4}27Uci=Ag7XlxR-xc^6{Pw_I@tXo4i(eb~IQ;U!-SCS8ACJE=u$Ogi z;1lt)19!()20jU25x56_X5gOqIe~lO=LPPKzddjt{F1G-1x3tWZ2HSqO#mFn%g=N=L}x9@yn z*VZraLi~w=tG~7X9q-=!=BMWu;g1gNUGkfr`rX?}fnDo>z_;N?2KL)(jnngY;5P?e zjQ?)nJMmS4y<6VN^t|61-{Hj8_N>55@P2brzwgGVz)SJI)2V+M-ghFgXW=`XcsYJ- z;1&3Rfj!Iafgivh8F(eWU10B4v%stH^#ebIF9^IE?=P)q4Ze2ZwfIJX*Wp_Sei+{= z@Ou0SfgiyS4*V$IGf4AozZe|X>>_!fbm#y1JP6W=tj-|9Ajy{komcj1o-4 zbZoA$R!7?BP!aMB4nv)h>p22>PmV%eknh|vs4Mb)GiNvCUOX?~Vegsmp6Y>mqF%@` zy-^?37xhE^k$GH;@27V*fEJ<~(M@O(x*6Sq zZbi4Dp~!Q*9eEF|hxNPzxz5GNn%TUAP4>scnWPt z?q>&j8o7S86Fr0cKI}rzB5P>9{G0K4+IpyC#xG>tn$~Zb?QX;k9FllXo~s6>Z{1$F z7E1ju=KFom>*c>uFTuu=eBQr}zej8S0_0l0PwQHY%P-TKw+-r_abXraH2d2u!Wx zyWEQQpc>pX;{o(L$4`*+jpixW^wTV6+@Jd%!o05gRpee)BcFHtYsmN_#>hWI<}f~x z%&y0nIXu&!BV&gkb6EFZAma-eBfp--tjjdUw4nWE7EgJ81)Jw!l=8fRH=gqR8gDG- z`3-D*40E-leG{46xa+lE#>{E|Z;>(ktexDKXRY1uP#t94e$UC+*Ho41MXi?yfSPhR;wWPbDMQ@%gr&6m#BeD5RUY0O{nHRt?*m~m_9 zexE~W{9p0L9OIdo^KZy_6>F3~%wm3Hwr1=8JKnkN`;xr>p!Me-?E45Aa}WA7-^cix zd-x|Y<7vz%*_c?jPl*|K51w1x!)LHD$D}=cjyFC(+rt-lWA0&dwudkA&TXG(nAU6i zIaTp|zC!NDb8x(SaliX${kdPq>_^7juRiVNU-+8){Wme=Y0THzn7H2q#EiRN?_u2U zH?T3sr2YCKF`o8Y3w9pk<*czawg7LuF)NY_Wm?}W`xa0ae#T>{tM6GP-yUKIsGV_ZXf0EH8WO8{ryCJ7p6+O4ys^DJ am#-P#nCJQqF>~6+ciDH$IbWjnd-5NcAsWX3 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_032.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_032.spv new file mode 100644 index 0000000000000000000000000000000000000000..a5808ecf657854d05b9d94cea714b267fc2f897c GIT binary patch literal 11380 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 T_j`{q;cUO`jmr1OQN3RS7h~%J literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_033.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_033.spv new file mode 100644 index 0000000000000000000000000000000000000000..98cf02e296b9b68dcc53f5865baa83f33a4cecb4 GIT binary patch literal 7180 zcmZA32iTTn6$kK_jiT(OtnUL68RBA@DIa1WN*UT-h@wORpE2442WeW_-h*~(X0*$O zP1}3h-g~>V`u|>@!}VO;dam<7|8wqhpL6c}c|QgXoHeY|8PFM?|4tsz>8>%IfnhqG z5uKr3y?X6=YZva=xpCp5#m5U6*%{Q06EmtatTQ-zU}Wot&D%J5aifFqIUs0IH&q!Cc3s>(cWC0+*7l2b^l#a7^01gVo!s#99MSMov+u}YdvLXHO0c>Yq&sy@ji{Z>%^c*K7O8l5 zpzg9~1dA=ZC)j-EHG6wozL~-9N)O(FdAk=gWxE@kTzWn#(&_A8z98L-n;pTmrDBf` zZ&mD^U|fkk&OIjD?98HSp4;_xI!iJG_36*@w(g2GFItVY*ZwHKKx-eC8&AR?YV zHSuabHln98u>{sMmZ{)a$cV(XTi$6YszbY~86C!fp*M&2u6C-$QPs5!Q zjQ4J~C6{|&6v5ZN#liNeq4q5a#<%w^jg7xMy)BE@BYk^%lK13@n)Q9Z$SIM1sl(g3 ze}v!ryd!m-8qIIr6Purnmlrk4vU!7(z-&v8q zh;?H#tFwdg&hft1MqB2@_rM5Fe)zH`*MoxX^KDlCbAtOK?)Hi%?!m!$-)z;kF4%s) zn)|uI=FaCGs`tDI{`#iYhcuj8&ARHMYn~4cR<~J*SMzmw;qpB!!fz&WRNW5`?u)3q z=JJSOyf|}tWVB^2e2RnRCU^&M?c1B4V5?-v0Xj zE)LdPPsF*KqAln0JwAeSE?nns4z4#ajtm#Yj!(>_1hD1 z?yhLdxqMHK;G7HBxlai`_}x7<9KJofr^Pm7zM9?BgUybwX7`L>e9i8e!MM>8Z=!0T zYj)2HR-<0Ut4|Nlj<)n5<~b3Z9^mR>cd*&i>?($?**KkNO*><3^p%mmh?uJ)&x=%#R|oe-_^yeR&o}Y>h_m@#5aFwPePJ;F z%!uFcYoqxs_3^(bf>$4`z85z(UG=F+jbdIBd1<8P^Ri$y@Vz`zzRAJrRX^V=B79Zf zD}(K=`d-!eqq_C+zdC|fA6(z)Yl7{a-r`;xtlznjy5H9Yi{-1g_xfOOkFVa|8-nq5 zuWt;->C3(Djke5>fL%T>zco{ zZwvM=tm57tjMG!~|Bhh%j7a5wXR!TzbvM@q4~y{mw-CF|_id?hPxLj-`PT=piCh|~ zyf?JCo0`Al?+Pcj?(@cA%YE{_JA#uRHj}dH`W9~r7O#f0BVxUe_e5LriP;yy$p_cp z>h}hp6=}cQ_r>-*+Mdn(V~gdh*?b__Z20QkelQqc@AgB%IDP7&YM`r!4+pDJU*grL zhmS;CdJyx`2u=@h^>A~rS-O|H-;V_!+{4Gi>6Nc~_(ZTC_}njBp342nV0&%$-|bXzR}MG+tU}Z%(P}g*Ejn4;J%1C z+hbmQqoQw(m>1v85x#ntUkK(O9dQR=jJDhX-YaZt7+>%F`@y*CwQ8lS*B=DyMgQXUq1PWqTY44qqX>8qQtR_wdtTe7o15#kQZXdi{B@UirK~w)3inUj)m8tK7c~#y1tt~ zHZkta9`mp7=1;-5M)+=v@YQ$o=U{&K?@s>`ZMjpvzeaHG6t4UGTd*^&ea+v7zX#)c zBI>MtbiJj21k0;-@p3x%pV5|c#r!LRb1q!x{yVtNt>2^D!{N=p;_hhT+HdL3aQOC} z+!fn?zPgjUgWU;VeK+?6l@X5oLr@n^~vF)iDcxN>`y1s|Qni%(CkGaPv%9J*#bIR@VR>-X=7*!cDvIWo4KeDy}A1iKTy`W~hR zZ>>S;9h4oT-1TSX2rm_`#LJN z{e0Ee>|lNId28(Un>{+VJh+8$^Mb;PeHX+u-%n!ynhprmtgm)%CAAMhLZdv623oXln literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_034.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_034.spv new file mode 100644 index 0000000000000000000000000000000000000000..306fd84511bc37d4a9c7729cb00c17a616da1bd1 GIT binary patch literal 1356 zcmYk5Nl#Q!5Jn4{QItUjMI2s>GuWa6njmUILT@@z~uQaeN6Id zAmZrFN2IqR+RfH(`*r8A(~W52@!kZO0?m|#LqBKP7mw{)*@NaRlbuA?sdEacK2P=}vH)_nl5BhSERZ{mEWjCJGe~VYGFSaH zi0EytGKKM3piktSIdsk=Ys{l~PtFQ{7m&WKe=FH?r*ARFdAFahT|L=eqQ|oY%(LEN zO44UNZTa=g(fK)Ko^uJksMzPxt!teNNc+frY1^~DJXhj*JKL9tMf9F*@}m68lSjUP zV-?74s#voQto4j7lsET5pYRNTuZh!TbmMaBeP?q=oa+_8*1M8?=Dxru$L@}PYkf|& zuA-acclwm_uA!Ujcgppyqx**Wxt{x{-+F(T=LXWblt0rPH_^RQfLmY%7<13^|3iW9 z&gPiCt^)fgz->^CHL!iV0Pel9AN20GyaSAT|9kSSq5GEK_gnJaMK{;jFF3r1w2tR5 zwsCF!&ZM3>a}MXKa%PXdS>^0Lww#%tIkR8=a@M04d2n|7bKj~w`gVt2-f`DXGP6Yk$*w#q#<_K#N|g8y>5L+$_o literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_035.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_035.spv new file mode 100644 index 0000000000000000000000000000000000000000..7ed19e09f634ff479d37b0902e324ab101beeceb GIT binary patch literal 648 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 U*0W+QwLH#~d+)k=Cj6V_G5scOXaE2J literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_038.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_038.spv new file mode 100644 index 0000000000000000000000000000000000000000..7bc54890807801c5ee9033e17bedc16344ce33ab GIT binary patch literal 3648 zcmZ9NX;)Td6owyp0TqWb$218d6SYvvF&r=ptf(xrxsW*ucOEyp*|r-7KM!T!nW zaQkRy7yoeM8qpKuljAc5uN1XvBcp|H5w^+c!M&)0FTRLZQWJbS`<9>wPmdP!H&RvZ zQyZDCPMn?@uQGW9GcKJs7kC+X9C422=>L0FSa(W8g|EUot>a9MR7h!TqQ9p$Fm|L` ztqntq{1xa^1GRz4%&)kFue^k>x`Zp@d@5KPYdqc#=9>4_Gm_YR#IgRx|N!1(c(4Wb?BBt>eH2I&ske5^Q_NU zyRw>!8_+EXR{&j~u0ngh+PgCMOto#x@f*P=81FpxFn%rkYP9`aV{=}wHe*||-8ETT z?j9H$wOheH&gR~2kbTibr)M;E z=;|KrL#*K$Df;d2y7e8Vzjx5~R`Pwh->qQ3 zfedIAAJJx(fmmb|&qy-iN{3e`YOy z&mKXvbs~Q-!=q@Qzp1J3F+`ia#L??&T}m&W{<&tL*+;jKL?X8ZrPJ&%)8xngo1=fBp z?@<-3%`=U>Q{c#RjdJ6{|4jC8M@QWnSbNl+25T$Voq=1|JnPDhi@K-5`h72=?z3R+ zQTI8pwsPI);gM%uxpCImihd#c_0?zo54*k>@i%N8Hop-*>ybUg`JHMk;e}xL_eFI4 zwk-y0mmA+y;?3Y?ncLUcjYxd|Uji>he9z10^DP^;=^Wv48xA&1IXh&M5c(zK(W{YQH0Ipx;D%^q)cNS4Zu)z}5)WBl0(MX5@?H59tgRi1{nq9lMZP*_{|sE7{d2gssQ(4nyB6Qs zFTuuWch0ZSKF+D{YebuKilfdqVCVc7yI8+*F~_%H=ZJ6FcVKN>khlxlT!-gwzPfxj PJe%nEJvjP_eV_gVl_v*- literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_039.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_039.spv new file mode 100644 index 0000000000000000000000000000000000000000..01b908defc112f3b2ebeb2fdc406415826052370 GIT binary patch literal 3428 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_042.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_042.spv new file mode 100644 index 0000000000000000000000000000000000000000..d356cb19d70a20e3eb48131743612eb99c0b9da3 GIT binary patch literal 6456 zcmZvg2b5k_6@_0ilSv@G0|{X!6JQ`1Ktc$Flp&A_FcigtH3R}N8ZtUbupk%^0Tt}M zfn8C=2#OR1#e%)}h84kr6_EaY|Nr)^yWaA$&YXSrx#!$__r34WT6B!=9a~kSs&V|c za8%VAQ>)Q1RW-iqYWab|QwA4p-L_%T;zJK|!lbIBHP1PdtFculel&LW`b}F*n3bCX zl4k)>N2}K=ipG#F=Z_&bhB=!sb6xn;x1ZHotBc6kF?{CMq0QU3Z5m<~YwYU~kHh!Z zco%%TR~MP8+PHb$n&I^uR}T#hZy;p8t5nsxfx$KF&KTM}G+b2!^&ZTNcNH+i~=r!i~bx z-;cn4p6y_~b6wARdFRS|9%JuQ&io-YF8eQr^NpB46z}}h8{1nh=UD=_pRs)o!>Ve> z%It3`ks2jF9PGE8_z1A?F!3_*kwq-_TT6a9*l!{63h>EAyb|nNO@0;F_n){QyrGDX z0{f1WUk!dy5g!fqZ6|*W*!P)u4fwJm9sv7>lV1y-U&P0PuPox@z`aF$JlJ=Y`a$q@ zMSKF-_mTXGVBbyRlfd5B5>$4dzDI|9x}Qj`d<)%p@4@$GY>#n8+zs|#%&*|ao!f)` zj~-9J+e?2hwNJ#Kf;r4T32$D%oV?$wcW95D{Pny~t~s@NfH}rb!R%$NIJN%%SliFn z>NoaO%ze2Z-&(&*L*s$z2xuXOwYhOT;JR?F*(;4dzS1+KKq#f zc0ZT!*RxH;pTz@LD zoa<%Iw0h1^t<7n~a{W{;!mr1?Z)?3@?m#T> zMb7%X7qv9!yUJTS9c*vCZ|MxY->1XcGx6s2S$ihf9(hY=f#nXu)XsP#W-n{SsrBDB zYt`Wp{By7ltb9kCYCiAixx{i=?|ESR$a`;_@ebEEcQz*H+G5X6+Sqpp@361A=VNmA6{nBCU-n7t@0Ia|_1*aIv7C34`+ou0`!{Eu-_I~6pE+B> z&ar>yYy-<*KyPcdV{+D}?i_IHyl-RYsYCX!H}uyk^o3aSPW?@n&z-&)ESEcd30Q71ruOIJ9cpjxrPz6xdll!b=Yu_~cNUFa2A0q7 z)ei9g`@OmV-rS|NmKTDpl~4bdgYBPhdja?&Og{Zz0Z#uV;OygKu(|ZV1Z=JR$y6NN z%K1+GEo=YVeHdPiJL{YptA*$G{L%Q8;HJi}f|HNNuLjFSXwX;8dn4FfGlp22!-dr^J5ZGGz^#3r}{>xj|{=NAK zSU&wf3Qqr01^zKpq+I2wEftOkp*Xz*3Ad^ETn91Tj1zXoqE8hjmWt$g}_ z18o1Ju=M{XSU&x~1y27`<8Q;8OaJeHt(A|)-vzs_xu(YE)L1P%x95+>-vc)_{yv<1 zH2witE*k$3EVmj{;~(K2YHaSu*iSIm5=Vodg4N(?EE@a_EFTSi4vq$;#=n3!7Y%+1 zwpKp0tYxQ1qVxC!hW^!RcRWJPY1j`p*ViD<6$_1G}!drpD&f zSS>ua=a0s_gPR)f0Vf}g=YZv+@m#Q6G~N^JP-AoRu)Q$X5=Vn>uo|3*MdKbg`Did7 z91Tj1d*RJRg9Tt~<DUe`tJiLpZ@!T)4$ZX58hn*?+3P4J{s>2c3pE#jm@dC zT6k{H{}7K}ELZC9J(O?Ww{LtW-uZgt{I=_jZ>#fq2d^~RUivEKOHI@UkT I-j-sI0n|@3S^xk5 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_043.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_043.spv new file mode 100644 index 0000000000000000000000000000000000000000..49c87ed4d4350d9ab49e8dfd0357bcd8f9b6d16a GIT binary patch literal 2084 zcmZ9M=}uHZ5QSS1P;miKad&WEaY5W!+yHeH5qC|9iVzcY62$)|#>7{^7tr_w{?R8G zAIG@G;P>6RHBM+#)~QpcyXsc=P+zyLDWwHz5&s^h%4$t@Fex>s#>@{EM~j^=XU02^ zb{|r)Jk@7HH7in6T8OX1oprMcVmSHdwNP^gT;ZdC#9*%7#@G0b9h|WUFJ1#)j4xpAoVNsT?02sw zwwD6NII?(Y9^=wJ^2W;ySgY8z953$~euK-{b6T?Kf80v!xz=5YcaQxR_`eNrPX2Tr zI~%#p`3&q;?JB(eIv2IZ&PC4r>Kv<&-qwJ-y1M!zZYO>}JKG!aT4Gi;zm8yHVxk(a zC;nD0_k?~!CGNG}MzFm`@5X+YT*f+Hwvj_bMdwd@UF!#CMBbmEgL;*6_W=dB?zN zoqce}!QPGf*n0x3*4$_M^S5*ov$pph+$peHxevMSG+3>XE1qZ+ks=k_cB2$dIWBMy&G_9%{hxWOCPfy1zX?wsJBk^b`xyg z-frPt_9lNDle0H*?X2Z%WAETQzrtqx9jpcOe)R5b#oY5Le@l14>g26`5AU+Jx%=1y f%-Z5!Gz; z$~-)Ba-?%$9oty4H&qKVQxG!z*QZ4eo0LOj6`?6Oh z;JH1g`>1)&sIdh1T;4}$O>pZL<~3#~u*YFH!_6D^E_kV6zXZ3xvA!E_-LXdt+y6 z()fZNVcHhtJxJON{b%O)ITIG?e z2W~FwxS4ak4p+Bt=6ZwKVJ_Et!9idy`L$eYAKYBN=j&PPhpYQu<4gl^b>Hh8IUAVE zK;62$_d}oz9HG4lF9U1+G5Za|^>yv9tR2pp@Bg=~9f9lXTKEmY)%`Ah&wj)3C;i?+ zQ`awI--fIE4gE^2Jva)~{onY7m*F{%0d@Z))FXZb?*8f#{|;Qe7=IjFJ>vh&b)G;o zx9bbsq3>)IsE=a#4#%>lF8m()>8J19wg2d!y|s__Gy3>0+&-2-^zkHIy$M7g--D~$ z$9b~)A21Ho?U~>9`&na3x3hLC>pPjf5B*L9^=1&UAHdCLzr*hgTzwaad}rb6=JS5c z_aQK+YrYk=kASfvVn5Eh|0%J@1YF%(BK8xwXDP-`VypZA6S3#u>c&Pb=i%z+t>j)! z!PO(~LSDD-@c9(3{ztBV8g8DV&qZwY==luX+{U_A?73^jp4)qE|0{e0{y)SU_zdnF zD1OVAu+>{Yyn$J`dhrd+VXH?U=izFO&?;~>dmHz(0N2;GxcAF&b+zc(B3!-Lvn6bG z?>)Y!Ww`nt5V4=bjco;S_g}!(+d#yA30E)1euZspJBZk?;p!bAVz0o}jrD)PZ}S^q qJ@%s!g#Inuy`I#+Lo-k4(ckaU%w?QDuE#g+TCtz@^?z=-2Rs0?hqV3x literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_045.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_045.spv new file mode 100644 index 0000000000000000000000000000000000000000..ad1972636e8f611cad90d6047e66dee420e14c7a GIT binary patch literal 4680 zcmZ9O2a{A)5QQHsNkM`n3BoQ}K}>)s0)s>qC7BZ$M1j=>446nN=A08|Q4tXXV$M1H zSBzDbe&6gn)RcFtt52WXw{M?*Z)Ucx<-oQ@(V}R_->*gU>Qc0XDT?+*o2s8abKcC6 zYt}9qIcoF~W^^p-s)^=wD%uvU@GY@b3sro1z-(qcI4E-HtR6odIR?DHOCD#v3K+<MG1u@i?f^EgFYy6*bLHF@cf?$Y)nol`^w7D6?*eYVzg2M{ z*n6#)b6vsS(}SM7;p?%U+|eCx?DH}1QO4?3Lr=W-$&V{zXDipQoS`+$JqT|d=W4F8 zbCq+ySBcH{uHJa>ww`^8`(Q<}VPfLG)wrl6KDZiJDkG@ud7p`A%yTb!{lV0kkhs1Y z7uCAXsR6UE><_5!SN84uo}@4H2Vu^{eB;5GIuj28t2OaZu+JdzFtG26b2tQV?ab8J z+O_u`O8hTt47XUvUR~DslV~{J8T+h9VCEz~tc?F6ZzR}!{cmL1`{9`Hl{NgJ9f|GY z9^a>w&RTaA<~h$#g7bYFjoF{v1QZ&ZH=bIa8H33s zKBkPflr_heIr2F#x1rp(e`|NbYW3P*dN>yBOw?=*V{!J61G{ex_l>(?)*FXcr#|yL z9&E06jK?NmJL$*yO~l-{zVoZ#-FG=Z_a|W$%(~*t?*wpar?<&)_9mYhO##d2+|+X4 zcRJ^$fjwuznI?w^Lq+lM%MP6w;U^U-q#SU&a71k0)O51#c| zc$c-^I~$X;wm9$EIbe0#YwkN2?0xR#zVpEHiO&anzwed2u~^Pr-?7}M&)l4&_o>hN z_F}HHus3~rbFON(H*@lgoKbQv0RO-L`Ed5{Uiw`CmQTD8?E7HP^2TDh1=x=Axh(=) z-)HSy7vo*d)x9N{oV|P|>oTzKu6y2PY+bSMz4xdy_4M2M_VxQ@Ip%%V z^mCDWE(Ck70n2yY3b6bX%$_g8yX@J$i!nKS7N^!qu=muy3#*9j***I-wsy{}27AW) zqq7n08TUM6Y%gldz52Wpe%Dw-y`HfrbNzm?N4>G%RmK&(&(YtRORzd@7QX@A@t2mI zysHIfU%l{6SR1S(=6UniVDekZFlW(L>H~i%#w~;!=S73cg zes1}jer3t`!@K5`x$D8+>)H#~8GjWf-yicCUX6G84Bfj1lXD*8^m;AWUVVmn*RKQ1 zr`HW&x%9dbY`+_@^tuTwZ_h60pZoMayWaTCm^l^9GxibHit9T<(7sY)`Jt_c^e-3t)4cxo7Mzy0(MWRgd}Jyoh(H%e|K{Ictie>t(RIhG5aP11uk1 zuYl#EYbV%VT42%jDp=m!=-LIAPp-PsgFd=mD|5EtJ!5~-wHvIid>&p0yVT|08i!1BpeS9;J#*SlqoT0K+S-+RRN zHw;UE?}O#j-v?m1^!Fjynzj9XL@aM^`ui9xpWMymZ^0*U>oMoqf!~d8_)jsPV=K)4 zJ>_r2XJGg8Ir$vya_;VZfyp^{apwLdSY2JP==usQA6;LA<)Z5wu)VtSK79+8H#fSz z1Iw$=<=oSQK6C#bY>v;uGxn$6-uNFd^-jgiOAkMS-E)Qe37q_JKbM@(U^c%~J@CI^ Uo;Tn9KA8WTI8*oj;l{Dpe<~cM>i_@% literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_046.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_046.spv new file mode 100644 index 0000000000000000000000000000000000000000..3b3678ada622f6f7fb658b8c15da3fbc154187ce GIT binary patch literal 5816 zcmZ9Qca&XK6~=Goy-fNfkX{Hcq)-wAnM^`WNW{z_2@r{>s1QOLflNkc5>ZeYs(=c1 zdQ&hO1VxIyQ0!9df(=Ew3jZJoi?#gy?mK%p>)u)4+TZ^6zI*R;-o59pHMN$RLyBTh zF_ga-isrRj(SlMGBZ}72cCA{oYJT7L4f8t|9biUVQ7aS88C?u1>ev?0y>81k14h-x zz|?5~tCh8uanoR;dH!HxgURV`Z!cr5@KbhdDton(tMApbZ6onoSx;X+6x-dtu;jx^ z-cj=5@`cu`u?~4NXJpBnIiutq&78K9H*-dp+?+aVD2l!v-F+DRR;m@n=B;Zxd)I9~ zqNk^KLsPF8yFr+FfqpB0`d+;o`+BzS*uJHQopF}kn=;($MX|PPRp;9EJzINvi{i+# zLo;D!%Io4D*YAFHaff@k*Fdc4&lvD)#n_CG%lP<=PssShj8Dq=dHtojY`8LVYKRz9AI_s2GX*WBcn4?VtdAEpLy zPmJrg1NSieg>avvai|@cz6kC$fu4)84KR_+1F`znn1p{2R!x68xjt*n{CaV4($x+n zSKsH)+y?$3iJNcjL$Pw-5o;fYRWslC60C9OHNF(97PA}I~zS_A*hSl6#^J!3}!FXJn*#?|## zVeRD%?w`K1s~JB!ar51K-w)Sg>=>;3qUOE&z9VX}mSf@83x74-*}eZQDHgr;-G|7x z=W(DY`VXJS)aI=Lt|wsJT5rX=E}s?s4i zXY&0$&3{+&{XO;HoqT`K*!L6Rx9r-rH2jnBi=uzYV$L4lFZapI_w8l8wOIGjTAop^ zN8es;neQy4GT&MKW<M2*GlB2DYnTYu0b@SDdjZc3W1c<6?x2Hb!70FdJtO|hTGwNZd%c2hd;?Ior`#Df zCSMzUtZgrI{FZD2G2gy$=QB0|7>gM;!;Qxbr=~cjoWb}OpzaKEXE-hS+UT<%+;h#G zao}`tds^#OxN+C(TD!5vydM1AunBy9jP-QXpY@oiJDl4)5z`E|4>sd#CWT*L9sy_k4J@?geP-QTIalFp$?(GcT{}zD3=Sz^ipHLQ{{r7sH2xysnyg zd0l^psCx;#TKA)9>QVP&@DU)dt7cwa*WWejejHw{dnuZF)V&No66AH&%**TgoJ8GE zz^ipXiKZTPKLsBJ^15o~<#m1TqVA{R)w-WSQ;)izg|~scu9|syU7zEq`#E^E?&WCe zQTGb?Xpq-cGcT{}bFA+>>hrAa=gD7y9SeN+R{(Q71I+Q=)jvJ?+PG&N+@5jIX(`8Z z#hm@I|;i8>oo&Z$`M@tpP^ZQL^v?)et?oD4T-J=S}!OujbG zvRUwUV9qpf6^PgjxMzg1Ilx$)+gHQAcOmecy9R6A%X7~7wLsk&&+V(PM z3b-CbY&P8aj7?IZWwavRpmZ;R^<|Eusp;A@}-+zx8s>!1$q0E5AupcUK&hJd@l zQ1A_4AM3<>_f5F>xF60M-CIj?=3Gx~fN?hMsF z-$OGNeZCLR`}_c3&AjNNmiKWVqR$WE!$7sqJ!r;!xbN!!Ii4l@Hz!{k_e_R6XWVmB%GrsHIsXiI&I{6e z{uj8~Ng(D_i<(p5b3oMeJa-OlAoidESGVV_o|AvnN4G`=34_tjUUy~)+=Yd+_IJnP7J;nS@ V?PqO!L~IQ_kD2otU$le3{{gq)Io|*P literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_047.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_047.spv new file mode 100644 index 0000000000000000000000000000000000000000..7253247b2bb01e0f285919b5de95f424ae0d34a8 GIT binary patch literal 3216 zcmZ9NdsmcI6o(HGf>-b^Y6W46X;!47l3b*q3khgt7mFqsks25pCPKQ1k!AnXcj!~J z`b_;_wpOj4XLvWhaaeop-~R3EIp>{2Lw#pcN_DB3zn{|j+MViQQre!j)bz;c_0cnn z)#)>5&pmI%uGCNqG^QmrrN_|q$XsD|UWZ<}R**amKn=B810*%#&Br&=sgam##X_lc zXK-PmQeM7VuFMrmvn$2v!D?Z?yKCuIcP}BtH8535OEtWuR(qjbDpUxKAnP~dpDLFt z(^<||^ula+Eq@!hkn!8mD;eH_uHIgsZzp)FIA1MR*6m%`)3b|JRBiqibYXs`RLtyF z^g^Lhn9Jv|MHwXrOA=e;mN6Tsa)&bkoLk=i_2*Q zuXUW+{@TVrfw)HS8tc+0eyV0YvO6~HhO{q-_h)!7H*)~oL9K&m@d5B5bUSj8x@~A} z@30;FFxoqo@4!BS)-SJp6s=F&_{Y)48*>UF3uFXMOSvxv3E zU_GyM87J>@&Y!chJP+3IdGwKGZ8>Y1+k?pIvyb-0EcXJ~zVeYP7r7U~=0>keU^&lv z2QP^AeNddow?hATR{JHeams^?y9_p7U-Xl+pJ(fD$#aeVePH|FAm4N8M~smlqoe2U zZ%$ruIg4jML5_DafW+@IxWSAwHn=MpXYM$sV!t6|05M*_-?4N1E$RD*ZWj>m++M!F zE`Pf{#Cg}gv)=#9Xz$zKt?y|5{?;_^OyHD>)?jil0#lH5Bn(u)(@B4i?`H1--i^=c%CY*fq{Sa)P zeDsye_qBhV+ect$yPwTH2|kX8m1g&L)o8z5wTE zTf*)_A@nzh zT+F5IT#>7e+;73=`p$^s9c=?QA+DoH4`+24-Hh1(E;{~i?gSef@9M5ic1zB-Mr&p} zgMC&J>w53n_mEZOB;p>dFBkFOf#u?@T?5x4zP0+yaR&Lw`5tVJKKpC?|JU=nk2E6k e`khxU&gciQ^}_xUY)t%*eE>E_-gDIU9RC9f9_7mb literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_048.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_048.spv new file mode 100644 index 0000000000000000000000000000000000000000..5c05c1c068654799b74ec397bf54a5978e0edbca GIT binary patch literal 4644 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_050.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_050.spv new file mode 100644 index 0000000000000000000000000000000000000000..8f847880b456ad1551fafe32089540deaa767b79 GIT binary patch literal 4156 zcmZvdXLnUq5QYyVp_kCb#-S-lmrf)_G_gbh5xYhth*2PzAa+FoyVwiZu#4C$VyEaA z{OE77tmV?@xpxm9@A72Lo%enB?Af#D?0r(zbA0bC>yh>0?{HRrhGacavaEmBtK?f+ zSF}#=-qb#Q&fJ+s49coXfyNBZdS})6p4j?T9UB~QRIL`I&H|vSQm#fO)i7F&m)8)p zy0f#Z9bdz`=2*L~t+{K}+9gRY&Fh8Ukpi7(?yfc6vv8&HK4pGtnO9|f%bYQzv#hP9 zwYhC|=eo|Wa(q9uV!r<6_}RG9i~(hy@>OR8%lznigW&(puc9AWwi$D^+KSjAWqvf* z&@wNr)k3^`c71cmt@lLCXBZtDh967R@Dk6mk>C;F92-USNW9$M=I~K?`=jpoF?h$# z>-cCqucM^bC2kFBQ{cuPi)GoCx)Jc>K)IC1aryBjR?c?<*!7$j^R54vBS-3oQ`MNH zN1oz3V;S4Eb994sjsqJL`xp;4uX^O20QQ+mr`_K~%(c`b<|HtcH3mN!wsPgK4KZgD z+!*zUnG9yXOYF}nAlJ1P$ICwZ&pxIy_BT(APlNMpasG6G{j~4)S8ngsV!at)!W-|KfRMPTn%tXT)PkM74cPs6)rymQxFjQK>4da&m`cmvq}1aAa;|AIGxz2Ebw+`C|3 ze7q08!%oNBXV1NRbA7qzr&oc;dyR3qd4qe7-CJ<`?%spjPwOsn>nw7=6TzMDcOtm+ zz2m{{Rc!_LTTvYMTOnV}emqZ0FwfCaRL}nzNmKXnT`s2!-o-O9$9+O;2CEsjj5u?& zV8%MOBWY(P-S0p>E817JCXjtP8&mT;U~R5<4yL}J5#Rs0N%NfkMvhjz&!5CQb{=*< z<~tNe?xkRJ=UC)k23FsfaxVv~jm6A;0p7>lj;+8h#LO)=k9%E-nR_e0@{5u-5x+fY z7bkrZKKgM9SbZ|Ko?PSbmtyMn$8#ok51y;bFtzB9-;m3b9x+#>m>h3?#$1W1ZzGTV zD$IH6F|Q3=nfq!q^`FzcRbaI#*ny;712&&y5w{ww?)S`nc-GWnt#)wbT5HhMBj(x^ zljCC_Yr*QVkL$qBQ;&Ha;L63bzt*37IEvr>amYLV6~`c16VEM zJHcwxu)XBLhqspnYnU3S6kRpjditL0ea+XPlG=DP{5o+tgMw5QE* z*K&L#XTke)Gp6o)>6^IwaqJdME%>b!{IaiR3#>i|i~DjnSbZ|Kfn2ljTQGIk?U%S`VJ`R{Of7mm6MS#d z4-zBanzVU%`>wVv>GScCYdhFnIp#i$yAM;3dG{x60Y36S09H4@@5Ol!Vy@wsb@xwN zto0DQa;=Ba)FbAR|A~1NP2Kz9Iy*4usYgAJC4C`2>V6!o?tZOj0A4NDdID@c#Xdd> zSC5#dQcRAI{yYs8OI zyYg(mfT_ov7s1X6{u0>t5H-9EHby;iyaHB_IlIBdI$njF<8bQ#YvA3OdgOQ=tR8ph z4Y0MD+p*#ua;$iVyi4*{ym!j~bJj8v|0Y(0ZRJ<~R?;To<4(Pu^g4XpsdvEY#XGeJ zuI^bFgqO#Aeiy7(JPUi_>Jjr^iplZOtM|d`@s2(KJ5N34eF!#pj>Wu>!0K^^J_b8i z-TDUO)gt~Auv(n2Pr+)%^ZprJ-SZXS)z87|i!t-o;?*MW7vN&vFX3wSSe%)CVD$zp z@_q$YkGw;`YLRz8xS02AxLP9?dA|XxH(`8k6^XRxC3ae5pf5>Y7rOb`4F0Gna3E%?PoRKvEupl9RHQ|$QEG#0Pzq@ A5&!@I literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_051.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_051.spv new file mode 100644 index 0000000000000000000000000000000000000000..727c64d2d62744b19cbc55ccee84e75f33be8417 GIT binary patch literal 3200 zcmZ9NS#y+C5Qa~dNsu6mBoJKSOGZ&ZA}SyXgo$VdbyO7hErtYQG-Py=xGOZ%$iNIjNU^dpUjj^yzQt>8|#t)RorpcP+Komeh?UrGeB}%6j8W zV{B=8cI@Dx14e92J!POVn^J%3MRtP=)ANfu^lIA-)6M~~o-$XBO%=SI@#+;~&aRv< z^Y?MCx~p|=skyMSJl`a9g&citbIHv+11eZOb8ca3vNb(-ve|6S8dl-YI;QH4$*Gy< zLbH|9snV)9rD|KGI=em3n(FNEjM4vnZGEIe_pAZ12^jAgJArE}S=J#($axb|z74(} zS(NB4_gcHQA$D&l?Y=@v`?7vBT*G$sjZkB)Z)dJmTY=9Sv|InttXsdf$h8^n@~kb$ zLWQMY{gzT|=i3T*ujj@7L3qKX2k{JLyZ&up{jb$y#;I=yH?B9vW8W~kck&K9kjB_6 z>%J9f546Yr+u$z!w7`ZxBe6DE~NFw{k-EZOq6fD8~7H1CUNGwJNs^+ z8+Q-z{lmW}+fLIl>)i|7W50y{acc7{eG{DLJMII{g6H|h$Mbpj!u4&)b?t}SwZSDv5vh&;rvi%P{55islz>PTw?4NQm_u&xS z^P+!;;o8>r?;&jZ{$l?TqZo0`%GESAp}Z?=_$==J$2@ATVa_{JxRx#yG!kBHin< zU;5ty+O1C>^E(AMXUy;0aBZFQJB_YA=JzbzWo~^lK%2ScF~75L?;GV@&*mL`R9_jL2eRDvY=gRGQ+);bXuf6n+!#T#@xJTLfPVSAm-hn&6zMVCi zKYa6WYhLRc!uBp0&Auwqeb)XS(q-+&I6K;`Lunn_)Rl480^C}x&2x>7`Mm(|2hOMS zt8RSE>LT2k4!sFCCf?_LxG~xz=Lc|e?gHjiH|{!hJEJYI8(8lW(t4HFtA807;~iGO zhrpTqD04))_hY1cm2vhbaL+bJ)ch%2d(6aVaBT&!ub(4b_Ep~(K%2Sck>^Xec|yOK z^~?FUb`{+i?cUqiRp31%pE733yIJROj`5zJsf_=NFTuNjzhV19{D1Qm-2M8kTiqVo zBXcOD&adIVVSJz8z_k@1ezUYi{AIXr9P!`6wG|*{L|epPf&0c0e-*B+0P+6XjNgI$ Q4){j;db9p7w>$#=18Q3WzyJUM literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_052.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_052.spv new file mode 100644 index 0000000000000000000000000000000000000000..d9ba741800113442e9b9ff29bdbf7990e75a6c29 GIT binary patch literal 5572 zcmZ9P2Xxle8Hc|l1kfNumIE;n7a+J;iUA@@P*H}f#eqNo(LgW>A`XZk7*s?MK~O}7 zC;|#q+*NQ?JGHH?t*w=|T5D^obyj=Y)93l}zxp0O&U5bX_ul>9d;gpi6?SWp%N68W z^6!gW)305wkVr09l53tXD@U9?qIX?=RqsB1kFiDTTv5KEZQA5o7VOn@rNk2Qo&#ni_3#mr-$Db?eK)sCMsw5F!E3Y%|NOgUlZ>~J z;I9Rq%(S>w`Z6&9(YEe@CKc2Hzb$JNO>xxxx2DFAn}F^zz_)p;rgr z8@)F8qtWYw_i?NX{#f*y;EzME4E}iZwZZp6UlDv?^pxQHp)U@;Kl=RO2cX9Ue*$`B z@F${21wRmdPVgt8F9^OIJt_D>=y|~pMlTC~2>P+$E6^_oe=_=w;D@5$4gM7LN5P+p z{xbMs=>G*@iT*11;pk6-KMnnU@Ta5S4*m@E>%osezY_eJ=tqM;3%x0LbGtcsbNf*6 zqtTB9@7X*V{MqQ;!Fv`j1b;62nc&YuZwcPBza#kXpce)IUG#Oqk3~-n-m@Mb{DtU? zf>%!n-n(~M@Z-=+gTDm5BY4MtEqKRzEBJ}%_kyoNe;B-X@6+HXqdyMbxA8&nm!jVZ z-o3sVyla0o_{-7H2Vaf8C-`aT8-t&Yz9IM;^!(swpl=G^w|sl>wdlKouS4G%d_DT+ z;Qf|eAN-YQN&jEWLi=Wt_gm>3PkuJ~*x;|u>u>6>!TZfj?fn*Y58k`uH!;=EK_4Id zTy%Nx4d~N?ckQk*^`D2{7QDH8DtL3-5c~qPXPWviMEeGk_iRQ7--!0jrus!_-*obx zjc+1(bM2i<{uZ=vAo;~;-)Qo;q6Y=P1btlax1kRYekuBZ;FqD>2JhWy8T@i|Ver0f ze`)>|=w`vMM3)5bUFsP8Ds)-!tI@{*XLRtdnAkk z-}4x-y>IWF40ClZIL3Kk-}Axy;G1@>W8nh05Zr_1MQ|~gGxy?svhO9}_~T&$OoS?M z?UP_KOo2;bDqIGagXiR0tHGR``)M#8YO+#41I+mqVE%hSZAKlXIjx78a3#1#*XtR~ zf~#OQTn*R2wQwEGfw|BC{lRm*9=r$U!+g#I*Et`|nWf(Rc7`%=-8X>uY5{l`7Q&6t z2#d1P^>`<40^69+o54P!Hg*dvh6cD5mcVVW6qdp5upI8lSV6fG?u1pa8tww;cRbJ2 z+_+BjXTCi*QJcfN!F{iRdtfcx3y#qMvtV7udddy35v=bIuG#xi4(8FlIL3Xj349ax zgJZJzYEfsyU~jp8_WB# z67%Mo{I!ICL&DV6s+Kck1U_ABv8QOlXA@zF|Z9MjS z4R3rDWA9D*b8sx&!Ms_1N%?x_Ek7dF-I)4M! zyRI$7JjdUH@iy=|`+1YnKK{PKTmL&S?%e7$-tWlM*0cxh*w&ecKT`U0J$oqs1jbyC+PS?iaqd6kjm5d&!5g2K&HXOg zm~(H-=Kc%XxvewDX&y^+Y|h?;Jzy?u?;2d^Un%{$PTRZ>#$2b`b$XBEI{$_@7T5WA zyz#Wo574g3cnxEhQ2qmqx8i2&{|N=q46K{aevE$zexs~Uck!bvzMFCsdum1bFEF0) zJLLY;xx0^aW*?(n?@k!Q{N6k7n(=hM?CU*p@0RhtI;OdF-cMi`c!ynsc}jWy6zzA$ wI=?a2ndi?a{h4Rm_)d&Dm!)$V(>K*M&Gk7k=X3tY!M2`>IkWD+WN-ldAGoskTmS$7 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_053.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_053.spv new file mode 100644 index 0000000000000000000000000000000000000000..d827004963e53c7d94d156630f91239cfb15d5f7 GIT binary patch literal 3936 zcmYk8S9g|06op@sP$WnR0Yp%PU<1Skh|~y5EKw3sv7i9~5e1?F6)VArVgq|Gh`lZ^ zU0%T7@JD#-QgpeN&+~n=!#Avxv*(&sBX)s+x#YRcke> z=DWJrcQ4qpck6&zOSH>09HCZkTxv#1|~7f%JBhVQ_pvCCMzbI&o4xmX=TCy%Yn zd>r%swxOl%uugB_jR!lXP^az=Ck*SHPpr*OtviYNAHDllW!*OB8;`6W-e+>1Kb&u` z%?DS_=fvuqg2~a;J{7NCzf}i6r{PCn#+Q}3-_=<5JOf-+gUd3XUZ1bA{!Fm^)H`== zW7FAb2HyQ#uW@8P1LjN;@?7t%LNcZv=iZeg``7RI_v4wLQ_J?8$eBBs%P}6#EO1pV zKaqL;E&OskHM7aeF`n2QuxHm6qr$h~ojZIRe=|D|zXF|}|9s4IuY>8gzo5j7J3RB@ zaxWKx&Aax261xa&yaOA@i}btA#jIP6ng5F&=HVUxf_*RZF}3J_Wi8*^#hA6eLu(e` z9si)!+$ESX>%=GVuIt>m`+EkP-u=B(_wQwWbzO!fm)PYchO2%nI<5fAHK&e+c!xU7 zEy5OK?khf2*1r;LjkRjCPLAAgmXy4_MvmM+xdU}xg}Ih%%eVeu*<&fV4U?1DGO%%D zLxr~-Y#*8nZw1(RW9>@j#{FH8dsqc-Jbx#1hvzqUHP(rFHgWd!zU^7p^lY7YIr^M! z4cNTrm2Z9S;u^5`<%pJR!N&a^W`QTEfvs%k?GSiI;DE zwA=tzi|;5}ZUh^TmTs^^E#_{*jHyMupSbsVGv;3ENM0Wu>q=g2a;=q{x2+Gi2kid7 zf9qVQhdcM(_hNHv^HcqK3v>I^-xcZ4^ERVtttV ziqm_Wz}8r+HtXcb4QF%7%WLGw%^lna-h{cfeCyL=Tfp|GoW!<*jT_7R+y=Hk&4qVA z*mz^@cIL)gvE0K0;KuXsVD9kz<{re1c{XwOd-}>CeF0l9I zh?d=8pc%Oha>)BV&Ejy_rjN?v{Pt&f&HV72&;qGd1Gc(gnU zcBsYNW0*0uh|`~sgWXFV$?KzIU&*UYuC;RWw)NpY0d{}izjdyY{(KT_|H$z>jKx2N z*`HIe^ykxH&$Sve?{|F$??`_>3-%oPoPR&q+Vtlj*x~uj9l!=L>%^YHb)6eee?A9x z{}#;s^Ua6A$tCuDiQ$I(^B`ERIkmrlcc{bMi`XH|ee1aX|MN@4tg%*Y*2$5Z{(QOQ z~}gD!2`klh|uub8lhBJexRsz73v?xu$0eN1wC3Q}UiyzV*3_cfsD5BU;`A8&6NXZ<3)Fb01*F z)FO_S55eu2`>7=yeYAX3^6HaseYAWGR*UZ_T0Q|AkCsot4z-y33^S${ar*Np*uB(| zygoWUFL|{c#jKT^x2+HN7}))N|JJ!q`tu90{Uay+`6aj)vv>11?^j^s^7FUx*I?t* zvGmb5V9!4WGw(aH=fB0w&B6RTd?tPrHWJ&w&#CzDN=$CP>Gvg$8;<=@V(t^(k0sWG c@8NGs*ZT>xUcPznb|t;pf;aacN|#{&11o81EC2ui literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_054.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_054.spv new file mode 100644 index 0000000000000000000000000000000000000000..a3aec7b62b5dfc4366332220ab8273baa8f8d10d GIT binary patch literal 3024 zcmZ9OS#y+C5Qa~d2{A+#$pWG5uW= z;uqjGzeE%$s(7AnPUBZO)=R&=obEpT^?)7i!>dwiOWpkUYigbKsU1s7t5a7YYxPU@ z(Z!|N(E|tf8L=jH6oJO9O{-ETvK`!-p1-X_ueNnC?G%7@6uHK^RKZ)0ui&c?GXwN> zA+IgpC~9?~se78&7aI%9OY;q?c*ne+3K7Kta z(Skpp`3AaK10TX~9r*x!9kN=WGp$G3tG3kp;Yn4A=MB0b;h~ErP>CW*zc(lI+>@A?*TrVTd zTZXG)5V3_MOJqlkwiao9mv0+lzCx?kS|ly82E7 zZRV6)Bi^W8-8tx2-XX8Ebbc|<^0)AA^fd|J4g5a#X#Vik;P$-I=eIZm+--gCwfF4( zEYf4|#<(Ba>`iGO+SHX%>m1x(?9IByx`X~5cpg-M`{mxN8y`Dbhr6TOLG1iHaP9W= zF47Y_`X1c+O8a>~>&oco0^A)n<|4QR^f}jF;Ew9+0s3M`KY;6x9sMx-5yedOe+0DK zgFJThW4L!?M?ZmUEAQy1=-LN?Z~F}Cao+kq2inXnj~)F2?wd9O-yAW@c(d;`#-5D# ze(dOFxV<=6>s~>6tgCMdXtS=|8u3Q$>dr~OGIrGY#XQU3!n@JeRk%Cq_pwLwhi@8g z&ntZc*sg(H**Ajpp1sc?J@#&l`=QO=l=h)bT^Y4z;a7pZS=ZRu(d%$`)E#t3)s2sR zya9J_L!W~i6W`}1+!*bVa~^Ka9l)IG#@XMONc&UTpL^;5TWkgP+zq}0v6l;Q{X2nw zciuwk_c#arw}E!^%A=14+&;V?{eKPD9{cePT-#>gjGIW0x%DjqZRVCoo+Y?>LSN2$ z{9E-cx-r_Ffw9`0LF7}a`yTTvW51k(efNR#+wFkI1w0At+W-In literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_055.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_055.spv new file mode 100644 index 0000000000000000000000000000000000000000..2da1375f5c055283ae8dd7f7e3105ce9b8776429 GIT binary patch literal 1220 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_057.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_057.spv new file mode 100644 index 0000000000000000000000000000000000000000..2a0f4897c3ecaa0490112d50bde4e127b23726e3 GIT binary patch literal 9044 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_058.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_058.spv new file mode 100644 index 0000000000000000000000000000000000000000..3211ec203c62b349061568e576b29ec5f9efac96 GIT binary patch literal 3172 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_060.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_060.spv new file mode 100644 index 0000000000000000000000000000000000000000..d1fdaeccda380caa4422832fa66fea2e903e9415 GIT binary patch literal 12388 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 Uvt>NBcFvz?!+PDwIPb-O0U7KeVgLXD literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_061.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_061.spv new file mode 100644 index 0000000000000000000000000000000000000000..de10f68b28ececfd7da218fd5c0070b822e7f1aa GIT binary patch literal 9564 zcmZ9Q1+k-l&aTS4Y6&^jj1;ft8e`_{6SdvkT<>&*0^qbpnEWAl>T!SXzs}pzm9gGd`@w*Y3!S z&UUbUia!eMTa52VG0Y?^}?wmOb2sSyjvT8HpnE#xmu~ zncQ9B9m(AdESKq;T{*LFRs9a%?z?!qW9^@B)ZYisukSlhZ+!2~?>fG5zp?oC&Tl%t z`F_)-Z*NN9@3ZvnrT%#K_sn}R?aAS=1F?J7oV>%koQP`Q^f;z#y-U}dzZX;fDsuG4 zGp!-NH{IiXlcPVO<_2RIk>mTC$ehr!YwGL^w)PNa>g)%W zPo4e2a%G(Z@a2zSweNEh)7tXt^*-dp-i2pQVC{ zOlz!Wuc6o}HRreZJ~{e_GOguWan>FNcCCFIhCQ6=w$O>b1laYD&H3GmeQ$oBV&7W!oC zV{-20J9aP6?>j%1sjj>m&vabPKUeqn_?mOwJJdJ<>#*0xPGridOPty#ft$5YhLgXf z?%xcsTst%CP64|vZ%|Dg%u|?`)$3-~oWEl^_bjmWjOBi3gS}s4>DL^v{EGT~bHQ?+ z&mQM2+PC;JePi>Op4Gma?>X(osaS`-FlRnf&R&SK=V@SjAFZc@<#I>H1 zXM*L+dpZl>`o?lkXM?>bW9ivBVENqBxnQ~6Q_iBzJ)H;ktoF`)&*?p#k9F7!b1q=Y z*$Z*@yb#=ocEOV+Vp8TxY^5#;pFpsbqQE*G*fMtVjXHTb{SJnZQ|6v z9NesZ1)O~JUI~`-4zlhlaP#e44JV&_x&|y)-qW@C)-#rSx(@6;8B5Qu2g~Q4ZUD>W zo^lp#?&(IbXSH|cdro_C6V_ob%(Pm)J!QQ%J-H3s?8)tL z^0}uwz;dIRYP%EbP@A#4m~v_pr}o`oYnR{CJ^1p;xwprjWWXPD12)gjKmYj>*g+Sr`; zxjIklziU@wS1}#xc^+#WZS<@LTO)7eg%+-=F<3R|zsR(fYsG39fX%)y)iJI6zKnf^ z>2Tjyv98r--`Bv_$iA>?abtS6zsW@^D(fTIpIDI zmLJ8;8+`+8J!5%$p8)&z-e9KwC&BW$$4`Of?1}gIX{^H@8v6`W&a;S9=dwAT-N^(Y<~P7fvp#fKL*R0=Xzsu$^Qx1nyc!+4}S`l%Uk^!*x_3> z_9j!#bBNQ!pM#ry{so+T{$~3nSkBt^BXzX-4gM9_ee99>Z!-O6evNgg!<^qR<-p?zg~l!C=C}_Q{xf^wpNVJ^(lM{1;9>XZjyl zu3YE;aBy9zu^XIxGTuVy?Ws{HTH&+kH)pYa^-vLgWuG+ zHk^Dk_65t88vEf}&sa3BqmM>oYSb?^u8ZH)*dI}~G04PU;z+rjwO zH!D=+7M*ULb9{5d-d&0>_ zZ-0bPWaPs-@i$lP2 zqp7E!)Y0bqnF4knHJa}pem{p|9qKUWFs7V3#L;m$xT)g^IQjgob|hG??AuiQ^ew%a z1}C5QHytcj-tAHN)-#s7JsRxY8cVHX!1DPmITkFJ-;$g~n_e6T_N?~De9vhwj>kIe zg*hiMM`R(StY4hIB0hhle=i0l3+l z3*qGRTXGRtF25zIqs{lT9PB=7G~Ye^elEsFhdGxp<J z-2s*>`*bJ1wTz`tcY*DbG4<$|-@x7YO+EL($w$we2~qw#UDT>0Lfz?UyIK8bIAW6}5& zSdGTis9$P)8efg&{wv_*v;Q+-x$?K2|wc{QAT^u7Rgt$h0MBG^6{%et4q^7-yw2FuwWzol2e4!zbWZ+GVZ0n&?A A+5i9m literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_062.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_062.spv new file mode 100644 index 0000000000000000000000000000000000000000..503304c3ae6d78d8c60772fea61ebc2370732109 GIT binary patch literal 1824 zcmYk6*-lhJ5QZBD1Vja7lSQ2ocMuf;Q3M82#)U+T7hVz+LP(HFkP9x+=&kSK3&>Mx z)WpQ^JExnRCPh{KwRCk=ohdbrw1m(QTKRh!^3xR>K|*K`Co*1Jd9yP9aerfca_WvA zXF@4+)Tbk~geG_+^kIE_SA$luP9$+IKq_UqssuG-E&4Zek1<<2Ys-7%ezA#Cq%Y#yw?+u6+QW(r}gwz9nTzP?l63!w&Lu6C#cs>K|LnazBcR5<#o zS28X4wN{UDt+|-VZ3X#cLG~Vx{-<&=lTRPZO<9c>j`b4#%a1YE=;@{-o$v}+7hJgy z`7FE)^^>I=u5Rztd!lX+%ILjt+MD6CQMVUjqv*!=K_MK@>fev#d&QIe9I|H&i}?p2 zu_E;nI|x>WQf~Dj$YU<`VaWS?sQ5g5AhZSh;C;pwPtu2oxQIbNYb-}6G2f)_%slCy z3UUKvUCy=)d9c*+djq!b>aA#ng`WQU#S^i#i=PNeN%iRm-?{QClquqkr8*}-Mm~Rf< z`He%yz5;cBZbwYqW8c1!SDPQVc6a0tdGEr_FaH_$VFKBm@XmYCB&5xGyVvf3HuqoK zcXB)XDM-6J@r&A~;o3ca(Y4=)#JyA58fKy{Pc?Y2b?EZ|dI+T&{GO~qo8P0hRKqN? z_Ef{8XoqDrXxCrd8kFs$yJt_`yU+X|g!|jzdn!;JA9rdF690;i`h3LfXNq$Vt)UpV zfG(cms>ou-t&+>xEJEh1LZ2e`7}=R=dkf~gmmq7^_65vZ{k=-PKa7~aTjJI-&xW`+ z?(HJ>e)tneOh0?zd!9n#?u&OVL*6HDO=8Z&`DjabIfwM-;!N$cx_e;1DaBcs{Fa!MunPO*` literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_063.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_063.spv new file mode 100644 index 0000000000000000000000000000000000000000..75d9b4c47bf1939e2899b1a39d7ccc6d1554ea8d GIT binary patch literal 13152 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 RXwLI3n)*9n>yTT=e*h4X=Sctn literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_064.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_064.spv new file mode 100644 index 0000000000000000000000000000000000000000..0b902cb2c9ac39f910ebfcd077ed74ee4f9cb15b GIT binary patch literal 6284 zcmZve2Yg*+8HZ1Dv)ZP6q*bg5MJTisf|NFtwnNGwt7kKG-)ra3HgnqDP9OMH@QbGW1YoSNkccT}U2*uI_0e zc_jG!l&?#UK=&8NiYW3LlSiS)D+7ZAmCBjpV>^qZrQ)tZR%OlQ_|6`voI5cxfZf1K zl4S2--?q`>-fZ`)agT=2&(iu3yO6YDSH_2^QAmyi$Gi6Y^!4;^>)Y*tNRsVD#JgI7 z&!>kRInPoLGx^S};S;v?eT>cL9aW{%IA^zx@6ou&O!*4Q(NnmN4oSLhsfBbs2Hi&d zO0;+}5yzrik(yN3CC8yX|ME+SU6t}l(n9QNu(ti%u#ZQ}nbV5B25qh}ZLI$Uw0?PI z6*2nK!<=m25_UUWlH4|BpOo6o-S&Je*c|t4Ih|*r;KUZ1>byYrBTEh>vUa zJhf`@=+|C{#M;+`tGN&QJK%g`)>FZU4;|VVw)g((tCnpJ`?RWmQ`j3*yLZaJ37e-g z{F_sAa?0*Z?S#8kn{e17kz08Y`n9(rt|Q`42Pc!0-QnM+O+?r|Sl)YW z_hEZxAA$Wiu*5k&q6wL;#|g`jU>rrSHzu@aq^1w&PCfV`fEFz+$o&fW6+)h zAMeUtSWiMbt7qNslk|~W_agFFai3?aL5*+Cv;Q zUjnvAyo;BDeHZe^_-%d}A|Lk4!LHjgp#K$!oN=)ya<0oY+EX1pUkSEn?Dwm{a$Awu zH@W=2IeYYfHQ4@_W&JM)%lWq<`pZT96=37NtKOH_AaXvzy%sE2ljE+;xLWiMPVO1# z*CFN`uYU_-&pNced#SJ<@$Zg%Q;+x@kE|o^ICKNzp1d9%d-8^ik9&3%ww!Bp=Bp98 z6OqVyBiLGz^Cqxdhd-O@L zdHSOFr@$K#eZhSiEWa6v`kw*k>tBy;oP5;(ELh%kIJ0L{E^2%Z>^j2!JlL}kGk*ar zm!J8I*yibr`ECF^v%cWI1ik^u&-`WV{LEj$HcsC8yeo2I?@4Edy(8i{M_&cUd(5BD zufglPp8f4Ye;w&WLIt0hWvS?}GF7zK1P$6W;-6`#xe1 z^Yl5B-xhhX-<58}wcd<&Pt^V{xCQ+K#7F-R(fZZV|3_fw4g1HL9p~XE*v805%um72 z9QMyLJ92)GZH#=}!(V`{r7zy|FTwJjHQ)2E&_2FreZNNJoLTG|T$8qZ^#2VwzlPst zcFglTY-8jj=l9_J8vc;kk@H7vW8~vr{t0X?eNpFDu=g|8`Dd_k^1h!Iv|Pmh1?;TR z=dWPzseHuz4eV?Y^LMau@)7e7u=g(d{u6ARynW4=i}>5X&Z5u$+WI_W|3Wz{}0$R81erF%SF6CIp3G(&-bN{{M*6Cgnb9ta~$7^JHgG!T4Wt!+$!{4 zh`u;KcY{yQ_-nKKau2q=vzQ+<{ts*){WtPU!FB&1kvA?Re)rxBcRON?=TZA+ez=Sc=L^M<{4-oXVy0pnT0sBIC?aL?dg0=(b^q+-&ccY zgX_`q{{GW8-#X^|uIGT8(6PsJv15-r;3IAxyuSF`Hy>=Se8emO&&btUh#j@^=W7wX fzNobrY_5F#eq92#M<@04JHMRsyEpe|zu6xEa|BRd literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_065.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_065.spv new file mode 100644 index 0000000000000000000000000000000000000000..437e45b06e2f23399361fbf6a1d177957d8444dd GIT binary patch literal 7184 zcmZvg2b|Ys9moH7$AN5+C5m|Gp~yOwJr53)qr!w}FG4`XkSm6^!%nuJy0mp4IDCckbM^sdM(6Gb|WZYpK^+GrTsS)(_hZF50kly9u+#M!<}-0Ia1x z*D{(~$(Hr{t<;>i`~3R+{prwmY~6n0=8e0y_HJKy$<|#PFCgB+uKGqR%(b>`TfcJ0 zhAk_4dv|Oy<9x2kd}r$S=RbYNj?FuJx9xU9>smN<-;fW4c7xXX47J+&p4BVYZ|vRH zyQ5ZHRgd=7cJ!HA4?XVFv-Gg0`#SkZuFr2TeD^vS3tA5(1H&;!uzq?T5aMHzoot>UHeBA@sR~Tw&0@*KDyvz3O=^tqd3tx zcsp|+hn0_okH@yv{eHFMvHG5U9J@QA^3`k_zPSmYR@<|5I!c>A5f}@`Q0JN2fEwAS ze-e0vF_AUBFV|`#*M@aHV~Z-^J2aNwcDTd2y^A&-hIxJOt_e8bB&@yebu{c0Z1#RC z{LVX8ccpJKzQexLu-?0US$7KDdDUWSmGjQ5pH}6JyKjAUvfeW~SI#&c?w*WUtM5B9 zmbGTUZ!7#xxNBvvr^9E02}J!s-KR14;s@s3#xtL_!u%|(`^wq0v%xuCJG)aq2j4fO zZ+}?yg!Me}3IRaHM|$z8Yq}g>b*+_>16+3t#THko*$(n!@jbPcHnW@J)rk z4E}<`?}lGp_{-sY3x5UthQdD!?mcAvv*GHfUMsQQW$sqryD*k_-vd{pU^*|@`(6cn zXJRffzccUI;dgf!?=e{4f$OP}cee!J^&Sgc=Uk%B_qZx%+~GZT^X*N-t_HrNcF+Nw z!@D~Nm|Iir>G4&}_*GTxT)1SkE zn|b^u)&uX^xx1K0-x~LqeyzS5I-hn=wKuhQzA2!*E6=9?9IQRs+}$X+cV~^?*#?li zI}dJtCh+byV$C}|oB2(^xbw&;rVPJHLwO-nQTy%X$~UUC+2WZpAuW%iM*) zm}|*BQ`R=Vuey)t!kx!+InOq%!+FeI1dKV4{IW{Fp>X@uFL$yXJ`kA8`|E`pPtEh- z*4Uex=fjO(%G}=d4q(h)@7A0#&yc-n_0`zDX>+&UP4-sarRTqfHT)T{6ZpN(21EGv zjqL(W!0*Vsy}Pl_uk{`H`}tzv?`Y?{1o$&EZ)7yw-^=Dk0(1FBUkL9H)Vc%Y{4au= z%U!=1ZtVK%j$Q(HUgN&4mtvjQ;XRpu88Gf%U%JM1u*U&YRqUBil6ku*RFqfaXZ-Sfm9eAH_#+rAy2lM*I-Gkh3!!=#Ubw$2K=g)fO zUhU7@ehXYZhXH$|&s*W<9ErURp87SY?3;f(P&4bzyG}IH=6&sftGD-Wk9)Azx8zy0 z`A$c`eFy4fP2Q_-NZ&VZk2XDiQ=>t8c2_mN{p|l8@QZ=xP3)ajtQmWG^)}uGx7M6L zpJrj-4O&14$eVgk70>tiUVLK*tM~LixUo6F_p}%5@Gi|=3*HYri#%`m18{%Vw1e^u ze-PhXerA3MJ`i+*?CHaB+<2+gja7}gQmfD5M<;F0|9QAM`=Zqs;L*x_ zYHxz8m3g&N2hZ%;qtzGTYPATc)y-IkTA8~A+zRZIN2@Qv8)@}r;^v~&SKw;37(}bD z!i`6(ufdJk8?C+$H(qM>jjG06snu=xY82%B-y~+vzG(F=c(gK~+S}o3WnQh+!86~A zjaGNS)oKY)t2?m{wKDf@@Eu^EJX(Dh-bkzO5jPjDz7JQcE)cDL05=}3eh4>aZ?yUm z+<2+gkE3o!K0P=)ZPVGEAwil4xZVwN2{O1)oLkFt6yLp zYGv-1;8(ytd9?a9ypdLih?|R6zkwgE)o+Ozk5<2f8#@G|)$ifPORfHZe+ZZ>wfZA| zBdz{K+?;*U>d)|KWj zt^P^eT(tTZ{AjKIP0V<-`VZWgz0vBwaO0&`|Ep@um0I0{-$<)_iJP-8THObaR_3GC zVYphES1Wb!%$_}3-49o*ZlG2VU>#~@?m_SnuumSX9)>s4>i@*eMXN{PM{DI~jYq2{ zHxKNMR?YavORZX}8gr#q{qP%U)k@r)ebK5voImy7gXW{v0JvJ2S1Wb!%$_}39Yap7 zmIJjKi0@DV1(twzF)ms%ZL)tD=_ z8in6TtI@>G*%z(G!1+_x%6zmM3s)=iYNZaI*|SHhad5R-0o3X^e1}?@8xM{L_Q|8w z3GhZ*O(1SATAc`2tFu6UwofExJX)OuH)e0NYJ(duwQ8?w%#~W5jNeGB4&vtQi&m51 z{HbeYK3bguS1a>sr4F9ivq!5_;c7JlsMTbAhgzA_KMmL?k5*IQjkKCd++4Jp23M=I zLA07q%y_h#0XJrEwCaQ#FSRkFSYXQ z57FWI)i3{UnGIK8-;cd&Q@%&vWoqZZeYbv>_BoHW`OdYeol9;2c#xQV&SPzUeri)Y zkKAE=e~;MbJl5v-k~X#T$={9d?`Qj*$J+e9*QRy>`MdD_dyjq2W9`jYbkG1=;)@oC`i2P0X2Y`LfW9?q7wc6A!Cch8=T40~^tgZg-vIO6}BeAY3W;n5> hRjirV8vYGF6}ya>{nneGK+OMV)UV1t%w5k1j{<9utUv$& literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_066.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_066.spv new file mode 100644 index 0000000000000000000000000000000000000000..5585a6f8d47b1063b99c35aa45ffc5fb58352347 GIT binary patch literal 3796 zcmZvdc~_NH6vkghE6YR>E72}mX@X?tn5hs6R+N^_6M-Pz0xn$!ZBjB#o9B6+{_KxF zM5}Mqv{tQtzsuS7uDdv_z4o)8J)FJId+wpGcKwnptI00n@26~GHD$FhS++E5tmyuM zBLiL2Gb3Hwwr??FSyopGH0JVbNmh@pMJ9%dlREUuEeFZ70jRE0tDB?-y!rSBm`$@=7%3D4^32TyU4P^ z{(-*1qowgu*_sWU1M!n1qbG)j$49~aL^*?dnSYR&=yg4|tDgut&&hauUWd5CZeK7f zw)?J4b~9N`;C5=PK#NyWqZwU5{BEnTThMauQNUh__MGM0v0D?CH-8nnfVeu6eZ_)V z$-fe8zBTo$uR>fc?6Mjid2L|(h`2RXwzJq*D>Gb;E+F=-){dUr!R}c=^m|77Jr8H{ zJZlj7J<0a$<<_P%E`W`_25nu>-B@kUJ@&fx0$zx}4%@xm&pFf^5LQpjwGqR+9rpEL z?_AiM!0s1z2Y4iBcY?hm;ol7QKG|;<+F4>YZReIV-tTn-VtgC+7PPT)`tA2d#1;0| ziZ#E#lgW&|2{9%_f5dJBvo6GL$B@g%Mx7mr55IN7w=?A}=G&F4r$3*!JLS1wweRMX zCtvOJeF?tWcMCrESZs#9i4T9imwhR3G2i~GdilKWl;?i(d0!89p3nPk&Bgzp*IfC= zz4-iYeh<&x^Yt7(FVDsK^*gIG*}FYB!uKz4``(6ayl-yU#{2Gut>528*!Jo@*WSy1_Sld3TQ~$; zKp#Zp6ju$>!yNvuZ%6#C`(Bw}K;MDLpC?B9PQ)7W`>5<*a@O!I7(nEF6RqLz>n=q8 zEHT=5CvF3Jk{I8}Ly3<%hq0~W8yR)(0n107d%<$~I!CbO53^Sb`aZ{Ss`V(?diw0g?=Kg19|Kp{ zeH>0c>OKLM%l9*gT|LK>aPpBi1eVM9GmLFLefH!1lk?1-=_q24XHx&Z%W|8Lh#3W& zH=kmTfsK=o?=S|I_ink5_gYTuotFQL-_BELe?#iu>7j^z8gc1=2CZKm`;UXI@eBK} zMo%De9mwC*(4IuBWv~@$IL<_L9GgGuZMm+bmel^ZJ9H=g=>|fg$`;R@;+ApHrQ|)(q34IcA=|6?mua5fj;HV#G_%fXQ&*@v92FrCK z&ZzwgVtwn0quv>Cb-lB2@~5fijISbcn~}&n2aY`F)Hcq(oxy$7`8nM`^3Q`KKjwH1 zPTqRU(Y=WA2hgu0a>f|H4*doqZ+v~S|KWAsh4_EQ`{-SCwIVx-^Zjo`?C(u<^z&BY z^Y`d&IQcl&cffLSkKP5lJY#+DA#&ChNA35)?%9UKtRH~oZth@ zxVq-oaPsHUJ^KbMw-$-KZ^6}beg`KXy?hUrGe7cv07stpL)$pd-+S?6^8ZV}V(-j< Dr)~`n literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_067.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_067.spv new file mode 100644 index 0000000000000000000000000000000000000000..763fd34f600410af27dcee7ea725fc55ed17a554 GIT binary patch literal 3716 zcmZ9NXLnUq5Qa~3Q)mW|s+m}n9=iEJUFV0=>ns?rrJ$rUJ=T;h5v=&7}F@@i^Mg5swG@=y6^rEG-y?ujy zo34+KY}&DNiy3W2rA#zuX3<(SVH?5K;Vah+7*(4EQ)dELrL5J(pk|_ZzJ4<~=Wkpp z>$fnkzR%dj>$TAv<5y}_Zl*>{T`p@_cVu{cSgDza^Ijeu>KPlpe6Us<8>#D7FN&ew zzMi2Awb9yGQ5+^a>aQ?~r=UEPX!f&s;W$u)WPo3mVWe?NwX98;ZyE%7+b{hWxf4a$2woc55Rq*UKc#C-;KYW z<|F@{KIwkzy{t@_v{ETM;MDbPr-fn z^XFcsTuE2+%ftCSnD}Q^mz;( zeQKl6LAZT6?m4V=V;+5bP>b~+hZn`ff$*QN`}<;^6ZmR@$UBKP?WgbehJOnG{=F%a z{%QR0+J5QW#m(}*dbU2^-#_qPz`FL>E7$iY`k55h{>rMo4e5;EwTL*HX?)aP^zyIOYm) zoO;xL8E$Rg%c%VdTs>+}hudRbdlX+iYF~vrPW^W(Uc>tQ4Y%(aaQ)hA^ym6#0(*-6 z@P4ZKJ&GLvcdQ*b{`aVv)6Ki-H{?~&0z9L99j~QW)S82@7PaQW)$&?n_)#n0@9XHs zqSidPTGW~kSF_gLbS4Yn>RllAav|Jx8jG?1_o;V-80&way5nQ)BDlKWyvSP&cO6|I z@|M8eCu1?kQn-3P$1;3%=kV^2V?85n-2H8E_tkS-4{m^nZG}f{-2<^LS!~qAaP>VPdT>wF7lG(?HM|St{jb4SxBsZO z7OtMxbN|&n)0o5a^89*${d#uxuZ&&g5OVbvzUI<~^*Bdt>Z<@By&4 z*13HD^^L{%Xaa7XJL!9L6RvhL({3g0RHl8HwA0xB^nZLC?s)T!=X2WMzePhizkPUL zcVq7W$Jx^nV6T1$2e2Q3RxlOpXN~&iTlYNHwP<7CX29c{XwGoT8NuqGO};k9_#YMD zXmie_oFT0K-Q;Vd=X>yDz?}QwV-WA(M!4^vu{K~V&g>Jo@j>8w^eNW3kLPAwU){CI zV=q2~yBCi4Kf%5G9H{%f*S8mYQ;+r8gJa?@#d@5>Gk4qLm+F|QMJgDO@V(xYy!$2j#94eOs>{%aQ-Gin-ZpJPqF zj;!}F^u^?HF^Ga~jNJf|{1tv-|zh}zoyz|+r!14#4a2SLO+!w{h7!Z5cygeIrI`Gh^f z4u)|U=N%8{AUW@-9p6I#2)1|jF8a0IkK8no?$!Ny-1B#=Bgi?T%sC2-U1lHd+ixW& zJkIr=I{JIb#UNP8&1kP(Q^8>x~T>$!>V*=@M4*82f&NuES99Pio z=A6Zzk)yPyF*V?Cu5%b~y|~9Cbp4*-9;3^7x8RmDS3s`hx-01B8?WDc&vTa+q`qHN Hm;t{5D06~Z literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_069.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_069.spv new file mode 100644 index 0000000000000000000000000000000000000000..f1e7950b63e26fee46f1746bcda1de9b8faff9c5 GIT binary patch literal 3740 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_071.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_071.spv new file mode 100644 index 0000000000000000000000000000000000000000..3eac74aa43d473baa0a994b4a604603ba5610f1c GIT binary patch literal 964 zcmYk3%S(b$5XC3orTNIx%pN{^EDC8+5l9vYejA}hi$e@XjzN4{k?61&hPWy z@X9#n%$z$jcfM$(nKWCnlzvAxKLv{@VwSc<=!5=Uzx6g7wa(5@QDiL|3en^&X)*bT z>}B}$N`fr0yby6U5Q>JiZgeTG?4mxdTwI#jA$s~5;LJy?rGIu(mic;{!pwkO zs0VvwJ`Q{R5v#~wsS11G`>+EzJ+@@jzST|UtGXC*4sZWl(tu*`?Ptg^9Dvj3(kO`!edY2l8L8 a&w(&GcIV%5D9k&^b+i$7PV83|E@gkM-6`(? literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_072.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_072.spv new file mode 100644 index 0000000000000000000000000000000000000000..e24611579c4e411573a2855843c8a297d85f617a GIT binary patch literal 20916 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_073.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_073.spv new file mode 100644 index 0000000000000000000000000000000000000000..b7e915be4aa29f7a14fdfbbd643a026a90d7df97 GIT binary patch literal 10108 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 J9aZ)n{SWL!OyvLo literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_078.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_078.spv new file mode 100644 index 0000000000000000000000000000000000000000..4739a9ac4eda697df919093cff9d1f4436c3cf5c GIT binary patch literal 7136 zcmZA32eehy5eDE3kESTSsqlCYM5KtQfFwo*K_EzC&=gY%iV_mw8A^H~1QQZcOz*vF zG=}uvd+)uN-h1pZ@&7JoSZA?y*8KC&?AbH3_qmUr!83<>nE~Rz9_ii?*lsj}PvPSoX6gbge_SJ|=eU zJ4g$2I)a>^nZ#9$f7^Az0n>)1A7eM$}H`WDasoi&VTj zPOro4x%l-;7{)r3df8yxohLvfT|%E2&s-J3rlun-#&erD9JC zZ&mEbJk+XJ%R9R@*1Tx-Rvx)-$-eo~)*Zp_ z?v#jl`s~E3e?dfl7p4Ml;nar1Tkc_b&h=gvM!YezwO{;c5&ZtduuqT3fnOia%+845 zt*aVtQ83;c+MZnAz~TtL_ALpvPYt#2%wT+b-_qFl+tS?H)7WIpOY!FowFx?=Q@kedv4bz7kgQ> zoU~fivpnK$i#ac{BEsi8SQ(ib;X6N4K4-0pIGb;Egik+f8XVO<^PbVpq^r)g!S<`u z?B%;4;ymm6W>)Kh@y_wS?iFpB6W_ffIQikdO|A=r?dy$H{`&;W?{4=saqENezTc|t zqG0>^YVH>Yn>(L(sNVZV@YgoA-ml@*YSvX3U9-M_u)57cyqd4c3zzQ!5q>j~qw2mS zxazLCJTM$yoVh$G+AI%ACx(VrXZWS1TF+0^VRhOXJ|YGRx#-u{~1?qL1) zMV$MXXv?{LkB#7*3)i`i3qJDQJw6=1J-a8wHeU!1vNf`KAQxMQ?mBi||!_ zFAui2>U%}wkLuRP|H=qneQy6*h7!S?gjdwgB6_sCc8 z@%6#@y6ZOt%)n4cQw0r2IJQ?+MV7IY`IhZcSUf{h3jwb!Qcxb?YH*s*q21wJ-#QlSib7< zy}^3qtGD*PV0^u`_Xp$D>wc;R+PiS~ABd>YJjAO{4fyt|W@5f| zPag?BvWJg`(<@)~@UdV$@VO_pJeB+7!S>+lUOo|wZ|C`BYQiYo86aXJy1P)0zog-`eMb#h9}_=2gFQpAR-KKC|Pi_w|Kfe)r`L zz8Gz}1HLasaP9!EZ{^Fu&h)L+zXQJ#jIX<|eRSRZSA*qMyLdUB`?YAxxnjN^!8sSM zbH5SnT&uWm23IY0kKYQ1Z@=?z$Huqc`FCQ=$yaaWyTR^+uip9hg7NjvzaNaNUaMBR zdi_DLUi2?sAA0>^w53-uKZ@Y=3Re$54t6)*L-qQT;3ND0X~VgT`W}83jBoe)^Vs(D zRjtK7d2mYYv*w%qmI{2^GLdKbQ%nlWA9%^#Z>_hygz*LU-$VDsm57ku^I{5hE4 z{kzk@L|g8Z@2?S@JB921{ub;^>tOR6|My^gUqqd?kFK}$k6?M#E?!RO{xjNgu9$yC zaL$G6+deOgledzVS(UxAt+!?{?6|Oh?zhHOcJyc)+53c@;^W%kU_d19XY4@nB+9*&7^u6$<9SKq_2@$tJ?cQq>5a#wt#BRF>j z*By)rc4q!R{5_0~f$s~a&e})U8yOcYuiC}S>D=+rmUG2Sh~S(H*SQmeoof|0so~Hy z>&Y?j=3l>mQ)1)WZ{)bxa`M$1IX>8(@YVNlLNLC*hpEB1`W~uQx_X@!tQY-@*N0wv zqbqEjM4~J~>!!KDpWL+;d{f-M){xvGMKP^J2@*SGng0%grY@yZw!v5?da#%KzQB zSM#Ln8(GlAxFdVa+B@BsJ!Vf=?D@e5B3DQ3t30D)ua2y3eAh*nZ%Xiak^PNtdE={D zo|-&M!?pWe7!JQUeD!-;Z2j`p`#U`tU+?dXV4OL4Q;UKvZ;Eem1g9_9+=j$IE28H$ z(R^aqD;k@YLm$f`6-U>*UXnf2V$0hfZI2qxjBVL3W_~cvIds)9JG?Xb`RF@yb4w$4 E0lGiL-~a#s literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_079.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_079.spv new file mode 100644 index 0000000000000000000000000000000000000000..6553ecf4f184bad2518dc20b4bf84da393e13d82 GIT binary patch literal 5548 zcmZveXOvat6^1{i35xU*BjSu$PzaF(DI&}rMj4brshVOkUS|flQZ5;WFqlNgmY8Bm zQKM;UiYBJ0>86?9Fuhk(SAOPK+FB{kbMD#0msuXzYrp&5?JN77JIzfCj!S7mn#jLD zr^YiqHNm8GLTW2?Pw%$gB?pHGmMlB(TqCBW<|5FTsp+`Xf^I_gRcrfo=#`rWlBWTv zxu{hksTFS?-%6iWVh+^$_jK3y)`u3>mafKbC8rHtD{yO3XJ2*yz`~tNSM$H9GZEiN zcfCF|(5O2J`$%RVkG*@awrlrr!+!$y)rWQ#`)H%Ow$ISu!TR1q!?ij)ur=Uj;)DIe>Jr#WmCNP%0^EOc#n zaH!f?M&X|gx2N#8q&eu3zWsxTOM5Q*Ky|2UVQW1L-8ie}bQ1WQf^SLBMh{ent0>~y zh)ikM-oEui)m`ODHTH2b{IPm1Y2N?Y&FK{EgNODNz2<}CUcBqRp5FC+{a#*5J#_Hi ze8i_VV1e5++)?5URE&FAkoo1DlOE34`#5dP*RUhs9-f_#*faAHAIoV@dF|61Aw|p? z89p<^XJvR{hCOE=>!00#1@_E+Bz@Uje_m*M3Z_AY%~_lgEA@X8FY%JBJPxP_ZZDe`A>TfVm))VTmHo=wCW zbUQMk&@E{#+HZpV9AY~QKBc+DR>0bxK?imhx`LR~j=c_Tt}z|VO*guN$SaG8(RU$| z(uQ?mUsTwC9kbUL_T+AR_JGZ4Lgv%ivzN2qhLV?CUE0o~vDS7E7b8CI^%8Wu29JL2 zjmQMVdcA0K?HB${V4qm)rQoNI9$gdmW!U%Kds1iEn;ZVMVQ(qy-ZB4HY@SN^w-x5- zn7zHQkF9?P_Fp*gS*+}GuzBw53dD7X{Q|J}t?j;Ei1@9Why5aS1(9=~FGhP$@}BXP zX!mTs{+FPwE$_K%d*^ccUs_^wwENK3t00T{x~Q*0+)GHTvkK?Bw9UU7Nolkz^7>0o zUa|fF+WxT~ZPzLnb&3yq8tq)p+&SA#h>x@W53HSN_u{Pjjc~nT`)vr@v+0Yf=A=wfLLmciKn)HE8|nHTb<}zhTyRjD30k zdrHpx{ueRYdl74yE4HtDioX5^=~LU6pV3rDeC&GwtzR8|&jDK_`o0V-7k#z)IVozH zD~{YnU~_L~&F*0_VxD}&_qh*ZWSmWfo;G8jk#J%H9hFz6f`CXUGdmX`+k6zb;tt0Qf zI7{{yJ4gCgmG8_ez|Ng9`dpjy^-9E<^o-2YHrBiI9zB0`tkd5Z*BNKK3@qn5V>aZ> zcP7ktCbXSLZFSW1w<*7?<=ApjPoJFmG2_moy?i&WDzWcH%;c-U_E9^N*P*XRe5^By z)~}9rtN>dhX7UEGoZl4R1??LVYndyK+?8N+<4kV?d#3WnRM0mg@?qZscKzOE1^sG7 z&bZi{oa=S%_EbmDRbYF@J)94gi*wT_XMUWAYmfe~0o(u9vj44Mxqc-2%SHTa!NzYX z=lpeGIiKKO50;ydac?NOCiG?|@JjS;i226r_xozk7PP*9Q(-0I_qKxFiuiOPD~MZ* zZbLki+tG0*rb{AMlMG3@8erbpL5|JwIk@Spd?Egt@W8@>|i(vN>_LoXKa=wghjC{=9SHMpq`kr8JE=PYA zk@sx>&N+My?c+|k zv*`O1uyOMCHD4~`e+qUjF_YT*oSy}V^B8|4oL+KQppDlj=lMH}-iJE!&j34rk$)yw zF7oxs<@4=5M*dk~d&K^76ZmOlJEGt9%ej8f=D+3NLH`4aVEp0$ literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_080.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_080.spv new file mode 100644 index 0000000000000000000000000000000000000000..802375b4045d8bd587d0835a94958f1ff1c61b58 GIT binary patch literal 5548 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 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_083.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_083.spv new file mode 100644 index 0000000000000000000000000000000000000000..fa27c33a17d62a66d52e5977ba0899798690e9a7 GIT binary patch literal 4328 zcmZ9O2X|Ff5QT4e2`%&_V8s_ex~OzSnkWH{ih{j_6oS!^he^P$D5BUK7O-Ijv3G3z z0{l5H%UZhpzMD62@-A!E*|TTQoH^};7&sv(-{Yf#jnY40ud z_08{?xvO*jat#W;Ko?ooTE^CD%W*9oXW5QYS5N$05 zGDf{x@IbvnHVWKc){JJ{(b|^xIwr@xt=schHET8&et~u3x3%Zm@q=R3*@QuUA*<7G zZ_Ty!gJRWL!yvzqP1G;-p&iODWZAavmUX?Y+t!v!y&brDjY*7cJ3I4p8H!HduXk%- zse5OCSBVpG4^JDQ^PJPcr~0qX&ZzLutnkkoHq*3#6xuBE-yUFyxUCK&s3FWsB< z%o2S}#rJDMA?LZPx1TAPU-*p!ZtgqB%r$3=X#=QFw=?z>uj_dWK= zOEZ86=60S7u>}hjtg<)#`Pjh&2UgBy4~xbyHS(cZ2gck;j58%Ef+Dm&RDm;dmM_Ho>dxC z^DjHI6!Xlyr~du$n}RK&W+S72Hv+ro*1eq3{hYyg1*T>?=Kffx8Iupqm0)vy%b~dn zEWfur_tjwY7ST+3EC`IxU0Y@U4NZ3A07?eh+N`OtKM zE7x)-oP5;23v8Zztfd?5oW^{k-U-(y_C6S2#?AIUZO43@YK*DzPRU0fJ>beSEy2l$ zW(T-(ukMDEk6wGh=E+B1AGq>N`{Cq6vlCpoSG(ZkqxL;u^WHYZfp?LsYxt0gv;*g1`P zM!s9uC-%)6k28H7?3t=Drp9+KAHR`%!JhLml(QJ0z~p9Qp?MN)UTF4#<>gyQg<9>b)_I}1&_yR098w<^sVDm!r6^s{&Q-!M6Q7pLz9 literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_084.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_084.spv new file mode 100644 index 0000000000000000000000000000000000000000..14f7bfddae6539e06dd35344b0888b84201b315f GIT binary patch literal 4180 zcmZ9O_j6W76ozjI2`GWkK|xFa6$P6vYxi6npQz`xBd_YdqCSb5~= zzLl%jTxrI%s=ZD$r@NX|O+-&X4h;<-HegiWbdY{F0JYb>`Y7rk+RX33(?QOmp`)Y2 z#|DRhbxtRG&)EKY&rZ5%yOK9Jc6eC3gWm4pveRUA$=TELb&^q42M!Ky9UVHbWn^S@ zU(4T7o%3JrSbWYt*gvp!aPP>$k?Iblnm%Wlj`Xvud7ibO9{Lv} zuGqaTv$maa3esK2+pBZW#@cJYraikF{;3T-t%2>~GT&KT;u$SiX1M}vuh~rD$CI8{ zfmwalT@7$gdpm=+T{2Q6de%i)bXKc;7oiASddSrbO z&){l9oY8vsH%IK=^8Xjn4QOXq|IS3cXuk>P@H~EB8Tt3MEGO1YMV>&y$&+B? z;bgSLQ8g#V&DU>Van5@L?0Kzkp7$uWv2ZsAmOJyp$x~qcImgpr&!Ruy<1w(kjQKs< zQ(yS;EcOgPIlHsUh40Im)#FUsi}qbQYif3Z&GFq?^GvbTd2i2xS0LsbN1j8%?E4FkC621OHEzCsXAp<87r}C7eK;Ej>rc)J@MNT!a}ryBcs&IkM_T^Y z@Az?S&txoII=g+sOL%a$^m+;GTeDWKPNSV$9X=L<<-@w^$jeChcm-@ce4Ht9RLzHR z^Yz;2kJrHZlk+-Q&YC%IVC&Br-UNFN{ds3^f$e3?cVyFO$#@(vR2-US<9hWPvW9@@Ce-%sQ3 zBl?|1>^>h9Tb+I8f!)WPS;&V-=AH?5ALq{AAAzkg=H4Hpt#P@xac%wXEzWPmCt!ag z>}ikO-KSt$BebHKs53D+lhI zy9#HXC+GMEoO3ky`WC;j%<~=i|MPs0Pk;U`{Q<1cTIVsQ&-?OD%aYjDl_t-Ew|x{Mg-T3z1jQhBXBwtuiSHa>Bk zh&Gq?fyA`CCf6vPk-Xd3d5;4xT!#?677)t%Tnn0%lQ)jf$(K{ijs#y``oqWlgX&&t zGk<@#wpR`QX6emZt-j^$ykKY83Lj3ehG zovW0}OO?&qZmsTIDeOmX;YOdI_;zondCW)7K@1IIu?yZx^Bj-xi3qnvn7j67n_G&X%??pbN(!ZR0Nx|hT05uGvo`M|+5Cy{0ju{Nh5tTDqHoGU)+B7R7^ zK>|M=Y$mI@D0%yY;uiDh*{Ts)|!wI1HUScv*TNXXB~1<6P)Fk z6lVWs-xen4m$0WPVL0M!PjJMO|Bi&3&Auzl8lS`Z)537X+4^wAQxo5RT+@u~xTe_< z18+6)PQY7D_9p#N|L4SW5757~#=P``gn|E_G=8-0`MxkY%w80xhM%foSo(p47~sp>DLnG6OW%aiF$a;@cmPUDan6jeQ@3Y literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_086.spv b/third_party/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_086.spv new file mode 100644 index 0000000000000000000000000000000000000000..a3119927b84db29657f40034fe07ecc35f1519d7 GIT binary patch literal 2476 zcmZvcd2f_e6o)Tur$AZCzKJ+(SrlqTb}W=upaWQ06>#lBhtg#1n3-bulNbmlej2}( zpTGzSiO=)SJ?71%cXD#h`JLZc?tSOp-ky>5DXmKz_&rOVwLSHKq_ipZ7rHj{U}mhn zx;S>`>`570Q*S|(Gnm$=K6DTA%lz_+0i$Buu*7MA)mzk>B&kBQ%&!ou!1=Y=M)%{T zwA7fLZp|-UZ8lqrxJ6Dsdg1xgVupTr`mR>J-E2HxU2f9dTK02kZ$LK~%bpvtmsjhp zc8(38f6MkJV}&gs!Byza4E4apODC#;t37 zCwd(sKAwH|Aa*FvYOdT}XzMz^TzzYc?Z)4Yt|I21$o?K|m-&0qa$}Z#*yhBn`?0Op z!TZty>?-22p8f}g*Qs|9TfX}-uKo}qIu(4+&Ux(r5n8@IW4Cf|J=Lp+Cr_#dO?iWzqwpCGRAj~Cv{E2Hc{ z?g>Ori1FZ#Vzd6|eu^Vj=0=^dj7Qu$5&JCXtra_2s%N~M_j%5Xq{@y`V-mre{zmD$alg!=JMV6 z7w-z%JM8=5J8QnachL7SeDBQ0E`OlQ_q_|gvuw`(W$HP@B;tSn4lHM$LMF4IihDD~ z6uu8%BG&TVFkk*vMEnmp`qvO^h)+=2`8!yJ`;^jkM9jCs8s4XAMEo@o{aVI+FIM1q zrZ+O~EY`V+SjRUc>fFkB)cFcutXyXXU;HlFzGYt{))seO&sWSop6_i$Ear8VI~fno z-OPzuh*I&#rjQ$>xBmRyY{T~o(TT44~f5djS*w;_kBZzo#e#Vyb zd*0_P_F+Uk^5(G3HTEX+=CS7xxp4+!?#n$oi#qx&V7sq4&nMVoM-cOkiIvaIJw^T^ qwsZcO``59>E+OW7SH=;)^91@SA|}ro-k&8zTz+5n-*am&ApZeo`G}bS literal 0 HcmV?d00001 diff --git a/third_party/spirv-tools/test/fuzzers/random_generator.cpp b/third_party/spirv-tools/test/fuzzers/random_generator.cpp new file mode 100644 index 0000000000..801a9ffed2 --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/random_generator.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2021 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 "test/fuzzers/random_generator.h" + +#include +#include +#include + +namespace spvtools { +namespace fuzzers { + +namespace { +/// Generate integer from uniform distribution +/// @tparam I - integer type +/// @param engine - random number engine to use +/// @param lower - Lower bound of integer generated +/// @param upper - Upper bound of integer generated +/// @returns i, where lower <= i < upper +template +I RandomUInt(std::mt19937_64* engine, I lower, I upper) { + assert(lower < upper && "|lower| must be stictly less than |upper|"); + return std::uniform_int_distribution(lower, upper - 1)(*engine); +} + +/// Helper for obtaining a seed bias value for HashCombine with a bit-width +/// dependent on the size of size_t. +template +struct HashCombineOffset {}; +/// Specialization of HashCombineOffset for size_t == 4. +template <> +struct HashCombineOffset<4> { + /// @returns the seed bias value for HashCombine() + static constexpr inline uint32_t value() { + return 0x9e3779b9; // Fractional portion of Golden Ratio, suggested by + // Linux Kernel and Knuth's Art of Computer Programming + } +}; +/// Specialization of HashCombineOffset for size_t == 8. +template <> +struct HashCombineOffset<8> { + /// @returns the seed bias value for HashCombine() + static constexpr inline uint64_t value() { + return 0x9e3779b97f4a7c16; // Fractional portion of Golden Ratio, suggested + // by Linux Kernel and Knuth's Art of Computer + // Programming + } +}; + +/// HashCombine "hashes" together an existing hash and hashable values. +template +void HashCombine(size_t* hash, const T& value) { + constexpr size_t offset = HashCombineOffset::value(); + *hash ^= std::hash()(value) + offset + (*hash << 6) + (*hash >> 2); +} + +/// Calculate the hash for the contents of a C-style data buffer +/// @param data - pointer to buffer to be hashed +/// @param size - number of elements in buffer +/// @returns hash of the data in the buffer +size_t HashBuffer(const uint8_t* data, const size_t size) { + size_t hash = + static_cast(0xCA8945571519E991); // seed with an arbitrary prime + HashCombine(&hash, size); + for (size_t i = 0; i < size; i++) { + HashCombine(&hash, data[i]); + } + return hash; +} + +} // namespace + +RandomGenerator::RandomGenerator(uint64_t seed) : engine_(seed) {} + +RandomGenerator::RandomGenerator(const uint8_t* data, size_t size) { + RandomGenerator(RandomGenerator::CalculateSeed(data, size)); +} + +spv_target_env RandomGenerator::GetTargetEnv() { + spv_target_env result; + + // Need to check that the generated value isn't for a deprecated target env. + do { + result = static_cast( + RandomUInt(&engine_, 0u, static_cast(SPV_ENV_MAX))); + } while (!spvIsValidEnv(result)); + + return result; +} + +uint32_t RandomGenerator::GetUInt32(uint32_t lower, uint32_t upper) { + return RandomUInt(&engine_, lower, upper); +} + +uint32_t RandomGenerator::GetUInt32(uint32_t bound) { + assert(bound > 0 && "|bound| must be greater than 0"); + return RandomUInt(&engine_, 0u, bound); +} + +uint64_t RandomGenerator::CalculateSeed(const uint8_t* data, size_t size) { + assert(data != nullptr && "|data| must be !nullptr"); + + // Number of bytes we want to skip at the start of data for the hash. + // Fewer bytes may be skipped when `size` is small. + // Has lower precedence than kHashDesiredMinBytes. + static const int64_t kHashDesiredLeadingSkipBytes = 5; + // Minimum number of bytes we want to use in the hash. + // Used for short buffers. + static const int64_t kHashDesiredMinBytes = 4; + // Maximum number of bytes we want to use in the hash. + static const int64_t kHashDesiredMaxBytes = 32; + int64_t size_i64 = static_cast(size); + int64_t hash_begin_i64 = + std::min(kHashDesiredLeadingSkipBytes, + std::max(size_i64 - kHashDesiredMinBytes, 0)); + int64_t hash_end_i64 = + std::min(hash_begin_i64 + kHashDesiredMaxBytes, size_i64); + size_t hash_begin = static_cast(hash_begin_i64); + size_t hash_size = static_cast(hash_end_i64) - hash_begin; + return HashBuffer(data + hash_begin, hash_size); +} + +} // namespace fuzzers +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzzers/random_generator.h b/third_party/spirv-tools/test/fuzzers/random_generator.h new file mode 100644 index 0000000000..b121fe8c67 --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/random_generator.h @@ -0,0 +1,68 @@ +// Copyright (c) 2021 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 TEST_FUZZERS_RANDOM_GENERATOR_H_ +#define TEST_FUZZERS_RANDOM_GENERATOR_H_ + +#include +#include + +#include "source/spirv_target_env.h" + +namespace spvtools { +namespace fuzzers { + +/// Pseudo random generator utility class for fuzzing +class RandomGenerator { + public: + /// @brief Initializes the internal engine + /// @param seed - seed value passed to engine + explicit RandomGenerator(uint64_t seed); + + /// @brief Initializes the internal engine + /// @param data - data to calculate the seed from + /// @param size - size of the data + explicit RandomGenerator(const uint8_t* data, size_t size); + + ~RandomGenerator() {} + + /// Calculate a seed value based on a blob of data. + /// Currently hashes bytes near the front of the buffer, after skipping N + /// bytes. + /// @param data - pointer to data to base calculation off of, must be !nullptr + /// @param size - number of elements in |data|, must be > 0 + static uint64_t CalculateSeed(const uint8_t* data, size_t size); + + /// Get random valid target env. + spv_target_env GetTargetEnv(); + + /// Get uint32_t value from uniform distribution. + /// @param lower - lower bound of integer generated + /// @param upper - upper bound of integer generated + /// @returns i, where lower <= i < upper + uint32_t GetUInt32(uint32_t lower, uint32_t upper); + + /// Get uint32_t value from uniform distribution. + /// @param bound - Upper bound of integer generated + /// @returns i, where 0 <= i < bound + uint32_t GetUInt32(uint32_t bound); + + private: + std::mt19937_64 engine_; +}; // class RandomGenerator + +} // namespace fuzzers +} // namespace spvtools + +#endif // TEST_FUZZERS_RANDOM_GENERATOR_UTILS_H_ diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp index 8cecb05f5d..ba3f5b97d1 100644 --- a/third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp +++ b/third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp @@ -18,18 +18,27 @@ #include "source/spirv_target_env.h" #include "spirv-tools/libspirv.hpp" +#include "test/fuzzers/random_generator.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - if (size < sizeof(spv_target_env) + 1) return 0; + spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0; + if (size > 0) { + spvtools::fuzzers::RandomGenerator random_gen(data, size); + target_env = random_gen.GetTargetEnv(); + } - const spv_context context = - spvContextCreate(*reinterpret_cast(data)); - if (context == nullptr) return 0; - - data += sizeof(spv_target_env); - size -= sizeof(spv_target_env); + const spv_context context = spvContextCreate(target_env); + if (context == nullptr) { + return 0; + } 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; + } std::vector input_str; size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char); diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp index 76ba4d9e95..3a97db4159 100644 --- a/third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp +++ b/third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp @@ -16,16 +16,18 @@ #include #include "spirv-tools/libspirv.hpp" +#include "test/fuzzers/random_generator.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - if (size < sizeof(spv_target_env) + 1) return 0; + if (size < 1) { + return 0; + } - const spv_context context = - spvContextCreate(*reinterpret_cast(data)); - if (context == nullptr) return 0; - - data += sizeof(spv_target_env); - size -= sizeof(spv_target_env); + spvtools::fuzzers::RandomGenerator random_gen(data, size); + const spv_context context = spvContextCreate(random_gen.GetTargetEnv()); + if (context == nullptr) { + return 0; + } std::vector input; input.resize(size >> 2); diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp index ca9a52d869..0cb0eff57e 100644 --- a/third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp +++ b/third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp @@ -18,16 +18,20 @@ #include "source/spirv_target_env.h" #include "spirv-tools/libspirv.hpp" +#include "test/fuzzers/random_generator.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - if (size < sizeof(spv_target_env) + 1) return 0; + if (size < 4) { + // There are not enough bytes to constitute a binary that can be + // disassembled. + return 0; + } - const spv_context context = - spvContextCreate(*reinterpret_cast(data)); - if (context == nullptr) return 0; - - data += sizeof(spv_target_env); - size -= sizeof(spv_target_env); + spvtools::fuzzers::RandomGenerator random_gen(data, size); + const spv_context context = spvContextCreate(random_gen.GetTargetEnv()); + if (context == nullptr) { + return 0; + } std::vector input; input.resize(size >> 2); diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_fuzz_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_fuzz_fuzzer.cpp new file mode 100644 index 0000000000..d43920cf51 --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/spvtools_fuzz_fuzzer.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 "source/fuzz/fuzzer.h" +#include "source/fuzz/pseudo_random_generator.h" +#include "spirv-tools/libspirv.hpp" +#include "test/fuzzers/random_generator.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size == 0 || (size % sizeof(uint32_t)) != 0) { + // An empty binary, or a binary whose size is not a multiple of word-size, + // cannot be valid, so can be rejected immediately. + return 0; + } + + std::vector initial_binary(size / sizeof(uint32_t)); + memcpy(initial_binary.data(), data, size); + + spvtools::ValidatorOptions validator_options; + + spvtools::MessageConsumer message_consumer = + [](spv_message_level_t, const char*, const spv_position_t&, const char*) { + }; + + spvtools::fuzzers::RandomGenerator random_gen(data, size); + auto target_env = random_gen.GetTargetEnv(); + std::unique_ptr ir_context; + if (!spvtools::fuzz::fuzzerutil::BuildIRContext( + target_env, message_consumer, initial_binary, validator_options, + &ir_context)) { + // The input is invalid - give up. + return 0; + } + + std::vector donor_suppliers = { + [&initial_binary, message_consumer, target_env, + &validator_options]() -> std::unique_ptr { + std::unique_ptr result; + if (!spvtools::fuzz::fuzzerutil::BuildIRContext( + target_env, message_consumer, initial_binary, validator_options, + &result)) { + // The input was successfully parsed and validated first time around, + // so something is wrong if it is now invalid. + abort(); + } + return result; + }}; + + uint32_t seed = random_gen.GetUInt32(std::numeric_limits::max()); + auto fuzzer_context = spvtools::MakeUnique( + spvtools::MakeUnique(seed), + spvtools::fuzz::FuzzerContext::GetMinFreshId(ir_context.get()), false); + + auto transformation_context = + spvtools::MakeUnique( + spvtools::MakeUnique(ir_context.get()), + validator_options); + + spvtools::fuzz::Fuzzer fuzzer( + std::move(ir_context), std::move(transformation_context), + std::move(fuzzer_context), message_consumer, donor_suppliers, false, + spvtools::fuzz::RepeatedPassStrategy::kLoopedWithRecommendations, true, + validator_options); + fuzzer.Run(0); + return 0; +} diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp index b45a98c370..6f4d7e8b74 100644 --- a/third_party/spirv-tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp +++ b/third_party/spirv-tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp @@ -16,9 +16,15 @@ #include #include "spirv-tools/optimizer.hpp" +#include "test/fuzzers/random_generator.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_3); + if (size < 1) { + return 0; + } + + spvtools::fuzzers::RandomGenerator random_gen(data, size); + spvtools::Optimizer optimizer(random_gen.GetTargetEnv()); optimizer.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, const char*) {}); diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp index 6c3bd6aba8..9c47d7d7af 100644 --- a/third_party/spirv-tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp +++ b/third_party/spirv-tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp @@ -16,9 +16,15 @@ #include #include "spirv-tools/optimizer.hpp" +#include "test/fuzzers/random_generator.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_3); + if (size < 1) { + return 0; + } + + spvtools::fuzzers::RandomGenerator random_gen(data, size); + spvtools::Optimizer optimizer(random_gen.GetTargetEnv()); optimizer.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, const char*) {}); diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp index 68c7974774..10fac42ac6 100644 --- a/third_party/spirv-tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp +++ b/third_party/spirv-tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp @@ -16,9 +16,15 @@ #include #include "spirv-tools/optimizer.hpp" +#include "test/fuzzers/random_generator.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_3); + if (size < 1) { + return 0; + } + + spvtools::fuzzers::RandomGenerator random_gen(data, size); + spvtools::Optimizer optimizer(random_gen.GetTargetEnv()); optimizer.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, const char*) {}); diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_val_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_val_fuzzer.cpp index 5dc4303b45..fd6396cda0 100644 --- a/third_party/spirv-tools/test/fuzzers/spvtools_val_fuzzer.cpp +++ b/third_party/spirv-tools/test/fuzzers/spvtools_val_fuzzer.cpp @@ -16,9 +16,15 @@ #include #include "spirv-tools/libspirv.hpp" +#include "test/fuzzers/random_generator.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_3); + if (size < 1) { + return 0; + } + + spvtools::fuzzers::RandomGenerator random_gen(data, size); + spvtools::SpirvTools tools(random_gen.GetTargetEnv()); tools.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, const char*) {}); diff --git a/third_party/spirv-tools/test/hex_float_test.cpp b/third_party/spirv-tools/test/hex_float_test.cpp index c422f75638..ffdb8bda61 100644 --- a/third_party/spirv-tools/test/hex_float_test.cpp +++ b/third_party/spirv-tools/test/hex_float_test.cpp @@ -1325,6 +1325,76 @@ TEST(FloatProxy, Lowest) { Eq(std::numeric_limits::lowest())); } +template +struct StreamParseCase { + StreamParseCase(const std::string& lit, bool succ, const std::string& suffix, + T value) + : literal(lit), + expect_success(succ), + expected_suffix(suffix), + expected_value(HexFloat>(value)) {} + + std::string literal; + bool expect_success; + std::string expected_suffix; + HexFloat> expected_value; +}; + +template +std::ostream& operator<<(std::ostream& os, const StreamParseCase& fspc) { + os << "StreamParseCase(" << fspc.literal + << ", expect_succes:" << int(fspc.expect_success) << "," + << fspc.expected_suffix << "," << fspc.expected_value << ")"; + return os; +} + +using FloatStreamParseTest = ::testing::TestWithParam>; + +TEST_P(FloatStreamParseTest, Samples) { + std::stringstream input(GetParam().literal); + HexFloat> parsed_value(0.0f); + // Hex floats must be read with the stream input operator. + input >> parsed_value; + if (GetParam().expect_success) { + EXPECT_FALSE(input.fail()); + std::string suffix; + input >> suffix; + // EXPECT_EQ(suffix, GetParam().expected_suffix); + EXPECT_EQ(parsed_value.value().getAsFloat(), + GetParam().expected_value.value().getAsFloat()); + } else { + EXPECT_TRUE(input.fail()); + } +} + +INSTANTIATE_TEST_SUITE_P( + HexFloatExponentMissingDigits, FloatStreamParseTest, + ::testing::ValuesIn(std::vector>{ + {"0x1.0p1", true, "", 2.0f}, + {"0x1.0p1a", true, "a", 2.0f}, + {"-0x1.0p1f", true, "f", -2.0f}, + {"0x1.0p", false, "", 0.0f}, + {"0x1.0pa", false, "", 0.0f}, + {"0x1.0p!", false, "", 0.0f}, + {"0x1.0p+", false, "", 0.0f}, + {"0x1.0p+a", false, "", 0.0f}, + {"0x1.0p+!", false, "", 0.0f}, + {"0x1.0p-", false, "", 0.0f}, + {"0x1.0p-a", false, "", 0.0f}, + {"0x1.0p-!", false, "", 0.0f}, + {"0x1.0p++", false, "", 0.0f}, + {"0x1.0p+-", false, "", 0.0f}, + {"0x1.0p-+", false, "", 0.0f}, + {"0x1.0p--", false, "", 0.0f}})); + +INSTANTIATE_TEST_SUITE_P( + HexFloatExponentTrailingSign, FloatStreamParseTest, + ::testing::ValuesIn(std::vector>{ + // Don't consume a sign after the binary exponent digits. + {"0x1.0p1", true, "", 2.0f}, + {"0x1.0p1+", true, "+", 2.0f}, + {"0x1.0p1-", true, "-", 2.0f}})); + // TODO(awoloszyn): Add fp16 tests and HexFloatTraits. } // namespace } // namespace utils diff --git a/third_party/spirv-tools/test/lint/CMakeLists.txt b/third_party/spirv-tools/test/lint/CMakeLists.txt new file mode 100644 index 0000000000..09bc6d3994 --- /dev/null +++ b/third_party/spirv-tools/test/lint/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (c) 2021 Google LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_spvtools_unittest(TARGET lint + SRCS divergence_analysis_test.cpp + LIBS SPIRV-Tools-lint SPIRV-Tools-opt +) diff --git a/third_party/spirv-tools/test/lint/divergence_analysis_test.cpp b/third_party/spirv-tools/test/lint/divergence_analysis_test.cpp new file mode 100644 index 0000000000..36cd32dd0a --- /dev/null +++ b/third_party/spirv-tools/test/lint/divergence_analysis_test.cpp @@ -0,0 +1,700 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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/lint/divergence_analysis.h" + +#include + +#include "gtest/gtest.h" +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace lint { +namespace { + +void CLIMessageConsumer(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: line " << position.index << ": " << message + << std::endl; + break; + case SPV_MSG_WARNING: + std::cout << "warning: line " << position.index << ": " << message + << std::endl; + break; + case SPV_MSG_INFO: + std::cout << "info: line " << position.index << ": " << message + << std::endl; + break; + default: + break; + } +} + +class DivergenceTest : public ::testing::Test { + protected: + std::unique_ptr context_; + std::unique_ptr divergence_; + + void Build(std::string text, uint32_t function_id = 1) { + context_ = BuildModule(SPV_ENV_UNIVERSAL_1_0, CLIMessageConsumer, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context_.get()); + opt::Module* module = context_->module(); + ASSERT_NE(nullptr, module); + // First function should have the given ID. + ASSERT_NE(module->begin(), module->end()); + opt::Function* function = &*module->begin(); + ASSERT_EQ(function->result_id(), function_id); + divergence_.reset(new DivergenceAnalysis(*context_)); + divergence_->Run(function); + } +}; + +// Makes assertions a bit shorter. +using Level = DivergenceAnalysis::DivergenceLevel; + +namespace { +std::string Preamble() { + return R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" %x %y + OpExecutionMode %1 OriginLowerLeft + OpDecorate %y Flat + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %bool = OpTypeBool + %float = OpTypeFloat 32 + %false = OpConstantFalse %bool + %true = OpConstantTrue %bool + %zero = OpConstant %float 0 + %one = OpConstant %float 1 + %x_t = OpTypePointer Input %float + %x = OpVariable %x_t Input + %y = OpVariable %x_t Input + %1 = OpFunction %void None %void_f + )"; +} +} // namespace + +TEST_F(DivergenceTest, SimpleTest) { + // pseudocode: + // %10: + // %11 = load x + // if (%12 = (%11 < 0)) { + // %13: + // // do nothing + // } + // %14: + // return + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %11 = OpLoad %float %x + %12 = OpFOrdLessThan %bool %11 %zero + OpSelectionMerge %14 None + OpBranchConditional %12 %13 %14 + %13 = OpLabel + OpBranch %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )")); + // Control flow divergence. + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13)); + EXPECT_EQ(12, divergence_->GetDivergenceSource(13)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14)); + // Value divergence. + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(0, divergence_->GetDivergenceSource(11)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(11, divergence_->GetDivergenceSource(12)); +} + +TEST_F(DivergenceTest, FlowTypesTest) { + // pseudocode: + // %10: + // %11 = load x + // %12 = x < 0 // data -> data + // if (%12) { + // %13: // data -> control + // if (true) { + // %14: // control -> control + // } + // %15: + // %16 = 1 + // } else { + // %17: + // %18 = 2 + // } + // %19: + // %19 = phi(%16 from %15, %18 from %17) // control -> data + // return + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %11 = OpLoad %float %x + %12 = OpFOrdLessThan %bool %11 %zero + OpSelectionMerge %19 None + OpBranchConditional %12 %13 %17 + %13 = OpLabel + OpSelectionMerge %15 None + OpBranchConditional %true %14 %15 + %14 = OpLabel + OpBranch %15 + %15 = OpLabel + %16 = OpFAdd %float %zero %zero + OpBranch %19 + %17 = OpLabel + %18 = OpFAdd %float %zero %one + OpBranch %19 + %19 = OpLabel + %20 = OpPhi %float %16 %15 %18 %17 + OpReturn + OpFunctionEnd + )")); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(0, divergence_->GetDivergenceSource(11)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(11, divergence_->GetDivergenceSource(12)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13)); + EXPECT_EQ(12, divergence_->GetDivergenceSource(13)); + EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(13)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14)); + EXPECT_EQ(13, divergence_->GetDivergenceSource(14)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15)); + EXPECT_EQ(12, divergence_->GetDivergenceSource(15)); + EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(15)); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(16)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17)); + EXPECT_EQ(12, divergence_->GetDivergenceSource(17)); + EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(17)); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(18)); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(19)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(20)); + EXPECT_TRUE(divergence_->GetDivergenceSource(20) == 15 || + divergence_->GetDivergenceDependenceSource(20) == 17) + << "Got: " << divergence_->GetDivergenceDependenceSource(20); +} + +TEST_F(DivergenceTest, ExitDependenceTest) { + // pseudocode: + // %10: + // %11 = load x + // %12 = %11 < 0 + // %13: + // do { + // %14: + // if (%12) { + // %15: + // continue; + // } + // %16: + // %17: + // continue; + // } %18: while(false); + // %19: + // return + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %11 = OpLoad %float %x + %12 = OpFOrdLessThan %bool %11 %zero ; data -> data + OpBranch %13 + %13 = OpLabel + OpLoopMerge %19 %18 None + OpBranch %14 + %14 = OpLabel + OpSelectionMerge %16 None + OpBranchConditional %12 %15 %16 + %15 = OpLabel + OpBranch %18 ; continue + %16 = OpLabel + OpBranch %17 + %17 = OpLabel + OpBranch %18 ; continue + %18 = OpLabel + OpBranchConditional %false %13 %19 + %19 = OpLabel + OpReturn + OpFunctionEnd + )")); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(0, divergence_->GetDivergenceSource(11)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(11, divergence_->GetDivergenceSource(12)); + + // Since both branches continue, there's no divergent control dependence + // to 13. + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(13)); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14)); + + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15)); + EXPECT_EQ(12, divergence_->GetDivergenceSource(15)); + EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(15)); + + // These two blocks are outside the if but are still control dependent. + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16)); + EXPECT_EQ(12, divergence_->GetDivergenceSource(16)); + EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(16)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17)); + EXPECT_EQ(12, divergence_->GetDivergenceSource(17)); + EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(17)); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(18)); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(19)); +} + +TEST_F(DivergenceTest, ReconvergencePromotionTest) { + // pseudocode: + // %10: + // %11 = load y + // %12 = %11 < 0 + // if (%12) { + // %13: + // %14: + // %15: + // if (true) { + // %16: + // } + // // Reconvergence *not* guaranteed as + // // control is not uniform on the IG level + // // at %15. + // %17: + // %18: + // %19: + // %20 = load x + // } + // %21: + // %22 = phi(%11, %20) + // return + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %11 = OpLoad %float %y + %12 = OpFOrdLessThan %bool %11 %zero + OpSelectionMerge %21 None + OpBranchConditional %12 %13 %21 + %13 = OpLabel + OpBranch %14 + %14 = OpLabel + OpBranch %15 + %15 = OpLabel + OpSelectionMerge %17 None + OpBranchConditional %true %16 %17 + %16 = OpLabel + OpBranch %17 + %17 = OpLabel + OpBranch %18 + %18 = OpLabel + OpBranch %19 + %19 = OpLabel + %20 = OpLoad %float %y + OpBranch %21 + %21 = OpLabel + %22 = OpPhi %float %11 %10 %20 %19 + OpReturn + OpFunctionEnd + )")); + ASSERT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + ASSERT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(21)); + + ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(11)); + ASSERT_EQ(0, divergence_->GetDivergenceSource(11)); + ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(12)); + ASSERT_EQ(11, divergence_->GetDivergenceSource(12)); + ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(13)); + ASSERT_EQ(12, divergence_->GetDivergenceSource(13)); + ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(13)); + ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(14)); + ASSERT_EQ(12, divergence_->GetDivergenceSource(14)); + ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(14)); + ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(15)); + ASSERT_EQ(12, divergence_->GetDivergenceSource(15)); + ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(15)); + ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(16)); + ASSERT_EQ(15, divergence_->GetDivergenceSource(16)); + + ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17)); + ASSERT_EQ(12, divergence_->GetDivergenceSource(17)); + ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(18)); + ASSERT_EQ(12, divergence_->GetDivergenceSource(18)); + ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(19)); + ASSERT_EQ(12, divergence_->GetDivergenceSource(19)); + + ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(20)); + ASSERT_EQ(0, divergence_->GetDivergenceSource(20)); + ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(22)); + ASSERT_EQ(19, divergence_->GetDivergenceSource(22)); + ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(15)); +} + +TEST_F(DivergenceTest, FunctionCallTest) { + // pseudocode: + // %2() { + // %20: + // %21 = load x + // %22 = %21 < 0 + // if (%22) { + // %23: + // return + // } + // %24: + // return + // } + // + // main() { + // %10: + // %11 = %2(); + // // Reconvergence *not* guaranteed. + // %12: + // return + // } + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %11 = OpFunctionCall %void %2 + OpBranch %12 + %12 = OpLabel + OpReturn + OpFunctionEnd + + %2 = OpFunction %void None %void_f + %20 = OpLabel + %21 = OpLoad %float %x + %22 = OpFOrdLessThan %bool %21 %zero + OpSelectionMerge %24 None + OpBranchConditional %22 %23 %24 + %23 = OpLabel + OpReturn + %24 = OpLabel + OpReturn + OpFunctionEnd + )")); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + // Conservatively assume function return value is uniform. + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(11)); + // TODO(dongja): blocks reachable from diverging function calls should be + // divergent. + // EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(12)); // Wrong! +} + +TEST_F(DivergenceTest, LateMergeTest) { + // pseudocode: + // %10: + // %11 = load y + // %12 = %11 < 0 + // [merge: %15] + // if (%12) { + // %13: + // } + // %14: // Reconvergence hasn't happened by here. + // %15: + // return + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %11 = OpLoad %float %x + %12 = OpFOrdLessThan %bool %11 %zero + OpSelectionMerge %15 None + OpBranchConditional %12 %13 %14 + %13 = OpLabel + OpBranch %14 + %14 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + )")); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13)); + // TODO(dongja): + // EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14)); // Wrong! + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(15)); +} + +// The following series of tests makes sure that we find the least fixpoint. +TEST_F(DivergenceTest, UniformFixpointTest) { + // pseudocode: + // %10: + // %20 = load x + // %21 = load y + // do { + // %11: + // %12: + // %13 = phi(%zero from %11, %14 from %16) + // %14 = %13 + 1 + // %15 = %13 < 1 + // } %16: while (%15) + // %17: + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %20 = OpLoad %float %x + %21 = OpLoad %float %y + OpBranch %11 + %11 = OpLabel + %13 = OpPhi %float %zero %10 %14 %16 + OpLoopMerge %17 %16 None + OpBranch %12 + %12 = OpLabel + %14 = OpFAdd %float %13 %one + %15 = OpFOrdLessThan %bool %13 %one + OpBranch %16 + %16 = OpLabel + OpBranchConditional %15 %11 %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )")); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(13)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(15)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(16)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17)); +} + +TEST_F(DivergenceTest, PartiallyUniformFixpointTest) { + // pseudocode: + // %10: + // %20 = load x + // %21 = load y + // do { + // %11: + // %12: + // %13 = phi(%zero from %11, %14 from %16) + // %14 = %13 + 1 + // %15 = %13 < %21 + // } %16: while (%15) + // %17: + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %20 = OpLoad %float %x + %21 = OpLoad %float %y + OpBranch %11 + %11 = OpLabel + %13 = OpPhi %float %zero %10 %14 %16 + OpLoopMerge %17 %16 None + OpBranch %12 + %12 = OpLabel + %14 = OpFAdd %float %13 %one + %15 = OpFOrdLessThan %bool %13 %21 + OpBranch %16 + %16 = OpLabel + OpBranchConditional %15 %11 %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )")); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(13)); + EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(14)); + EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(15)); + EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(16)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17)); +} + +TEST_F(DivergenceTest, DivergentFixpointTest) { + // pseudocode: + // %10: + // %20 = load x + // %21 = load y + // do { + // %11: + // %12: + // %13 = phi(%zero from %11, %14 from %16) + // %14 = %13 + 1 + // %15 = %13 < %20 + // } %16: while (%15) + // %17: + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %20 = OpLoad %float %x + %21 = OpLoad %float %y + OpBranch %11 + %11 = OpLabel + %13 = OpPhi %float %zero %10 %14 %16 + OpLoopMerge %17 %16 None + OpBranch %12 + %12 = OpLabel + %14 = OpFAdd %float %13 %one + %15 = OpFOrdLessThan %bool %13 %20 + OpBranch %16 + %16 = OpLabel + OpBranchConditional %15 %11 %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )")); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17)); +} + +TEST_F(DivergenceTest, DivergentOverridesPartiallyUniformTest) { + // pseudocode: + // %10: + // %20 = load x + // %21 = load y + // %11: + // do { + // %12: + // %13 = phi(%21 from %11, %14 from %16) + // %14 = %13 + 1 + // %15 = %13 < %20 + // } %16: while (%15) + // %17: + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %20 = OpLoad %float %x + %21 = OpLoad %float %y + OpBranch %11 + %11 = OpLabel + %13 = OpPhi %float %zero %10 %14 %16 + OpLoopMerge %17 %16 None + OpBranch %12 + %12 = OpLabel + %14 = OpFAdd %float %13 %one + %15 = OpFOrdLessThan %bool %13 %20 + OpBranch %16 + %16 = OpLabel + OpBranchConditional %15 %11 %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )")); + + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17)); +} + +TEST_F(DivergenceTest, NestedFixpointTest) { + // pseudocode: + // %10: + // %20 = load x + // %21 = load y + // do { + // %22: + // %23: + // %24 = phi(%zero from %22, %25 from %26) + // %11: + // do { + // %12: + // %13 = phi(%zero from %11, %14 from %16) + // %14 = %13 + 1 + // %15 = %13 < %24 + // } %16: while (%15) + // %17: + // %25 = load x + // } %26: while (false) + // %27: + // return + ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"( + %10 = OpLabel + %20 = OpLoad %float %x + %21 = OpLoad %float %y + OpBranch %22 + %22 = OpLabel + %24 = OpPhi %float %zero %10 %25 %26 + OpLoopMerge %27 %26 None + OpBranch %23 + %23 = OpLabel + OpBranch %11 + %11 = OpLabel + %13 = OpPhi %float %zero %23 %14 %16 + OpLoopMerge %17 %16 None + OpBranch %12 + %12 = OpLabel + %14 = OpFAdd %float %13 %one + %15 = OpFOrdLessThan %bool %13 %24 + OpBranch %16 + %16 = OpLabel + OpBranchConditional %15 %11 %17 + %17 = OpLabel + %25 = OpLoad %float %x + OpBranch %26 + %26 = OpLabel + OpBranchConditional %false %22 %27 + %27 = OpLabel + OpReturn + OpFunctionEnd + )")); + // This test makes sure that divergent values flowing upward can influence the + // fixpoint of a loop. + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16)); + // Control of the outer loop is still uniform. + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(22)); + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(23)); + // Seed divergent values. + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(24)); + EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(25)); + // Outer loop control. + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(26)); + // Merged. + EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(27)); +} + +} // namespace +} // namespace lint +} // namespace spvtools diff --git a/third_party/spirv-tools/test/operand_capabilities_test.cpp b/third_party/spirv-tools/test/operand_capabilities_test.cpp index 6f83dfeb8e..bc0ee05519 100644 --- a/third_party/spirv-tools/test/operand_capabilities_test.cpp +++ b/third_party/spirv-tools/test/operand_capabilities_test.cpp @@ -368,19 +368,6 @@ INSTANTIATE_TEST_SUITE_P( // clang-format on }))); -// See SPIR-V Section 3.15 FP Fast Math Mode -INSTANTIATE_TEST_SUITE_P( - FPFastMathMode, EnumCapabilityTest, - Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), - ValuesIn(std::vector{ - CASE0(FP_FAST_MATH_MODE, FPFastMathModeMaskNone), - CASE1(FP_FAST_MATH_MODE, FPFastMathModeNotNaNMask, Kernel), - CASE1(FP_FAST_MATH_MODE, FPFastMathModeNotInfMask, Kernel), - CASE1(FP_FAST_MATH_MODE, FPFastMathModeNSZMask, Kernel), - CASE1(FP_FAST_MATH_MODE, FPFastMathModeAllowRecipMask, Kernel), - CASE1(FP_FAST_MATH_MODE, FPFastMathModeFastMask, Kernel), - }))); - // See SPIR-V Section 3.17 Linkage Type INSTANTIATE_TEST_SUITE_P( LinkageType, EnumCapabilityTest, diff --git a/third_party/spirv-tools/test/opt/CMakeLists.txt b/third_party/spirv-tools/test/opt/CMakeLists.txt index 621a6aa46d..bc44e8d6e6 100644 --- a/third_party/spirv-tools/test/opt/CMakeLists.txt +++ b/third_party/spirv-tools/test/opt/CMakeLists.txt @@ -28,8 +28,11 @@ add_spvtools_unittest(TARGET opt compact_ids_test.cpp constants_test.cpp constant_manager_test.cpp + control_dependence.cpp convert_relaxed_to_half_test.cpp + convert_to_sampled_image_test.cpp copy_prop_array_test.cpp + dataflow.cpp dead_branch_elim_test.cpp dead_insert_elim_test.cpp dead_variable_elim_test.cpp @@ -82,6 +85,7 @@ add_spvtools_unittest(TARGET opt remove_unused_interface_variables_test.cpp register_liveness.cpp relax_float_ops_test.cpp + replace_desc_array_access_using_var_index_test.cpp replace_invalid_opc_test.cpp scalar_analysis.cpp scalar_replacement_test.cpp diff --git a/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp b/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp index 5b4291dacd..f228c8cb24 100644 --- a/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp @@ -7063,6 +7063,287 @@ TEST_F(AggressiveDCETest, DebugInfoKeepInFunctionElimStoreVar) { SinglePassRunAndMatch(text, true); } +TEST_F(AggressiveDCETest, ShaderDebugInfoKeepInFunctionElimStoreVar) { + // Verify that dead local variable tc and store eliminated but all + // in-function NonSemantic Shader debuginfo kept. + + const std::string text = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %g_sAniso %in_var_TEXCOORD2 %out_var_SV_Target0 + OpExecutionMode %MainPs OriginUpperLeft + %7 = OpString "foo.frag" + %8 = OpString "PS_OUTPUT" + %9 = OpString "float" + %10 = OpString "vColor" + %11 = OpString "PS_INPUT" + %12 = OpString "vTextureCoords" + %13 = OpString "@type.2d.image" + %14 = OpString "type.2d.image" + %15 = OpString "Texture2D.TemplateParam" + %16 = OpString "src.MainPs" + %17 = OpString "tc" + %18 = OpString "ps_output" + %19 = OpString "i" + %20 = OpString "@type.sampler" + %21 = OpString "type.sampler" + %22 = OpString "g_sAniso" + %23 = OpString "g_tColor" + OpName %type_2d_image "type.2d.image" + OpName %g_tColor "g_tColor" + OpName %type_sampler "type.sampler" + OpName %g_sAniso "g_sAniso" + OpName %in_var_TEXCOORD2 "in.var.TEXCOORD2" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %MainPs "MainPs" + OpName %PS_INPUT "PS_INPUT" + OpMemberName %PS_INPUT 0 "vTextureCoords" + OpName %param_var_i "param.var.i" + OpName %PS_OUTPUT "PS_OUTPUT" + OpMemberName %PS_OUTPUT 0 "vColor" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %in_var_TEXCOORD2 Location 0 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %g_tColor DescriptorSet 0 + OpDecorate %g_tColor Binding 0 + OpDecorate %g_sAniso DescriptorSet 0 + OpDecorate %g_sAniso Binding 1 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_32 = OpConstant %uint 32 + %float = OpTypeFloat 32 +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %uint_128 = OpConstant %uint 128 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 + %uint_5 = OpConstant %uint 5 + %uint_7 = OpConstant %uint 7 + %uint_8 = OpConstant %uint 8 + %uint_10 = OpConstant %uint 10 + %uint_11 = OpConstant %uint 11 + %uint_12 = OpConstant %uint 12 + %uint_14 = OpConstant %uint 14 + %uint_15 = OpConstant %uint 15 + %uint_16 = OpConstant %uint 16 + %uint_17 = OpConstant %uint 17 + %uint_19 = OpConstant %uint 19 + %uint_20 = OpConstant %uint 20 + %uint_21 = OpConstant %uint 21 + %uint_25 = OpConstant %uint 25 + %uint_29 = OpConstant %uint 29 + %uint_30 = OpConstant %uint 30 + %uint_35 = OpConstant %uint 35 + %uint_41 = OpConstant %uint 41 + %uint_48 = OpConstant %uint 48 + %uint_53 = OpConstant %uint 53 + %uint_64 = OpConstant %uint 64 + %45 = OpTypeFunction %void + %PS_INPUT = OpTypeStruct %v2float +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT + %PS_OUTPUT = OpTypeStruct %v4float + %47 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%_ptr_Function_v2float = OpTypePointer Function %v2float +%type_sampled_image = OpTypeSampledImage %type_2d_image +%_ptr_Function_v4float = OpTypePointer Function %v4float + %g_tColor = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + %g_sAniso = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%in_var_TEXCOORD2 = OpVariable %_ptr_Input_v2float Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output + %51 = OpExtInst %void %1 DebugInfoNone + %52 = OpExtInst %void %1 DebugExpression + %53 = OpExtInst %void %1 DebugOperation %uint_0 + %54 = OpExtInst %void %1 DebugExpression %53 + %55 = OpExtInst %void %1 DebugSource %7 + %56 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %55 %uint_5 + %59 = OpExtInst %void %1 DebugTypeBasic %9 %uint_32 %uint_3 %uint_0 + %60 = OpExtInst %void %1 DebugTypeVector %59 %uint_4 + %58 = OpExtInst %void %1 DebugTypeMember %10 %60 %55 %uint_12 %uint_5 %uint_0 %uint_128 %uint_3 + %57 = OpExtInst %void %1 DebugTypeComposite %8 %uint_1 %55 %uint_10 %uint_1 %56 %8 %uint_128 %uint_3 %58 + %63 = OpExtInst %void %1 DebugTypeVector %59 %uint_2 + %62 = OpExtInst %void %1 DebugTypeMember %12 %63 %55 %uint_7 %uint_5 %uint_0 %uint_64 %uint_3 + %61 = OpExtInst %void %1 DebugTypeComposite %11 %uint_1 %55 %uint_5 %uint_1 %56 %11 %uint_64 %uint_3 %62 + %64 = OpExtInst %void %1 DebugTypeComposite %13 %uint_0 %55 %uint_0 %uint_0 %56 %14 %51 %uint_3 + %67 = OpExtInst %void %1 DebugTypeFunction %uint_3 %57 %61 + %68 = OpExtInst %void %1 DebugFunction %16 %67 %55 %uint_15 %uint_1 %56 %16 %uint_3 %uint_16 + %69 = OpExtInst %void %1 DebugLexicalBlock %55 %uint_16 %uint_1 %68 + %70 = OpExtInst %void %1 DebugLocalVariable %17 %63 %55 %uint_19 %uint_12 %69 %uint_4 + %71 = OpExtInst %void %1 DebugLocalVariable %18 %57 %55 %uint_17 %uint_15 %69 %uint_4 + %72 = OpExtInst %void %1 DebugLocalVariable %19 %61 %55 %uint_15 %uint_29 %68 %uint_4 %uint_1 + %73 = OpExtInst %void %1 DebugTypeComposite %20 %uint_1 %55 %uint_0 %uint_0 %56 %21 %51 %uint_3 + %74 = OpExtInst %void %1 DebugGlobalVariable %22 %73 %55 %uint_3 %uint_14 %56 %22 %g_sAniso %uint_8 + %75 = OpExtInst %void %1 DebugGlobalVariable %23 %64 %55 %uint_1 %uint_11 %56 %23 %g_tColor %uint_8 + %MainPs = OpFunction %void None %45 + %76 = OpLabel + %78 = OpVariable %_ptr_Function_PS_OUTPUT Function + %79 = OpVariable %_ptr_Function_v2float Function + %81 = OpVariable %_ptr_Function_PS_OUTPUT Function +%param_var_i = OpVariable %_ptr_Function_PS_INPUT Function + %82 = OpLoad %v2float %in_var_TEXCOORD2 + %83 = OpCompositeConstruct %PS_INPUT %82 + OpStore %param_var_i %83 + %112 = OpExtInst %void %1 DebugFunctionDefinition %68 %MainPs + %109 = OpExtInst %void %1 DebugScope %68 + %85 = OpExtInst %void %1 DebugDeclare %72 %param_var_i %52 + %110 = OpExtInst %void %1 DebugScope %69 + %87 = OpExtInst %void %1 DebugDeclare %71 %78 %52 +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugFunctionDefinition %68 %MainPs +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugScope %68 +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugDeclare %72 %param_var_i %52 +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugScope %69 +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugDeclare %71 %78 %52 + %300 = OpExtInst %void %1 DebugLine %55 %uint_19 %uint_19 %uint_17 %uint_30 +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugLine %55 %uint_19 %uint_19 %uint_17 %uint_30 + %88 = OpAccessChain %_ptr_Function_v2float %param_var_i %int_0 + %89 = OpLoad %v2float %88 + %301 = OpExtInst %void %1 DebugLine %55 %uint_19 %uint_19 %uint_12 %uint_35 + OpStore %79 %89 +;CHECK-NOT: OpStore %79 %89 + %302 = OpExtInst %void %1 DebugLine %55 %uint_19 %uint_19 %uint_12 %uint_35 +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugLine %55 %uint_19 %uint_19 %uint_12 %uint_35 + %106 = OpExtInst %void %1 DebugValue %70 %89 %52 +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugValue %70 %89 %52 + %303 = OpExtInst %void %1 DebugLine %55 %uint_20 %uint_20 %uint_25 %uint_32 + %91 = OpLoad %type_2d_image %g_tColor + %304 = OpExtInst %void %1 DebugLine %55 %uint_20 %uint_20 %uint_41 %uint_48 + %92 = OpLoad %type_sampler %g_sAniso + %305 = OpExtInst %void %1 DebugLine %55 %uint_20 %uint_20 %uint_25 %uint_53 + %94 = OpSampledImage %type_sampled_image %91 %92 + %95 = OpImageSampleImplicitLod %v4float %94 %89 None + %306 = OpExtInst %void %1 DebugLine %55 %uint_20 %uint_20 %uint_5 %uint_53 + %96 = OpAccessChain %_ptr_Function_v4float %78 %int_0 + OpStore %96 %95 + %307 = OpExtInst %void %1 DebugLine %55 %uint_21 %uint_21 %uint_12 %uint_20 + %97 = OpLoad %PS_OUTPUT %78 + %308 = OpExtInst %void %1 DebugLine %55 %uint_21 %uint_21 %uint_5 %uint_20 + OpStore %81 %97 + %309 = OpExtInst %void %1 DebugNoLine +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugNoLine + %111 = OpExtInst %void %1 DebugNoScope +;CHECK: {{%\w+}} = OpExtInst %void %1 DebugNoScope + %100 = OpCompositeExtract %v4float %97 0 + OpStore %out_var_SV_Target0 %100 + OpReturn + OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + +TEST_F(AggressiveDCETest, ShaderDebugInfoGlobalDCE) { + // Verify that DebugGlobalVariable for eliminated private variable has + // variable operand replaced with DebugInfoNone. + + const std::string text = R"(OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %out_var_SV_Target0 %a +OpExecutionMode %MainPs OriginUpperLeft +%5 = OpString "source2.hlsl" +%24 = OpString "float" +%29 = OpString "vColor" +%33 = OpString "PS_OUTPUT" +%37 = OpString "MainPs" +%38 = OpString "" +%42 = OpString "ps_output" +%46 = OpString "a" +OpName %a "a" +OpName %out_var_SV_Target0 "out.var.SV_Target0" +OpName %MainPs "MainPs" +OpName %PS_OUTPUT "PS_OUTPUT" +OpMemberName %PS_OUTPUT 0 "vColor" +OpDecorate %out_var_SV_Target0 Location 0 +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%8 = OpConstantNull %v4float +%float_0 = OpConstant %float 0 +%10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%uint = OpTypeInt 32 0 +%uint_32 = OpConstant %uint 32 +%_ptr_Private_v4float = OpTypePointer Private %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%void = OpTypeVoid +%uint_1 = OpConstant %uint 1 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_3 = OpConstant %uint 3 +%uint_0 = OpConstant %uint 0 +%uint_128 = OpConstant %uint 128 +%uint_12 = OpConstant %uint 12 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_10 = OpConstant %uint 10 +%uint_15 = OpConstant %uint 15 +%48 = OpTypeFunction %void +%PS_OUTPUT = OpTypeStruct %v4float +%54 = OpTypeFunction %PS_OUTPUT +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%_ptr_Function_v4float = OpTypePointer Function %v4float +%a = OpVariable %_ptr_Private_v4float Private +;CHECK-NOT: %a = OpVariable %_ptr_Private_v4float Private +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output +;CHECK: [[dbg_none:%\w+]] = OpExtInst %void %1 DebugInfoNone +%18 = OpExtInst %void %1 DebugExpression +%19 = OpExtInst %void %1 DebugSource %5 +%20 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %19 %uint_5 +%25 = OpExtInst %void %1 DebugTypeBasic %24 %uint_32 %uint_3 %uint_0 +%28 = OpExtInst %void %1 DebugTypeVector %25 %uint_4 +%31 = OpExtInst %void %1 DebugTypeMember %29 %28 %19 %uint_5 %uint_12 %uint_0 %uint_128 %uint_3 +%34 = OpExtInst %void %1 DebugTypeComposite %33 %uint_1 %19 %uint_3 %uint_8 %20 %33 %uint_128 %uint_3 %31 +%36 = OpExtInst %void %1 DebugTypeFunction %uint_3 %34 +%39 = OpExtInst %void %1 DebugFunction %37 %36 %19 %uint_8 %uint_1 %20 %38 %uint_3 %uint_9 +%41 = OpExtInst %void %1 DebugLexicalBlock %19 %uint_9 %uint_1 %39 +%43 = OpExtInst %void %1 DebugLocalVariable %42 %34 %19 %uint_10 %uint_15 %41 %uint_4 +%47 = OpExtInst %void %1 DebugGlobalVariable %46 %28 %19 %uint_1 %uint_15 %20 %46 %a %uint_8 +;CHECK: %47 = OpExtInst %void %1 DebugGlobalVariable %46 %28 %19 %uint_1 %uint_15 %20 %46 [[dbg_none]] %uint_8 +%MainPs = OpFunction %void None %48 +%49 = OpLabel +%65 = OpVariable %_ptr_Function_PS_OUTPUT Function +%66 = OpVariable %_ptr_Function_PS_OUTPUT Function +OpStore %a %8 +%72 = OpExtInst %void %1 DebugScope %41 +%69 = OpExtInst %void %1 DebugDeclare %43 %65 %18 +OpLine %5 11 5 +%70 = OpAccessChain %_ptr_Function_v4float %65 %int_0 +OpStore %70 %10 +OpLine %5 12 12 +%71 = OpLoad %PS_OUTPUT %65 +OpLine %5 12 5 +OpStore %66 %71 +%73 = OpExtInst %void %1 DebugNoLine +%74 = OpExtInst %void %1 DebugNoScope +%51 = OpLoad %PS_OUTPUT %66 +%53 = OpCompositeExtract %v4float %51 0 +OpStore %out_var_SV_Target0 %53 +OpLine %5 13 1 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + TEST_F(AggressiveDCETest, DebugInfoDeclareKeepsStore) { // Verify that local variable tc and its store are kept by DebugDeclare. // @@ -7584,11 +7865,178 @@ TEST_F(AggressiveDCETest, KeepDebugScopeParent) { SinglePassRunAndMatch(text, true); } -// TODO(greg-lunarg): Add tests to verify handling of these cases: -// -// Check that logical addressing required -// Check that function calls inhibit optimization -// Others? +TEST_F(AggressiveDCETest, KeepExportFunctions) { + // All functions are reachable. In particular, ExportedFunc and Constant are + // reachable because ExportedFunc is exported. Nothing should be removed. + const std::vector text = { + // clang-format off + "OpCapability Shader", + "OpCapability Linkage", + "OpMemoryModel Logical GLSL450", + "OpEntryPoint Fragment %main \"main\"", + "OpName %main \"main\"", + "OpName %ExportedFunc \"ExportedFunc\"", + "OpName %Live \"Live\"", + "OpDecorate %ExportedFunc LinkageAttributes \"ExportedFunc\" Export", + "%void = OpTypeVoid", + "%7 = OpTypeFunction %void", + "%main = OpFunction %void None %7", + "%15 = OpLabel", + "OpReturn", + "OpFunctionEnd", +"%ExportedFunc = OpFunction %void None %7", + "%19 = OpLabel", + "%16 = OpFunctionCall %void %Live", + "OpReturn", + "OpFunctionEnd", + "%Live = OpFunction %void None %7", + "%20 = OpLabel", + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + std::string assembly = JoinAllInsts(text); + auto result = SinglePassRunAndDisassemble( + assembly, /* skip_nop = */ true, /* do_validation = */ false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); + EXPECT_EQ(assembly, std::get<0>(result)); +} + +TEST_F(AggressiveDCETest, KeepPrivateVarInExportFunctions) { + // The loads and stores from the private variable should not be removed + // because the functions are exported and could be called. + const std::string text = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %privateVar "privateVar" +OpName %ReadPrivate "ReadPrivate" +OpName %WritePrivate "WritePrivate" +OpName %value "value" +OpDecorate %ReadPrivate LinkageAttributes "ReadPrivate" Export +OpDecorate %WritePrivate LinkageAttributes "WritePrivate" Export +%int = OpTypeInt 32 1 +%_ptr_Private_int = OpTypePointer Private %int +%6 = OpTypeFunction %int +%void = OpTypeVoid +%_ptr_Function_int = OpTypePointer Function %int +%10 = OpTypeFunction %void %_ptr_Function_int +%privateVar = OpVariable %_ptr_Private_int Private +%ReadPrivate = OpFunction %int None %6 +%12 = OpLabel +%8 = OpLoad %int %privateVar +OpReturnValue %8 +OpFunctionEnd +%WritePrivate = OpFunction %void None %10 +%value = OpFunctionParameter %_ptr_Function_int +%13 = OpLabel +%14 = OpLoad %int %value +OpStore %privateVar %14 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); + EXPECT_EQ(text, std::get<0>(result)); +} + +TEST_F(AggressiveDCETest, KeepLableNames) { + const std::string text = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %WritePrivate "WritePrivate" +OpName %entry "entry" +OpName %target "target" +OpDecorate %WritePrivate LinkageAttributes "WritePrivate" Export +%void = OpTypeVoid +%3 = OpTypeFunction %void +%WritePrivate = OpFunction %void None %3 +%entry = OpLabel +OpBranch %target +%target = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); + EXPECT_EQ(text, std::get<0>(result)); +} + +TEST_F(AggressiveDCETest, PreserveInterface) { + // Set preserve_interface to true. Verify that unused uniform + // constant in entry point interface is not eliminated. + const std::string text = R"(OpCapability RayTracingKHR +OpExtension "SPV_KHR_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint RayGenerationNV %2 "main" %3 %4 +OpDecorate %3 Location 0 +OpDecorate %4 DescriptorSet 2 +OpDecorate %4 Binding 0 +%void = OpTypeVoid +%6 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%float = OpTypeFloat 32 +%_ptr_CallableDataNV_float = OpTypePointer CallableDataNV %float +%3 = OpVariable %_ptr_CallableDataNV_float CallableDataNV +%13 = OpTypeAccelerationStructureKHR +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%4 = OpVariable %_ptr_UniformConstant_13 UniformConstant +%2 = OpFunction %void None %6 +%15 = OpLabel +OpExecuteCallableKHR %uint_0 %3 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ false, + /* preserve_interface */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); + EXPECT_EQ(text, std::get<0>(result)); +} + +TEST_F(AggressiveDCETest, EmptyContinueWithConditionalBranch) { + const std::string text = R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +%void = OpTypeVoid +%4 = OpTypeFunction %void +%bool = OpTypeBool +%false = OpConstantFalse %bool +%2 = OpFunction %void None %4 +%9 = OpLabel +OpBranch %10 +%10 = OpLabel +OpLoopMerge %11 %12 None +OpBranch %13 +%13 = OpLabel +OpKill +%12 = OpLabel +OpBranchConditional %false %10 %10 +%11 = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(text, text, false); +} } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/block_merge_test.cpp b/third_party/spirv-tools/test/opt/block_merge_test.cpp index 140a5c09ee..6903c4e70f 100644 --- a/third_party/spirv-tools/test/opt/block_merge_test.cpp +++ b/third_party/spirv-tools/test/opt/block_merge_test.cpp @@ -90,6 +90,63 @@ OpFunctionEnd true); } +TEST_F(BlockMergeTest, BlockMergeForLinkage) { + const std::string before = + R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %BaseColor "BaseColor" +OpName %bb_entry "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%8 = OpTypeFunction %v4float %_ptr_Function_v4float +%main = OpFunction %v4float None %8 +%BaseColor = OpFunctionParameter %_ptr_Function_v4float +%bb_entry = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%9 = OpLoad %v4float %BaseColor +OpStore %v %9 +OpBranch %10 +%10 = OpLabel +%11 = OpLoad %v4float %v +OpBranch %12 +%12 = OpLabel +OpReturnValue %11 +OpFunctionEnd +)"; + + const std::string after = + R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %BaseColor "BaseColor" +OpName %bb_entry "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%8 = OpTypeFunction %v4float %_ptr_Function_v4float +%main = OpFunction %v4float None %8 +%BaseColor = OpFunctionParameter %_ptr_Function_v4float +%bb_entry = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%9 = OpLoad %v4float %BaseColor +OpStore %v %9 +%11 = OpLoad %v4float %v +OpReturnValue %11 +OpFunctionEnd +)"; + SinglePassRunAndCheck(before, after, true, true); +} + TEST_F(BlockMergeTest, EmptyBlock) { // Note: SPIR-V hand edited to insert empty block // after two statements in main. @@ -1038,6 +1095,112 @@ OpFunctionEnd SinglePassRunAndCheck(spirv, spirv, true, true); } +TEST_F(BlockMergeTest, DebugMerge) { + // Verify merge can be done completely, cleanly and validly in presence of + // NonSemantic.Shader.DebugInfo.100 instructions + const std::string text = R"( +; CHECK: OpLoopMerge +; CHECK-NEXT: OpBranch +; CHECK-NOT: OpBranch +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET +OpExecutionMode %main OriginUpperLeft +%5 = OpString "lexblock.hlsl" +%20 = OpString "float" +%32 = OpString "main" +%33 = OpString "" +%46 = OpString "b" +%49 = OpString "a" +%58 = OpString "c" +%63 = OpString "color" +OpName %in_var_COLOR "in.var.COLOR" +OpName %out_var_SV_TARGET "out.var.SV_TARGET" +OpName %main "main" +OpDecorate %in_var_COLOR Location 0 +OpDecorate %out_var_SV_TARGET Location 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%v4float = OpTypeVector %float 4 +%9 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%float_1 = OpConstant %float 1 +%13 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 +%uint = OpTypeInt 32 0 +%uint_32 = OpConstant %uint 32 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%void = OpTypeVoid +%uint_3 = OpConstant %uint 3 +%uint_0 = OpConstant %uint 0 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_5 = OpConstant %uint 5 +%uint_12 = OpConstant %uint 12 +%uint_13 = OpConstant %uint 13 +%uint_20 = OpConstant %uint 20 +%uint_15 = OpConstant %uint 15 +%uint_17 = OpConstant %uint 17 +%uint_16 = OpConstant %uint 16 +%uint_14 = OpConstant %uint 14 +%uint_10 = OpConstant %uint 10 +%65 = OpTypeFunction %void +%in_var_COLOR = OpVariable %_ptr_Input_v4float Input +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output +%62 = OpExtInst %void %1 DebugExpression +%22 = OpExtInst %void %1 DebugTypeBasic %20 %uint_32 %uint_3 %uint_0 +%25 = OpExtInst %void %1 DebugTypeVector %22 %uint_4 +%27 = OpExtInst %void %1 DebugTypeFunction %uint_3 %25 %25 +%28 = OpExtInst %void %1 DebugSource %5 +%29 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %28 %uint_5 +%34 = OpExtInst %void %1 DebugFunction %32 %27 %28 %uint_12 %uint_1 %29 %33 %uint_3 %uint_13 +%37 = OpExtInst %void %1 DebugLexicalBlock %28 %uint_13 %uint_1 %34 +%52 = OpExtInst %void %1 DebugLexicalBlock %28 %uint_15 %uint_12 %37 +%54 = OpExtInst %void %1 DebugLocalVariable %46 %25 %28 %uint_17 %uint_12 %52 %uint_4 +%56 = OpExtInst %void %1 DebugLocalVariable %49 %25 %28 %uint_16 %uint_12 %52 %uint_4 +%59 = OpExtInst %void %1 DebugLocalVariable %58 %25 %28 %uint_14 %uint_10 %37 %uint_4 +%64 = OpExtInst %void %1 DebugLocalVariable %63 %25 %28 %uint_12 %uint_20 %34 %uint_4 %uint_1 +%main = OpFunction %void None %65 +%66 = OpLabel +%69 = OpLoad %v4float %in_var_COLOR +%168 = OpExtInst %void %1 DebugValue %64 %69 %62 +%169 = OpExtInst %void %1 DebugScope %37 +OpLine %5 14 10 +%164 = OpExtInst %void %1 DebugValue %59 %9 %62 +OpLine %5 15 3 +OpBranch %150 +%150 = OpLabel +%165 = OpPhi %v4float %9 %66 %158 %159 +%167 = OpExtInst %void %1 DebugValue %59 %165 %62 +%170 = OpExtInst %void %1 DebugScope %37 +OpLine %5 15 12 +%171 = OpExtInst %void %1 DebugNoScope +OpLoopMerge %160 %159 None +OpBranch %151 +%151 = OpLabel +OpLine %5 16 12 +%162 = OpExtInst %void %1 DebugValue %56 %9 %62 +OpLine %5 17 12 +%163 = OpExtInst %void %1 DebugValue %54 %13 %62 +OpLine %5 18 15 +%158 = OpFAdd %v4float %165 %13 +OpLine %5 18 5 +%166 = OpExtInst %void %1 DebugValue %59 %158 %62 +%172 = OpExtInst %void %1 DebugScope %37 +OpLine %5 19 3 +OpBranch %159 +%159 = OpLabel +OpLine %5 19 3 +OpBranch %150 +%160 = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // More complex control flow diff --git a/third_party/spirv-tools/test/opt/ccp_test.cpp b/third_party/spirv-tools/test/opt/ccp_test.cpp index ef73435335..212e05140b 100644 --- a/third_party/spirv-tools/test/opt/ccp_test.cpp +++ b/third_party/spirv-tools/test/opt/ccp_test.cpp @@ -1208,6 +1208,32 @@ TEST_F(CCPTest, CCPNoChangeFailureWithUnfoldableInstr) { auto result = SinglePassRunAndMatch(text, true); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } + +TEST_F(CCPTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp b/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp index aed14c9deb..5be3ba6384 100644 --- a/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp +++ b/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp @@ -768,6 +768,32 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(CombineAccessChainsTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/control_dependence.cpp b/third_party/spirv-tools/test/opt/control_dependence.cpp new file mode 100644 index 0000000000..4665547222 --- /dev/null +++ b/third_party/spirv-tools/test/opt/control_dependence.cpp @@ -0,0 +1,306 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/control_dependence.h" + +#include +#include + +#include "gmock/gmock-matchers.h" +#include "gtest/gtest.h" +#include "source/opt/build_module.h" +#include "source/opt/cfg.h" +#include "test/opt/function_utils.h" + +namespace spvtools { +namespace opt { + +namespace { +void GatherEdges(const ControlDependenceAnalysis& cdg, + std::vector& ret) { + cdg.ForEachBlockLabel([&](uint32_t label) { + ret.reserve(ret.size() + cdg.GetDependenceTargets(label).size()); + ret.insert(ret.end(), cdg.GetDependenceTargets(label).begin(), + cdg.GetDependenceTargets(label).end()); + }); + std::sort(ret.begin(), ret.end()); + // Verify that reverse graph is the same. + std::vector reverse_edges; + reverse_edges.reserve(ret.size()); + cdg.ForEachBlockLabel([&](uint32_t label) { + reverse_edges.insert(reverse_edges.end(), + cdg.GetDependenceSources(label).begin(), + cdg.GetDependenceSources(label).end()); + }); + std::sort(reverse_edges.begin(), reverse_edges.end()); + ASSERT_THAT(reverse_edges, testing::ElementsAreArray(ret)); +} + +using ControlDependenceTest = ::testing::Test; + +TEST(ControlDependenceTest, DependenceSimpleCFG) { + const std::string text = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %1 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpTypeInt 32 0 + %6 = OpConstant %5 0 + %7 = OpConstantFalse %4 + %8 = OpConstantTrue %4 + %9 = OpConstant %5 1 + %1 = OpFunction %2 None %3 + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + OpSwitch %6 %12 1 %13 + %12 = OpLabel + OpBranch %14 + %13 = OpLabel + OpBranch %14 + %14 = OpLabel + OpBranchConditional %8 %15 %16 + %15 = OpLabel + OpBranch %19 + %16 = OpLabel + OpBranchConditional %8 %17 %18 + %17 = OpLabel + OpBranch %18 + %18 = OpLabel + OpBranch %19 + %19 = OpLabel + OpReturn + OpFunctionEnd +)"; + + // CFG: (all edges pointing downward) + // %10 + // | + // %11 + // / \ (R: %6 == 1, L: default) + // %12 %13 + // \ / + // %14 + // T/ \F + // %15 %16 + // | T/ |F + // | %17| + // | \ | + // | %18 + // | / + // %19 + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + Module* module = context->module(); + EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" + << text << std::endl; + const Function* fn = spvtest::GetFunction(module, 1); + const BasicBlock* entry = spvtest::GetBasicBlock(fn, 10); + EXPECT_EQ(entry, fn->entry().get()) + << "The entry node is not the expected one"; + + { + PostDominatorAnalysis pdom; + const CFG& cfg = *context->cfg(); + pdom.InitializeTree(cfg, fn); + ControlDependenceAnalysis cdg; + cdg.ComputeControlDependenceGraph(cfg, pdom); + + // Test HasBlock. + for (uint32_t id = 10; id <= 19; id++) { + EXPECT_TRUE(cdg.HasBlock(id)); + } + EXPECT_TRUE(cdg.HasBlock(ControlDependenceAnalysis::kPseudoEntryBlock)); + // Check blocks before/after valid range. + EXPECT_FALSE(cdg.HasBlock(5)); + EXPECT_FALSE(cdg.HasBlock(25)); + EXPECT_FALSE(cdg.HasBlock(UINT32_MAX)); + + // Test ForEachBlockLabel. + std::set block_labels; + cdg.ForEachBlockLabel([&block_labels](uint32_t id) { + bool inserted = block_labels.insert(id).second; + EXPECT_TRUE(inserted); // Should have no duplicates. + }); + EXPECT_THAT(block_labels, testing::ElementsAre(0, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19)); + + { + // Test WhileEachBlockLabel. + uint32_t iters = 0; + EXPECT_TRUE(cdg.WhileEachBlockLabel([&iters](uint32_t) { + ++iters; + return true; + })); + EXPECT_EQ((uint32_t)block_labels.size(), iters); + iters = 0; + EXPECT_FALSE(cdg.WhileEachBlockLabel([&iters](uint32_t) { + ++iters; + return false; + })); + EXPECT_EQ(1, iters); + } + + // Test IsDependent. + EXPECT_TRUE(cdg.IsDependent(12, 11)); + EXPECT_TRUE(cdg.IsDependent(13, 11)); + EXPECT_TRUE(cdg.IsDependent(15, 14)); + EXPECT_TRUE(cdg.IsDependent(16, 14)); + EXPECT_TRUE(cdg.IsDependent(18, 14)); + EXPECT_TRUE(cdg.IsDependent(17, 16)); + EXPECT_TRUE(cdg.IsDependent(10, 0)); + EXPECT_TRUE(cdg.IsDependent(11, 0)); + EXPECT_TRUE(cdg.IsDependent(14, 0)); + EXPECT_TRUE(cdg.IsDependent(19, 0)); + EXPECT_FALSE(cdg.IsDependent(14, 11)); + EXPECT_FALSE(cdg.IsDependent(17, 14)); + EXPECT_FALSE(cdg.IsDependent(19, 14)); + EXPECT_FALSE(cdg.IsDependent(12, 0)); + + // Test GetDependenceSources/Targets. + std::vector edges; + GatherEdges(cdg, edges); + EXPECT_THAT(edges, + testing::ElementsAre( + ControlDependence(0, 10), ControlDependence(0, 11, 10), + ControlDependence(0, 14, 10), ControlDependence(0, 19, 10), + ControlDependence(11, 12), ControlDependence(11, 13), + ControlDependence(14, 15), ControlDependence(14, 16), + ControlDependence(14, 18, 16), ControlDependence(16, 17))); + + const uint32_t expected_condition_ids[] = { + 0, 0, 0, 0, 6, 6, 8, 8, 8, 8, + }; + + for (uint32_t i = 0; i < edges.size(); i++) { + EXPECT_EQ(expected_condition_ids[i], edges[i].GetConditionID(cfg)); + } + } +} + +TEST(ControlDependenceTest, DependencePaperCFG) { + const std::string text = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %101 "main" + %102 = OpTypeVoid + %103 = OpTypeFunction %102 + %104 = OpTypeBool + %108 = OpConstantTrue %104 + %101 = OpFunction %102 None %103 + %1 = OpLabel + OpBranch %2 + %2 = OpLabel + OpBranchConditional %108 %3 %7 + %3 = OpLabel + OpBranchConditional %108 %4 %5 + %4 = OpLabel + OpBranch %6 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpBranch %8 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpBranchConditional %108 %10 %11 + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + OpBranchConditional %108 %12 %9 + %12 = OpLabel + OpBranchConditional %108 %13 %2 + %13 = OpLabel + OpReturn + OpFunctionEnd +)"; + + // CFG: (edges pointing downward if no arrow) + // %1 + // | + // %2 <----+ + // T/ \F | + // %3 \ | + // T/ \F \ | + // %4 %5 %7 | + // \ / / | + // %6 / | + // \ / | + // %8 | + // | | + // %9 <-+ | + // T/ | | | + // %10 | | | + // \ | | | + // %11-F+ | + // T| | + // %12-F---+ + // T| + // %13 + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + Module* module = context->module(); + EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" + << text << std::endl; + const Function* fn = spvtest::GetFunction(module, 101); + const BasicBlock* entry = spvtest::GetBasicBlock(fn, 1); + EXPECT_EQ(entry, fn->entry().get()) + << "The entry node is not the expected one"; + + { + PostDominatorAnalysis pdom; + const CFG& cfg = *context->cfg(); + pdom.InitializeTree(cfg, fn); + ControlDependenceAnalysis cdg; + cdg.ComputeControlDependenceGraph(cfg, pdom); + + std::vector edges; + GatherEdges(cdg, edges); + EXPECT_THAT( + edges, testing::ElementsAre( + ControlDependence(0, 1), ControlDependence(0, 2, 1), + ControlDependence(0, 8, 1), ControlDependence(0, 9, 1), + ControlDependence(0, 11, 1), ControlDependence(0, 12, 1), + ControlDependence(0, 13, 1), ControlDependence(2, 3), + ControlDependence(2, 6, 3), ControlDependence(2, 7), + ControlDependence(3, 4), ControlDependence(3, 5), + ControlDependence(9, 10), ControlDependence(11, 9), + ControlDependence(11, 11, 9), ControlDependence(12, 2), + ControlDependence(12, 8, 2), ControlDependence(12, 9, 2), + ControlDependence(12, 11, 2), ControlDependence(12, 12, 2))); + + const uint32_t expected_condition_ids[] = { + 0, 0, 0, 0, 0, 0, 0, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + }; + + for (uint32_t i = 0; i < edges.size(); i++) { + EXPECT_EQ(expected_condition_ids[i], edges[i].GetConditionID(cfg)); + } + } +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp b/third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp index ca6ee5838e..6a06de84f7 100644 --- a/third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp +++ b/third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp @@ -204,6 +204,98 @@ OpFunctionEnd defs_after + func_after, true, true); } +TEST_F(ConvertToHalfTest, ConvertToHalfForLinkage) { + const std::string before = + R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %type_cbuff "type.cbuff" +OpMemberName %type_cbuff 0 "c" +OpName %cbuff "cbuff" +OpName %main "main" +OpName %BaseColor "BaseColor" +OpName %bb_entry "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +OpDecorate %cbuff DescriptorSet 0 +OpDecorate %cbuff Binding 0 +OpMemberDecorate %type_cbuff 0 Offset 0 +OpDecorate %type_cbuff Block +OpDecorate %18 RelaxedPrecision +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%type_cbuff = OpTypeStruct %float +%_ptr_Uniform_type_cbuff = OpTypePointer Uniform %type_cbuff +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%9 = OpTypeFunction %v4float %_ptr_Function_v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%cbuff = OpVariable %_ptr_Uniform_type_cbuff Uniform +%main = OpFunction %v4float None %9 +%BaseColor = OpFunctionParameter %_ptr_Function_v4float +%bb_entry = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%14 = OpLoad %v4float %BaseColor +%16 = OpAccessChain %_ptr_Uniform_float %cbuff %int_0 +%17 = OpLoad %float %16 +%18 = OpVectorTimesScalar %v4float %14 %17 +OpStore %v %18 +%19 = OpLoad %v4float %v +OpReturnValue %19 +OpFunctionEnd +)"; + + const std::string after = + R"(OpCapability Shader +OpCapability Linkage +OpCapability Float16 +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %type_cbuff "type.cbuff" +OpMemberName %type_cbuff 0 "c" +OpName %cbuff "cbuff" +OpName %main "main" +OpName %BaseColor "BaseColor" +OpName %bb_entry "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +OpDecorate %cbuff DescriptorSet 0 +OpDecorate %cbuff Binding 0 +OpMemberDecorate %type_cbuff 0 Offset 0 +OpDecorate %type_cbuff Block +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%type_cbuff = OpTypeStruct %float +%_ptr_Uniform_type_cbuff = OpTypePointer Uniform %type_cbuff +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%14 = OpTypeFunction %v4float %_ptr_Function_v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%cbuff = OpVariable %_ptr_Uniform_type_cbuff Uniform +%half = OpTypeFloat 16 +%v4half = OpTypeVector %half 4 +%main = OpFunction %v4float None %14 +%BaseColor = OpFunctionParameter %_ptr_Function_v4float +%bb_entry = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%16 = OpLoad %v4float %BaseColor +%17 = OpAccessChain %_ptr_Uniform_float %cbuff %int_0 +%18 = OpLoad %float %17 +%22 = OpFConvert %v4half %16 +%23 = OpFConvert %half %18 +%7 = OpVectorTimesScalar %v4half %22 %23 +%24 = OpFConvert %v4float %7 +OpStore %v %24 +%19 = OpLoad %v4float %v +OpReturnValue %19 +OpFunctionEnd +)"; + + SinglePassRunAndCheck(before, after, true, true); +} TEST_F(ConvertToHalfTest, ConvertToHalfWithDrefSample) { // The resulting SPIR-V was processed with --relax-float-ops. // @@ -1397,6 +1489,87 @@ TEST_F(ConvertToHalfTest, RemoveRelaxDec) { EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); } +TEST_F(ConvertToHalfTest, HandleNonRelaxedPhi) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4452 + + // This test is a case with a non-relaxed phi with a relaxed operand. + // A convert must be inserted at the end of the block associated with + // the operand. + const std::string test = + R"( +; CHECK: [[fcvt:%\w+]] = OpFConvert %v3float {{%\w+}} +; CHECK-NEXT: OpSelectionMerge {{%\w+}} None +; CHECK: {{%\w+}} = OpPhi %v3float [[fcvt]] {{%\w+}} {{%\w+}} {{%\w+}} + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %output_color + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %MaterialParams "MaterialParams" + OpMemberName %MaterialParams 0 "foo" + OpName %materialParams "materialParams" + OpName %output_color "output_color" + OpMemberDecorate %MaterialParams 0 Offset 0 + OpDecorate %MaterialParams Block + OpDecorate %materialParams DescriptorSet 0 + OpDecorate %materialParams Binding 5 + OpDecorate %output_color Location 0 + OpDecorate %57 RelaxedPrecision + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 +%MaterialParams = OpTypeStruct %float +%_ptr_Uniform_MaterialParams = OpTypePointer Uniform %MaterialParams +%materialParams = OpVariable %_ptr_Uniform_MaterialParams Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %float_0 = OpConstant %float 0 + %bool = OpTypeBool + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%output_color = OpVariable %_ptr_Output_v4float Output + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Output_float = OpTypePointer Output %float + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %float_0_5 = OpConstant %float 0.5 + %61 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 + %main = OpFunction %void None %3 + %5 = OpLabel + %55 = OpAccessChain %_ptr_Uniform_float %materialParams %int_0 + %56 = OpLoad %float %55 + %57 = OpCompositeConstruct %v3float %56 %56 %56 + %31 = OpFOrdGreaterThan %bool %56 %float_0 + OpSelectionMerge %33 None + OpBranchConditional %31 %32 %33 + %32 = OpLabel + %37 = OpFMul %v3float %57 %61 + OpBranch %33 + %33 = OpLabel + %58 = OpPhi %v3float %57 %5 %37 %32 + %45 = OpAccessChain %_ptr_Output_float %output_color %uint_0 + %46 = OpCompositeExtract %float %58 0 + OpStore %45 %46 + %48 = OpAccessChain %_ptr_Output_float %output_color %uint_1 + %49 = OpCompositeExtract %float %58 1 + OpStore %48 %49 + %51 = OpAccessChain %_ptr_Output_float %output_color %uint_2 + %52 = OpCompositeExtract %float %58 2 + OpStore %51 %52 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunAndMatch(test, true); + EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/convert_to_sampled_image_test.cpp b/third_party/spirv-tools/test/opt/convert_to_sampled_image_test.cpp new file mode 100644 index 0000000000..37f6560109 --- /dev/null +++ b/third_party/spirv-tools/test/opt/convert_to_sampled_image_test.cpp @@ -0,0 +1,353 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 "gmock/gmock.h" +#include "source/opt/convert_to_sampled_image_pass.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using testing::Eq; +using VectorOfDescriptorSetAndBindingPairs = + std::vector; + +struct DescriptorSetAndBindingStringParsingTestCase { + const char* descriptor_set_binding_str; + bool expect_success; + VectorOfDescriptorSetAndBindingPairs expected_descriptor_set_binding_pairs; +}; + +using DescriptorSetAndBindingStringParsingTest = + ::testing::TestWithParam; + +TEST_P(DescriptorSetAndBindingStringParsingTest, TestCase) { + const auto& tc = GetParam(); + auto actual_descriptor_set_binding_pairs = + ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString( + tc.descriptor_set_binding_str); + if (tc.expect_success) { + EXPECT_NE(nullptr, actual_descriptor_set_binding_pairs); + if (actual_descriptor_set_binding_pairs) { + EXPECT_THAT(*actual_descriptor_set_binding_pairs, + Eq(tc.expected_descriptor_set_binding_pairs)); + } + } else { + EXPECT_EQ(nullptr, actual_descriptor_set_binding_pairs); + } +} + +INSTANTIATE_TEST_SUITE_P( + ValidString, DescriptorSetAndBindingStringParsingTest, + ::testing::ValuesIn(std::vector< + DescriptorSetAndBindingStringParsingTestCase>{ + // 0. empty vector + {"", true, VectorOfDescriptorSetAndBindingPairs({})}, + // 1. one pair + {"100:1024", true, + VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100, + 1024}})}, + // 2. two pairs + {"100:1024 200:2048", true, + VectorOfDescriptorSetAndBindingPairs( + {DescriptorSetAndBinding{100, 1024}, + DescriptorSetAndBinding{200, 2048}})}, + // 3. spaces between entries + {"100:1024 \n \r \t \v \f 200:2048", true, + VectorOfDescriptorSetAndBindingPairs( + {DescriptorSetAndBinding{100, 1024}, + DescriptorSetAndBinding{200, 2048}})}, + // 4. \t, \n, \r and spaces before spec id + {" \n \r\t \t \v \f 100:1024", true, + VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100, + 1024}})}, + // 5. \t, \n, \r and spaces after value string + {"100:1024 \n \r\t \t \v \f ", true, + VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100, + 1024}})}, + // 6. maximum spec id + {"4294967295:0", true, + VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{ + 4294967295, 0}})}, + // 7. minimum spec id + {"0:100", true, + VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{0, + 100}})}, + // 8. multiple entries + {"101:1 102:2 103:3 104:4 200:201 9999:1000", true, + VectorOfDescriptorSetAndBindingPairs( + {DescriptorSetAndBinding{101, 1}, DescriptorSetAndBinding{102, 2}, + DescriptorSetAndBinding{103, 3}, DescriptorSetAndBinding{104, 4}, + DescriptorSetAndBinding{200, 201}, + DescriptorSetAndBinding{9999, 1000}})}, + })); + +INSTANTIATE_TEST_SUITE_P( + InvalidString, DescriptorSetAndBindingStringParsingTest, + ::testing::ValuesIn( + std::vector{ + // 0. missing default value + {"100:", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 1. descriptor set is not an integer + {"100.0:200", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 2. descriptor set is not a number + {"something_not_a_number:1", false, + VectorOfDescriptorSetAndBindingPairs{}}, + // 3. only descriptor set number + {"100", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 4. empty descriptor set + {":3", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 5. only colon + {":", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 6. descriptor set overflow + {"4294967296:200", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 7. descriptor set less than 0 + {"-1:200", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 8. nullptr + {nullptr, false, VectorOfDescriptorSetAndBindingPairs{}}, + // 9. only a number is invalid + {"1234", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 10. invalid entry separator + {"12:34;23:14", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 11. invalid descriptor set and default value separator + {"12@34", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 12. spaces before colon + {"100 :1024", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 13. spaces after colon + {"100: 1024", false, VectorOfDescriptorSetAndBindingPairs{}}, + // 14. descriptor set represented in hex float format is invalid + {"0x3p10:200", false, VectorOfDescriptorSetAndBindingPairs{}}, + })); + +std::string BuildShader(const char* shader_decorate_instructions, + const char* shader_image_and_sampler_variables, + const char* shader_body) { + // Base HLSL code: + // + // SamplerState sam : register(s2); + // Texture2D texture : register(t5); + // + // float4 main() : SV_TARGET { + // return texture.SampleLevel(sam, float2(1, 2), 10, 2); + // } + std::stringstream ss; + ss << R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %out_var_SV_TARGET + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + OpName %type_sampler "type.sampler" + OpName %type_2d_image "type.2d.image" + OpName %out_var_SV_TARGET "out.var.SV_TARGET" + OpName %main "main" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %out_var_SV_TARGET Location 0 + )"; + ss << shader_decorate_instructions; + ss << R"( + %float = OpTypeFloat 32 + %float_1 = OpConstant %float 1 + %float_2 = OpConstant %float 2 + %v2float = OpTypeVector %float 2 + %12 = OpConstantComposite %v2float %float_1 %float_2 + %float_10 = OpConstant %float 10 + %int = OpTypeInt 32 1 + %int_2 = OpConstant %int 2 + %v2int = OpTypeVector %int 2 + %17 = OpConstantComposite %v2int %int_2 %int_2 +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %23 = OpTypeFunction %void +%type_sampled_image = OpTypeSampledImage %type_2d_image + )"; + ss << shader_image_and_sampler_variables; + ss << R"( +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %23 + %24 = OpLabel + )"; + ss << shader_body; + ss << R"( + OpReturn + OpFunctionEnd + )"; + return ss.str(); +} + +using ConvertToSampledImageTest = PassTest<::testing::Test>; + +TEST_F(ConvertToSampledImageTest, Texture2DAndSamplerToSampledImage) { + const std::string shader = BuildShader( + R"( + OpDecorate %sam DescriptorSet 0 + OpDecorate %sam Binding 5 + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 5 + )", + R"( + ; CHECK-NOT: OpVariable %_ptr_UniformConstant_type_2d_image + + ; CHECK: [[tex:%\w+]] = OpVariable %_ptr_UniformConstant_type_sampled_image UniformConstant + %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + )", + R"( + ; CHECK: [[load:%\w+]] = OpLoad %type_sampled_image [[tex]] + ; CHECK: OpImageSampleExplicitLod %v4float [[load]] + %25 = OpLoad %type_2d_image %texture + %26 = OpLoad %type_sampler %sam + %27 = OpSampledImage %type_sampled_image %25 %26 + %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17 + OpStore %out_var_SV_TARGET %28 + )"); + + auto result = SinglePassRunAndMatch( + shader, /* do_validate = */ true, + VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}}); + + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(ConvertToSampledImageTest, Texture2DToSampledImage) { + const std::string shader = BuildShader( + R"( + OpDecorate %sam DescriptorSet 0 + OpDecorate %sam Binding 2 + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 5 + )", + R"( + ; CHECK: [[tex:%\w+]] = OpVariable %_ptr_UniformConstant_type_sampled_image UniformConstant + %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + )", + R"( + ; CHECK: [[load:%\w+]] = OpLoad %type_sampled_image [[tex]] + ; CHECK: [[image_extraction:%\w+]] = OpImage %type_2d_image [[load]] + ; CHECK: OpSampledImage %type_sampled_image [[image_extraction]] + %25 = OpLoad %type_2d_image %texture + %26 = OpLoad %type_sampler %sam + %27 = OpSampledImage %type_sampled_image %25 %26 + %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17 + OpStore %out_var_SV_TARGET %28 + )"); + + auto result = SinglePassRunAndMatch( + shader, /* do_validate = */ true, + VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}}); + + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(ConvertToSampledImageTest, SamplerToSampledImage) { + const std::string shader = BuildShader( + R"( + OpDecorate %sam DescriptorSet 0 + OpDecorate %sam Binding 2 + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 5 + )", + R"( + %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + )", + R"( + %25 = OpLoad %type_2d_image %texture + %26 = OpLoad %type_sampler %sam + %27 = OpSampledImage %type_sampled_image %25 %26 + %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17 + OpStore %out_var_SV_TARGET %28 + )"); + + auto result = SinglePassRunToBinary( + shader, /* skip_nop = */ false, + VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 2}}); + + EXPECT_EQ(std::get<1>(result), Pass::Status::Failure); +} + +TEST_F(ConvertToSampledImageTest, TwoImagesWithDuplicatedDescriptorSetBinding) { + const std::string shader = BuildShader( + R"( + OpDecorate %sam DescriptorSet 0 + OpDecorate %sam Binding 2 + OpDecorate %texture0 DescriptorSet 0 + OpDecorate %texture0 Binding 5 + OpDecorate %texture1 DescriptorSet 0 + OpDecorate %texture1 Binding 5 + )", + R"( + %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %texture0 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + %texture1 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + )", + R"( + %25 = OpLoad %type_2d_image %texture0 + %26 = OpLoad %type_sampler %sam + %27 = OpSampledImage %type_sampled_image %25 %26 + %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17 + OpStore %out_var_SV_TARGET %28 + )"); + + auto result = SinglePassRunToBinary( + shader, /* skip_nop = */ false, + VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}}); + + EXPECT_EQ(std::get<1>(result), Pass::Status::Failure); +} + +TEST_F(ConvertToSampledImageTest, + TwoSamplersWithDuplicatedDescriptorSetBinding) { + const std::string shader = BuildShader( + R"( + OpDecorate %sam0 DescriptorSet 0 + OpDecorate %sam0 Binding 2 + OpDecorate %sam1 DescriptorSet 0 + OpDecorate %sam1 Binding 2 + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 5 + )", + R"( + %sam0 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %sam1 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + )", + R"( + %25 = OpLoad %type_2d_image %texture + %26 = OpLoad %type_sampler %sam0 + %27 = OpSampledImage %type_sampled_image %25 %26 + %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17 + OpStore %out_var_SV_TARGET %28 + )"); + + auto result = SinglePassRunToBinary( + shader, /* skip_nop = */ false, + VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 2}}); + + EXPECT_EQ(std::get<1>(result), Pass::Status::Failure); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp b/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp index 72bc7f6f69..a4599f0f6d 100644 --- a/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp +++ b/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp @@ -1814,6 +1814,31 @@ OpFunctionEnd SinglePassRunAndMatch(before, false); } +TEST_F(CopyPropArrayPassTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/dataflow.cpp b/third_party/spirv-tools/test/opt/dataflow.cpp new file mode 100644 index 0000000000..4742015a73 --- /dev/null +++ b/third_party/spirv-tools/test/opt/dataflow.cpp @@ -0,0 +1,225 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/dataflow.h" + +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "opt/function_utils.h" +#include "source/opt/build_module.h" + +namespace spvtools { +namespace opt { +namespace { + +using DataFlowTest = ::testing::Test; + +// Simple analyses for testing: + +// Stores the result IDs of visited instructions in visit order. +struct VisitOrder : public ForwardDataFlowAnalysis { + std::vector visited_result_ids; + + VisitOrder(IRContext& context, LabelPosition label_position) + : ForwardDataFlowAnalysis(context, label_position) {} + + VisitResult Visit(Instruction* inst) override { + if (inst->HasResultId()) { + visited_result_ids.push_back(inst->result_id()); + } + return DataFlowAnalysis::VisitResult::kResultFixed; + } +}; + +// For each block, stores the set of blocks it can be preceded by. +// For example, with the following CFG: +// V-----------. +// -> 11 -> 12 -> 13 -> 15 +// \-> 14 ---^ +// +// The answer is: +// 11: 11, 12, 13 +// 12: 11, 12, 13 +// 13: 11, 12, 13 +// 14: 11, 12, 13 +// 15: 11, 12, 13, 14 +struct BackwardReachability : public ForwardDataFlowAnalysis { + std::map> reachable_from; + + BackwardReachability(IRContext& context) + : ForwardDataFlowAnalysis( + context, ForwardDataFlowAnalysis::LabelPosition::kLabelsOnly) {} + + VisitResult Visit(Instruction* inst) override { + // Conditional branches can be enqueued from labels, so skip them. + if (inst->opcode() != SpvOpLabel) + return DataFlowAnalysis::VisitResult::kResultFixed; + uint32_t id = inst->result_id(); + VisitResult ret = DataFlowAnalysis::VisitResult::kResultFixed; + std::set& precedents = reachable_from[id]; + for (uint32_t pred : context().cfg()->preds(id)) { + bool pred_inserted = precedents.insert(pred).second; + if (pred_inserted) { + ret = DataFlowAnalysis::VisitResult::kResultChanged; + } + for (uint32_t block : reachable_from[pred]) { + bool inserted = precedents.insert(block).second; + if (inserted) { + ret = DataFlowAnalysis::VisitResult::kResultChanged; + } + } + } + return ret; + } + + void InitializeWorklist(Function* function, + bool is_first_iteration) override { + // Since successor function is exact, only need one pass. + if (is_first_iteration) { + ForwardDataFlowAnalysis::InitializeWorklist(function, true); + } + } +}; + +TEST_F(DataFlowTest, ReversePostOrder) { + // Note: labels and IDs are intentionally out of order. + // + // CFG: (order of branches is from bottom to top) + // V-----------. + // -> 50 -> 40 -> 20 -> 60 -> 70 + // \-> 30 ---^ + + // DFS tree with RPO numbering: + // -> 50[0] -> 40[1] -> 20[2] 60[4] -> 70[5] + // \-> 30[3] ---^ + + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %6 = OpTypeBool + %5 = OpConstantTrue %6 + %2 = OpFunction %3 None %4 + %50 = OpLabel + %51 = OpUndef %6 + %52 = OpUndef %6 + OpBranch %40 + %70 = OpLabel + %69 = OpUndef %6 + OpReturn + %60 = OpLabel + %61 = OpUndef %6 + OpBranchConditional %5 %70 %40 + %30 = OpLabel + %29 = OpUndef %6 + OpBranch %60 + %20 = OpLabel + %21 = OpUndef %6 + OpBranch %60 + %40 = OpLabel + %39 = OpUndef %6 + OpBranchConditional %5 %30 %20 + OpFunctionEnd + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(context, nullptr); + + Function* function = spvtest::GetFunction(context->module(), 2); + + std::map> + expected_order; + expected_order[ForwardDataFlowAnalysis::LabelPosition::kLabelsOnly] = { + 50, 40, 20, 30, 60, 70, + }; + expected_order[ForwardDataFlowAnalysis::LabelPosition::kLabelsAtBeginning] = { + 50, 51, 52, 40, 39, 20, 21, 30, 29, 60, 61, 70, 69, + }; + expected_order[ForwardDataFlowAnalysis::LabelPosition::kLabelsAtEnd] = { + 51, 52, 50, 39, 40, 21, 20, 29, 30, 61, 60, 69, 70, + }; + expected_order[ForwardDataFlowAnalysis::LabelPosition::kNoLabels] = { + 51, 52, 39, 21, 29, 61, 69, + }; + + for (const auto& test_case : expected_order) { + VisitOrder analysis(*context, test_case.first); + analysis.Run(function); + EXPECT_EQ(test_case.second, analysis.visited_result_ids); + } +} + +TEST_F(DataFlowTest, BackwardReachability) { + // CFG: + // V-----------. + // -> 11 -> 12 -> 13 -> 15 + // \-> 14 ---^ + + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %6 = OpTypeBool + %5 = OpConstantTrue %6 + %2 = OpFunction %3 None %4 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpBranchConditional %5 %14 %13 + %13 = OpLabel + OpBranchConditional %5 %15 %11 + %14 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(context, nullptr); + + Function* function = spvtest::GetFunction(context->module(), 2); + + BackwardReachability analysis(*context); + analysis.Run(function); + + std::map> expected_result; + expected_result[11] = {11, 12, 13}; + expected_result[12] = {11, 12, 13}; + expected_result[13] = {11, 12, 13}; + expected_result[14] = {11, 12, 13}; + expected_result[15] = {11, 12, 13, 14}; + EXPECT_EQ(expected_result, analysis.reachable_from); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp b/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp index f89befb496..9c1ef2a317 100644 --- a/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp @@ -3403,6 +3403,71 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(DeadBranchElimTest, DontTransferDecorations) { + // When replacing %4 with %14, we don't want %14 to inherit %4's decorations. + const std::string text = R"( +; CHECK-NOT: OpDecorate {{%\w+}} RelaxedPrecision +; CHECK: [[div:%\w+]] = OpFDiv +; CHECK: {{%\w+}} = OpCopyObject %float [[div]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + %3 = OpString "STEVEN" + OpDecorate %4 RelaxedPrecision + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %void = OpTypeVoid + %float_1 = OpConstant %float 1 + %uint_0 = OpConstant %uint 0 + %10 = OpTypeFunction %void + %2 = OpFunction %void None %10 + %11 = OpLabel + OpSelectionMerge %12 None + OpSwitch %uint_0 %13 + %13 = OpLabel + %14 = OpFDiv %float %float_1 %float_1 + OpLine %3 0 0 + OpBranch %12 + %15 = OpLabel + OpBranch %12 + %12 = OpLabel + %4 = OpPhi %float %float_1 %15 %14 %13 + %16 = OpCopyObject %float %4 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(DeadBranchElimTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // More complex control flow diff --git a/third_party/spirv-tools/test/opt/dead_insert_elim_test.cpp b/third_party/spirv-tools/test/opt/dead_insert_elim_test.cpp index 9ea948a49c..268e659063 100644 --- a/third_party/spirv-tools/test/opt/dead_insert_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/dead_insert_elim_test.cpp @@ -170,6 +170,72 @@ OpFunctionEnd after_predefs + after, true, true); } +TEST_F(DeadInsertElimTest, DeadInsertForLinkage) { + const std::string before = + R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %BaseColor "BaseColor" +OpName %bb_entry "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%v2float = OpTypeVector %float 2 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%14 = OpTypeFunction %v2float %_ptr_Function_v2float +%_ptr_Function_float = OpTypePointer Function %float +%main = OpFunction %v2float None %14 +%BaseColor = OpFunctionParameter %_ptr_Function_v2float +%bb_entry = OpLabel +%v = OpVariable %_ptr_Function_v2float Function +%16 = OpLoad %v2float %v +%17 = OpAccessChain %_ptr_Function_float %BaseColor %int_1 +%18 = OpLoad %float %17 +%19 = OpCompositeInsert %v2float %18 %16 0 +%20 = OpCompositeInsert %v2float %float_0 %19 0 +OpReturnValue %20 +OpFunctionEnd +)"; + const std::string after = + R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %BaseColor "BaseColor" +OpName %bb_entry "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +%int = OpTypeInt 32 1 +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%v2float = OpTypeVector %float 2 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%14 = OpTypeFunction %v2float %_ptr_Function_v2float +%_ptr_Function_float = OpTypePointer Function %float +%main = OpFunction %v2float None %14 +%BaseColor = OpFunctionParameter %_ptr_Function_v2float +%bb_entry = OpLabel +%v = OpVariable %_ptr_Function_v2float Function +%16 = OpLoad %v2float %v +%20 = OpCompositeInsert %v2float %float_0 %16 0 +OpReturnValue %20 +OpFunctionEnd +)"; + SinglePassRunAndCheck(before, after, true, true); +} + TEST_F(DeadInsertElimTest, DeadInsertInChainWithPhi) { // Dead insert eliminated with phi in insertion chain. // diff --git a/third_party/spirv-tools/test/opt/debug_info_manager_test.cpp b/third_party/spirv-tools/test/opt/debug_info_manager_test.cpp index 49407fd580..e87d0beaf7 100644 --- a/third_party/spirv-tools/test/opt/debug_info_manager_test.cpp +++ b/third_party/spirv-tools/test/opt/debug_info_manager_test.cpp @@ -185,6 +185,122 @@ void main(float in_var_color : COLOR) { 100U); } +TEST(DebugInfoManager, CreateDebugInlinedAtWithConstantManager) { + // Show that CreateDebugInlinedAt will use the Constant manager to generate + // its line operand if the Constant and DefUse managers are valid. This is + // proven by checking that the id for the line operand 7 is the same as the + // existing constant 7. + // + // int function1() { + // return 1; + // } + // + // void main() { + // function1(); + // } + const std::string text = R"(OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%3 = OpString "parent3.hlsl" +%8 = OpString "int" +%19 = OpString "function1" +%20 = OpString "" +%26 = OpString "main" +OpName %main "main" +OpName %src_main "src.main" +OpName %bb_entry "bb.entry" +OpName %function1 "function1" +OpName %bb_entry_0 "bb.entry" +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%uint = OpTypeInt 32 0 +%uint_32 = OpConstant %uint 32 +%void = OpTypeVoid +%uint_4 = OpConstant %uint 4 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%uint_1 = OpConstant %uint 1 +%uint_5 = OpConstant %uint 5 +%uint_2 = OpConstant %uint 2 +%uint_17 = OpConstant %uint 17 +%uint_6 = OpConstant %uint 6 +%uint_13 = OpConstant %uint 13 +%100 = OpConstant %uint 7 +%31 = OpTypeFunction %void +%42 = OpTypeFunction %int +%10 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_4 %uint_0 +%13 = OpExtInst %void %1 DebugTypeFunction %uint_3 %10 +%15 = OpExtInst %void %1 DebugSource %3 +%16 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %15 %uint_5 +%21 = OpExtInst %void %1 DebugFunction %19 %13 %15 %uint_2 %uint_1 %16 %20 %uint_3 %uint_2 +%23 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_2 %uint_17 %21 +%25 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void +%27 = OpExtInst %void %1 DebugFunction %26 %25 %15 %uint_6 %uint_1 %16 %20 %uint_3 %uint_6 +%29 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_6 %uint_13 %27 +%main = OpFunction %void None %31 +%32 = OpLabel +%33 = OpFunctionCall %void %src_main +OpLine %3 8 1 +OpReturn +OpFunctionEnd +OpLine %3 6 1 +%src_main = OpFunction %void None %31 +OpNoLine +%bb_entry = OpLabel +%47 = OpExtInst %void %1 DebugScope %27 +%37 = OpExtInst %void %1 DebugFunctionDefinition %27 %src_main +%48 = OpExtInst %void %1 DebugScope %29 +OpLine %3 7 3 +%39 = OpFunctionCall %int %function1 +%49 = OpExtInst %void %1 DebugScope %27 +OpLine %3 8 1 +OpReturn +%50 = OpExtInst %void %1 DebugNoScope +OpFunctionEnd +OpLine %3 2 1 +%function1 = OpFunction %int None %42 +OpNoLine +%bb_entry_0 = OpLabel +%51 = OpExtInst %void %1 DebugScope %21 +%45 = OpExtInst %void %1 DebugFunctionDefinition %21 %function1 +%52 = OpExtInst %void %1 DebugScope %23 +OpLine %3 3 3 +OpReturnValue %int_1 +%53 = OpExtInst %void %1 DebugNoScope +OpFunctionEnd + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + const uint32_t line_number = 7U; + Instruction line(context.get(), SpvOpLine); + line.SetInOperands({ + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {5U}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {0U}}, + }); + + DebugScope scope(29U, 0U); + + auto db_manager = context.get()->get_debug_info_mgr(); + auto du_manager = context.get()->get_def_use_mgr(); + auto c_manager = context.get()->get_constant_mgr(); + + (void)du_manager; + (void)c_manager; + + uint32_t inlined_at_id = db_manager->CreateDebugInlinedAt(&line, scope); + auto* inlined_at = db_manager->GetDebugInlinedAt(inlined_at_id); + EXPECT_NE(inlined_at, nullptr); + EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex), + 100); +} + TEST(DebugInfoManager, GetDebugInfoNone) { const std::string text = R"( OpCapability Shader diff --git a/third_party/spirv-tools/test/opt/desc_sroa_test.cpp b/third_party/spirv-tools/test/opt/desc_sroa_test.cpp index b35ad474da..dcb625d6d4 100644 --- a/third_party/spirv-tools/test/opt/desc_sroa_test.cpp +++ b/third_party/spirv-tools/test/opt/desc_sroa_test.cpp @@ -770,6 +770,69 @@ TEST_F(DescriptorScalarReplacementTest, BindingForResourceArrayOfStructs) { SinglePassRunAndMatch(shader, true); } +TEST_F(DescriptorScalarReplacementTest, MemberDecorationForResourceStruct) { + // Check that an OpMemberDecorate instruction is correctly converted to a + // OpDecorate instruction. + + const std::string shader = R"( +; CHECK: OpDecorate [[t:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[t]] Binding 0 +; CHECK: OpDecorate [[t]] RelaxedPrecision +; CHECK: OpDecorate [[s:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[s]] Binding 1 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" %in_var_TEXCOORD %out_var_SV_Target + OpExecutionMode %PSMain OriginUpperLeft + OpSource HLSL 600 + OpName %sampler2D_h "sampler2D_h" + OpMemberName %sampler2D_h 0 "t" + OpMemberName %sampler2D_h 1 "s" + OpName %type_2d_image "type.2d.image" + OpName %type_sampler "type.sampler" + OpName %_MainTex "_MainTex" + OpName %in_var_TEXCOORD "in.var.TEXCOORD" + OpName %out_var_SV_Target "out.var.SV_Target" + OpName %PSMain "PSMain" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %in_var_TEXCOORD Location 0 + OpDecorate %out_var_SV_Target Location 0 + OpDecorate %_MainTex DescriptorSet 0 + OpDecorate %_MainTex Binding 0 + OpMemberDecorate %sampler2D_h 0 RelaxedPrecision + OpDecorate %out_var_SV_Target RelaxedPrecision + OpDecorate %69 RelaxedPrecision + %float = OpTypeFloat 32 +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%type_sampler = OpTypeSampler +%sampler2D_h = OpTypeStruct %type_2d_image %type_sampler +%_ptr_UniformConstant_sampler2D_h = OpTypePointer UniformConstant %sampler2D_h + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %35 = OpTypeFunction %void +%type_sampled_image = OpTypeSampledImage %type_2d_image + %_MainTex = OpVariable %_ptr_UniformConstant_sampler2D_h UniformConstant +%in_var_TEXCOORD = OpVariable %_ptr_Input_v2float Input +%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output + %PSMain = OpFunction %void None %35 + %43 = OpLabel + %44 = OpLoad %v2float %in_var_TEXCOORD + %57 = OpLoad %sampler2D_h %_MainTex + %72 = OpCompositeExtract %type_2d_image %57 0 + %73 = OpCompositeExtract %type_sampler %57 1 + %68 = OpSampledImage %type_sampled_image %72 %73 + %69 = OpImageSampleImplicitLod %v4float %68 %44 None + OpStore %out_var_SV_Target %69 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(shader, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp b/third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp index 7728782e70..e277999e44 100644 --- a/third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp +++ b/third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp @@ -576,7 +576,6 @@ TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateArrayLength) { %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform %main = OpFunction %void None %9 %10 = OpLabel - %11 = OpLoad %type__Globals %_Globals %12 = OpArrayLength %uint %_Globals 2 OpReturn OpFunctionEnd @@ -627,6 +626,67 @@ TEST_F(EliminateDeadMemberTest, KeepMembersOpStore) { EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); } +TEST_F(EliminateDeadMemberTest, KeepStorageBufferMembers) { + // Test that all members of the storage buffer struct %S are kept. + // No change expected. + const std::string text = R"( + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + OpExtension "SPV_GOOGLE_user_type" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" %out_var_SV_TARGET + OpExecutionMode %PSMain OriginUpperLeft + OpSource HLSL 600 + OpName %type_StructuredBuffer_S "type.StructuredBuffer.S" + OpName %S "S" + OpMemberName %S 0 "A" + OpMemberName %S 1 "B" + OpName %Buf "Buf" + OpName %out_var_SV_TARGET "out.var.SV_TARGET" + OpName %PSMain "PSMain" + OpDecorateString %out_var_SV_TARGET UserSemantic "SV_TARGET" + OpDecorate %out_var_SV_TARGET Location 0 + OpDecorate %Buf DescriptorSet 0 + OpDecorate %Buf Binding 0 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 16 + OpDecorate %_runtimearr_S ArrayStride 32 + OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable + OpDecorate %type_StructuredBuffer_S BufferBlock + OpDecorateString %Buf UserTypeGOOGLE "structuredbuffer" + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %int_1 = OpConstant %int 1 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %S = OpTypeStruct %v4float %v4float +%_runtimearr_S = OpTypeRuntimeArray %S +%type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S +%_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %18 = OpTypeFunction %void +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float + %Buf = OpVariable %_ptr_Uniform_type_StructuredBuffer_S Uniform +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output + %PSMain = OpFunction %void None %18 + %20 = OpLabel + %21 = OpAccessChain %_ptr_Uniform_v4float %Buf %int_0 %uint_0 %int_1 + %22 = OpLoad %v4float %21 + OpStore %out_var_SV_TARGET %22 + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemory) { // Test that all members are kept because of an OpCopyMemory. // No change expected. diff --git a/third_party/spirv-tools/test/opt/fold_test.cpp b/third_party/spirv-tools/test/opt/fold_test.cpp index 8457bbfe63..0487e78cc8 100644 --- a/third_party/spirv-tools/test/opt/fold_test.cpp +++ b/third_party/spirv-tools/test/opt/fold_test.cpp @@ -137,6 +137,7 @@ OpName %main "main" %int = OpTypeInt 32 1 %long = OpTypeInt 64 1 %uint = OpTypeInt 32 0 +%ulong = OpTypeInt 64 0 %v2int = OpTypeVector %int 2 %v4int = OpTypeVector %int 4 %v4float = OpTypeVector %float 4 @@ -154,6 +155,7 @@ OpName %main "main" %_ptr_double = OpTypePointer Function %double %_ptr_half = OpTypePointer Function %half %_ptr_long = OpTypePointer Function %long +%_ptr_ulong = OpTypePointer Function %ulong %_ptr_v2int = OpTypePointer Function %v2int %_ptr_v4int = OpTypePointer Function %v4int %_ptr_v4float = OpTypePointer Function %v4float @@ -171,12 +173,23 @@ OpName %main "main" %int_2 = OpConstant %int 2 %int_3 = OpConstant %int 3 %int_4 = OpConstant %int 4 +%int_10 = OpConstant %int 10 +%int_1073741824 = OpConstant %int 1073741824 +%int_n1 = OpConstant %int -1 %int_n24 = OpConstant %int -24 +%int_n858993459 = OpConstant %int -858993459 %int_min = OpConstant %int -2147483648 %int_max = OpConstant %int 2147483647 %long_0 = OpConstant %long 0 +%long_1 = OpConstant %long 1 %long_2 = OpConstant %long 2 %long_3 = OpConstant %long 3 +%long_10 = OpConstant %long 10 +%long_4611686018427387904 = OpConstant %long 4611686018427387904 +%long_n1 = OpConstant %long -1 +%long_n3689348814741910323 = OpConstant %long -3689348814741910323 +%long_min = OpConstant %long -9223372036854775808 +%long_max = OpConstant %long 9223372036854775807 %uint_0 = OpConstant %uint 0 %uint_1 = OpConstant %uint 1 %uint_2 = OpConstant %uint 2 @@ -184,7 +197,13 @@ OpName %main "main" %uint_4 = OpConstant %uint 4 %uint_32 = OpConstant %uint 32 %uint_42 = OpConstant %uint 42 +%uint_2147483649 = OpConstant %uint 2147483649 %uint_max = OpConstant %uint 4294967295 +%ulong_0 = OpConstant %ulong 0 +%ulong_1 = OpConstant %ulong 1 +%ulong_2 = OpConstant %ulong 2 +%ulong_9223372036854775809 = OpConstant %ulong 9223372036854775809 +%ulong_max = OpConstant %ulong 18446744073709551615 %v2int_undef = OpUndef %v2int %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0 %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0 @@ -3589,7 +3608,19 @@ INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingT "%4 = OpCompositeExtract %int %3 2\n" + "OpReturn\n" + "OpFunctionEnd", - 4, INT_0_ID) + 4, INT_0_ID), + // Test case 15: + // Don't fold extract fed by construct with vector result if the index is + // past the last element. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" + + "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" + + "%4 = OpCompositeExtract %int %3 4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 4, 0) )); INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest, @@ -5572,7 +5603,109 @@ INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest, "%5 = OpFMul %float %4 %2\n" + "OpReturn\n" + "OpFunctionEnd\n", - 5, true) + 5, true), + // Test case 25: fold overflowing signed 32 bit imuls + // (x * 1073741824) * 2 = x * int_min + InstructionFoldingCase( + Header() + + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + + "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + + "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_min]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_int Function\n" + + "%2 = OpLoad %int %var\n" + + "%3 = OpIMul %int %2 %int_1073741824\n" + + "%4 = OpIMul %int %3 %int_2\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 26: fold overflowing signed 64 bit imuls + // (x * 4611686018427387904) * 2 = x * long_min + InstructionFoldingCase( + Header() + + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + + "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + + "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_min]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_long Function\n" + + "%2 = OpLoad %long %var\n" + + "%3 = OpIMul %long %2 %long_4611686018427387904\n" + + "%4 = OpIMul %long %3 %long_2\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 27: fold overflowing 32 bit unsigned imuls + // (x * 2147483649) * 2 = x * 2 + InstructionFoldingCase( + Header() + + "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" + + "; CHECK: [[uint_2:%\\w+]] = OpConstant [[uint]] 2\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" + + "; CHECK: %4 = OpIMul [[uint]] [[ld]] [[uint_2]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_uint Function\n" + + "%2 = OpLoad %uint %var\n" + + "%3 = OpIMul %uint %2 %uint_2147483649\n" + + "%4 = OpIMul %uint %3 %uint_2\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 28: fold overflowing 64 bit unsigned imuls + // (x * 9223372036854775809) * 2 = x * 2 + InstructionFoldingCase( + Header() + + "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" + + "; CHECK: [[ulong_2:%\\w+]] = OpConstant [[ulong]] 2\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" + + "; CHECK: %4 = OpIMul [[ulong]] [[ld]] [[ulong_2]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_ulong Function\n" + + "%2 = OpLoad %ulong %var\n" + + "%3 = OpIMul %ulong %2 %ulong_9223372036854775809\n" + + "%4 = OpIMul %ulong %3 %ulong_2\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 29: fold underflowing signed 32 bit imuls + // (x * (-858993459)) * 10 = x * 2 + InstructionFoldingCase( + Header() + + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + + "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + + "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_2]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_int Function\n" + + "%2 = OpLoad %int %var\n" + + "%3 = OpIMul %int %2 %int_n858993459\n" + + "%4 = OpIMul %int %3 %int_10\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 30: fold underflowing signed 64 bit imuls + // (x * (-3689348814741910323)) * 10 = x * 2 + InstructionFoldingCase( + Header() + + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + + "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + + "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_2]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_long Function\n" + + "%2 = OpLoad %long %var\n" + + "%3 = OpIMul %long %2 %long_n3689348814741910323\n" + + "%4 = OpIMul %long %3 %long_10\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true) )); INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, @@ -5732,15 +5865,11 @@ INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd\n", 4, false), - // Test case 11: merge sdiv of snegate - // (-x) / 2 = x / -2 + // Test case 11: Do not merge sdiv of snegate. If %2 is INT_MIN, then the + // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv. + // Specifically, (-INT_MIN) / 2 != INT_MIN / -2. InstructionFoldingCase( Header() + - "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + - "; CHECK: OpConstant [[int]] -2147483648\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" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + @@ -5749,16 +5878,12 @@ INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, "%4 = OpSDiv %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", - 4, true), - // Test case 12: merge sdiv of snegate - // 2 / (-x) = -2 / x + 4, false), + // Test case 12: Do not merge sdiv of snegate. If %2 is INT_MIN, then the + // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv. + // Specifically, 2 / (-INT_MIN) != -2 / INT_MIN. InstructionFoldingCase( Header() + - "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + - "; CHECK: OpConstant [[int]] -2147483648\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" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + @@ -5767,7 +5892,7 @@ INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, "%4 = OpSDiv %int %int_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", - 4, true), + 4, false), // Test case 13: Don't merge // (x / {null}) / {null} InstructionFoldingCase( @@ -5818,7 +5943,33 @@ INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, "%5 = OpFDiv %float %4 %2\n" + "OpReturn\n" + "OpFunctionEnd\n", - 5, true) + 5, true), + // Test case 16: Do not merge udiv of snegate + // (-x) / 2u + InstructionFoldingCase( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_uint Function\n" + + "%2 = OpLoad %uint %var\n" + + "%3 = OpSNegate %uint %2\n" + + "%4 = OpUDiv %uint %3 %uint_2\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, false), + // Test case 17: Do not merge udiv of snegate + // 2u / (-x) + InstructionFoldingCase( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_uint Function\n" + + "%2 = OpLoad %uint %var\n" + + "%3 = OpSNegate %uint %2\n" + + "%4 = OpUDiv %uint %uint_2 %3\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, false) )); INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest, @@ -6026,6 +6177,108 @@ INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest, "%4 = OpFAdd %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", + 4, true), + // Test case 12: fold overflowing signed 32 bit iadds + // (x + int_max) + 1 = x + int_min + InstructionFoldingCase( + Header() + + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + + "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + + "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_min]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_int Function\n" + + "%2 = OpLoad %int %var\n" + + "%3 = OpIAdd %int %2 %int_max\n" + + "%4 = OpIAdd %int %3 %int_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 13: fold overflowing signed 64 bit iadds + // (x + long_max) + 1 = x + long_min + InstructionFoldingCase( + Header() + + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + + "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + + "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_min]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_long Function\n" + + "%2 = OpLoad %long %var\n" + + "%3 = OpIAdd %long %2 %long_max\n" + + "%4 = OpIAdd %long %3 %long_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 14: fold overflowing 32 bit unsigned iadds + // (x + uint_max) + 2 = x + 1 + InstructionFoldingCase( + Header() + + "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" + + "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" + + "; CHECK: %4 = OpIAdd [[uint]] [[ld]] [[uint_1]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_uint Function\n" + + "%2 = OpLoad %uint %var\n" + + "%3 = OpIAdd %uint %2 %uint_max\n" + + "%4 = OpIAdd %uint %3 %uint_2\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 15: fold overflowing 64 bit unsigned iadds + // (x + ulong_max) + 2 = x + 1 + InstructionFoldingCase( + Header() + + "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" + + "; CHECK: [[ulong_1:%\\w+]] = OpConstant [[ulong]] 1\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" + + "; CHECK: %4 = OpIAdd [[ulong]] [[ld]] [[ulong_1]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_ulong Function\n" + + "%2 = OpLoad %ulong %var\n" + + "%3 = OpIAdd %ulong %2 %ulong_max\n" + + "%4 = OpIAdd %ulong %3 %ulong_2\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 16: fold underflowing signed 32 bit iadds + // (x + int_min) + (-1) = x + int_max + InstructionFoldingCase( + Header() + + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + + "; CHECK: [[int_max:%\\w+]] = OpConstant [[int]] 2147483647\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + + "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_max]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_int Function\n" + + "%2 = OpLoad %int %var\n" + + "%3 = OpIAdd %int %2 %int_min\n" + + "%4 = OpIAdd %int %3 %int_n1\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 17: fold underflowing signed 64 bit iadds + // (x + long_min) + (-1) = x + long_max + InstructionFoldingCase( + Header() + + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + + "; CHECK: [[long_max:%\\w+]] = OpConstant [[long]] 9223372036854775807\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + + "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_max]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_long Function\n" + + "%2 = OpLoad %long %var\n" + + "%3 = OpIAdd %long %2 %long_min\n" + + "%4 = OpIAdd %long %3 %long_n1\n" + + "OpReturn\n" + + "OpFunctionEnd\n", 4, true) )); @@ -6394,6 +6647,40 @@ INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest, "%4 = OpISub %int %int_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", + 4, true), + // Test case 14: fold overflowing signed 32 bit isubs + // (x - int_max) - 1 = x - int_min + InstructionFoldingCase( + Header() + + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + + "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + + "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_min]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_int Function\n" + + "%2 = OpLoad %int %var\n" + + "%3 = OpISub %int %2 %int_max\n" + + "%4 = OpISub %int %3 %int_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 4, true), + // Test case 15: fold overflowing signed 64 bit isubs + // (x - long_max) - 1 = x - long_min + InstructionFoldingCase( + Header() + + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + + "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + + "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_min]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_long Function\n" + + "%2 = OpLoad %long %var\n" + + "%3 = OpISub %long %2 %long_max\n" + + "%4 = OpISub %long %3 %long_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n", 4, true) )); diff --git a/third_party/spirv-tools/test/opt/inline_opaque_test.cpp b/third_party/spirv-tools/test/opt/inline_opaque_test.cpp index 8cb8925cdb..e4db432553 100644 --- a/third_party/spirv-tools/test/opt/inline_opaque_test.cpp +++ b/third_party/spirv-tools/test/opt/inline_opaque_test.cpp @@ -226,6 +226,115 @@ OpFunctionEnd predefs + before + post_defs, predefs + after + post_defs, true, true); } +TEST_F(InlineOpaqueTest, InlineOpaqueForLinkage) { + const std::string predefs_1 = + R"(OpCapability Shader +OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %S_t "S_t" +OpMemberName %S_t 0 "v0" +OpMemberName %S_t 1 "v1" +OpMemberName %S_t 2 "smp" +OpName %foo_struct_S_t_vf2_vf21_ "foo(struct-S_t-vf2-vf21;" +OpName %s "s" +OpName %outColor "outColor" +OpName %sampler15 "sampler15" +OpName %s0 "s0" +OpName %texCoords "texCoords" +OpName %param "param" +OpDecorate %main LinkageAttributes "main" Export +)"; + + const std::string name = R"(OpName %return_value "return_value" +)"; + + const std::string predefs_2 = R"(OpDecorate %sampler15 DescriptorSet 0 +%void = OpTypeVoid +%13 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%outColor = OpVariable %_ptr_Output_v4float Output +%18 = OpTypeImage %float 2D 0 0 0 1 Unknown +%19 = OpTypeSampledImage %18 +%S_t = OpTypeStruct %v2float %v2float %19 +%_ptr_Function_S_t = OpTypePointer Function %S_t +%21 = OpTypeFunction %void %_ptr_Function_S_t +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 +%_ptr_Function_19 = OpTypePointer Function %19 +%sampler15 = OpVariable %_ptr_UniformConstant_19 UniformConstant +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_2 = OpConstant %int 2 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Input_v2float = OpTypePointer Input %v2float +%texCoords = OpVariable %_ptr_Input_v2float Input +)"; + + const std::string before = + R"(%main = OpFunction %void None %13 +%29 = OpLabel +%s0 = OpVariable %_ptr_Function_S_t Function +%param = OpVariable %_ptr_Function_S_t Function +%30 = OpLoad %v2float %texCoords +%31 = OpAccessChain %_ptr_Function_v2float %s0 %int_0 +OpStore %31 %30 +%32 = OpLoad %19 %sampler15 +%33 = OpAccessChain %_ptr_Function_19 %s0 %int_2 +OpStore %33 %32 +%34 = OpLoad %S_t %s0 +OpStore %param %34 +%return_value = OpFunctionCall %void %foo_struct_S_t_vf2_vf21_ %param +OpReturn +OpFunctionEnd +)"; + + const std::string after = + R"(%main = OpFunction %void None %13 +%29 = OpLabel +%s0 = OpVariable %_ptr_Function_S_t Function +%param = OpVariable %_ptr_Function_S_t Function +%30 = OpLoad %v2float %texCoords +%31 = OpAccessChain %_ptr_Function_v2float %s0 %int_0 +OpStore %31 %30 +%32 = OpLoad %19 %sampler15 +%33 = OpAccessChain %_ptr_Function_19 %s0 %int_2 +OpStore %33 %32 +%34 = OpLoad %S_t %s0 +OpStore %param %34 +%42 = OpAccessChain %_ptr_Function_19 %param %int_2 +%43 = OpLoad %19 %42 +%44 = OpAccessChain %_ptr_Function_v2float %param %int_0 +%45 = OpLoad %v2float %44 +%46 = OpImageSampleImplicitLod %v4float %43 %45 +OpStore %outColor %46 +OpReturn +OpFunctionEnd +)"; + + const std::string post_defs = + R"(%foo_struct_S_t_vf2_vf21_ = OpFunction %void None %21 +%s = OpFunctionParameter %_ptr_Function_S_t +%35 = OpLabel +%36 = OpAccessChain %_ptr_Function_19 %s %int_2 +%37 = OpLoad %19 %36 +%38 = OpAccessChain %_ptr_Function_v2float %s %int_0 +%39 = OpLoad %v2float %38 +%40 = OpImageSampleImplicitLod %v4float %37 %39 +OpStore %outColor %40 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck( + predefs_1 + name + predefs_2 + before + post_defs, + predefs_1 + predefs_2 + after + post_defs, true, true); +} + TEST_F(InlineOpaqueTest, InlineInNonEntryPointFunction) { // This demonstrates opaque inlining in a function that is not // an entry point function (main2) but is in the call tree of an diff --git a/third_party/spirv-tools/test/opt/inline_test.cpp b/third_party/spirv-tools/test/opt/inline_test.cpp index 2939901338..d22f027c56 100644 --- a/third_party/spirv-tools/test/opt/inline_test.cpp +++ b/third_party/spirv-tools/test/opt/inline_test.cpp @@ -2300,7 +2300,6 @@ TEST_F(InlineTest, DontInlineDirectlyRecursiveFunc) { OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "main" OpExecutionMode %1 OriginUpperLeft -OpDecorate %2 DescriptorSet 439418829 %void = OpTypeVoid %4 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2330,7 +2329,6 @@ TEST_F(InlineTest, DontInlineInDirectlyRecursiveFunc) { OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "main" OpExecutionMode %1 OriginUpperLeft -OpDecorate %2 DescriptorSet 439418829 %void = OpTypeVoid %4 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2581,6 +2579,132 @@ OpFunctionEnd SinglePassRunAndCheck(before, after, false, true); } +TEST_F(InlineTest, InlineForLinkage) { + const std::string before = + R"(OpCapability SampledBuffer +OpCapability ImageBuffer +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %type_buffer_image "type.buffer.image" +OpName %output "output" +OpName %main "main" +OpName %color "color" +OpName %bb_entry "bb.entry" +OpName %param_var_color "param.var.color" +OpName %fn "fn" +OpName %color_0 "color" +OpName %bb_entry_0 "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +OpDecorate %output DescriptorSet 0 +OpDecorate %output Binding 1 +%float = OpTypeFloat 32 +%float_0_200000003 = OpConstant %float 0.200000003 +%v4float = OpTypeVector %float 4 +%6 = OpConstantComposite %v4float %float_0_200000003 %float_0_200000003 %float_0_200000003 %float_0_200000003 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%type_buffer_image = OpTypeImage %float Buffer 2 0 0 2 Rgba32f +%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image +%_ptr_Function_v4float = OpTypePointer Function %v4float +%11 = OpTypeFunction %float %_ptr_Function_v4float +%_ptr_Function_float = OpTypePointer Function %float +%output = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant +%main = OpFunction %float None %11 +%color = OpFunctionParameter %_ptr_Function_v4float +%bb_entry = OpLabel +%param_var_color = OpVariable %_ptr_Function_v4float Function +%16 = OpLoad %v4float %color +OpStore %param_var_color %16 +%17 = OpFunctionCall %float %fn %param_var_color +OpReturnValue %17 +OpFunctionEnd +%fn = OpFunction %float None %11 +%color_0 = OpFunctionParameter %_ptr_Function_v4float +%bb_entry_0 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%22 = OpLoad %v4float %color_0 +OpStore %v %22 +%23 = OpLoad %v4float %v +%24 = OpFMul %v4float %23 %6 +OpStore %v %24 +%26 = OpAccessChain %_ptr_Function_float %v %int_0 +%27 = OpLoad %float %26 +OpReturnValue %27 +OpFunctionEnd + )"; + + const std::string after = + R"(OpCapability SampledBuffer +OpCapability ImageBuffer +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %type_buffer_image "type.buffer.image" +OpName %output "output" +OpName %main "main" +OpName %color "color" +OpName %bb_entry "bb.entry" +OpName %param_var_color "param.var.color" +OpName %fn "fn" +OpName %color_0 "color" +OpName %bb_entry_0 "bb.entry" +OpName %v "v" +OpDecorate %main LinkageAttributes "main" Export +OpDecorate %output DescriptorSet 0 +OpDecorate %output Binding 1 +%float = OpTypeFloat 32 +%float_0_200000003 = OpConstant %float 0.200000003 +%v4float = OpTypeVector %float 4 +%6 = OpConstantComposite %v4float %float_0_200000003 %float_0_200000003 %float_0_200000003 %float_0_200000003 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%type_buffer_image = OpTypeImage %float Buffer 2 0 0 2 Rgba32f +%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image +%_ptr_Function_v4float = OpTypePointer Function %v4float +%11 = OpTypeFunction %float %_ptr_Function_v4float +%_ptr_Function_float = OpTypePointer Function %float +%output = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant +%main = OpFunction %float None %11 +%color = OpFunctionParameter %_ptr_Function_v4float +%bb_entry = OpLabel +%28 = OpVariable %_ptr_Function_v4float Function +%29 = OpVariable %_ptr_Function_float Function +%param_var_color = OpVariable %_ptr_Function_v4float Function +%16 = OpLoad %v4float %color +OpStore %param_var_color %16 +%31 = OpLoad %v4float %param_var_color +OpStore %28 %31 +%32 = OpLoad %v4float %28 +%33 = OpFMul %v4float %32 %6 +OpStore %28 %33 +%34 = OpAccessChain %_ptr_Function_float %28 %int_0 +%35 = OpLoad %float %34 +OpStore %29 %35 +%17 = OpLoad %float %29 +OpReturnValue %17 +OpFunctionEnd +%fn = OpFunction %float None %11 +%color_0 = OpFunctionParameter %_ptr_Function_v4float +%bb_entry_0 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%22 = OpLoad %v4float %color_0 +OpStore %v %22 +%23 = OpLoad %v4float %v +%24 = OpFMul %v4float %23 %6 +OpStore %v %24 +%26 = OpAccessChain %_ptr_Function_float %v %int_0 +%27 = OpLoad %float %26 +OpReturnValue %27 +OpFunctionEnd +)"; + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(before, after, false, true); +} + TEST_F(InlineTest, InlineFuncWithOpTerminateRayNotInContinue) { const std::string text = R"( @@ -3259,6 +3383,82 @@ TEST_F(InlineTest, DebugSimple) { SinglePassRunAndMatch(text, true); } +TEST_F(InlineTest, ShaderDebugSimple) { + // Same as DebugSimple but for NonSemantic.Shader.DebugInfo.100. + const std::string text = R"( +; CHECK: [[main_name:%\d+]] = OpString "main" +; CHECK: [[foo_name:%\d+]] = OpString "foo" +; CHECK: [[dbg_main:%\d+]] = OpExtInst %void {{%\d+}} DebugFunction [[main_name]] {{%\d+}} {{%\d+}} %uint_4 %uint_1 {{%\d+}} [[main_name]] %uint_3 %uint_4 +; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void {{%\d+}} DebugFunction [[foo_name]] {{%\d+}} {{%\d+}} %uint_1 %uint_1 {{%\d+}} [[foo_name]] %uint_3 %uint_1 +; CHECK: [[foo_bb:%\d+]] = OpExtInst %void {{%\d+}} DebugLexicalBlock {{%\d+}} %uint_1 %uint_14 [[dbg_foo]] +; CHECK: [[inlined_at:%\d+]] = OpExtInst %void {{%\d+}} DebugInlinedAt %uint_4 [[dbg_main]] +; CHECK: [[main:%\d+]] = OpFunction %void None +; CHECK: {{%\d+}} = OpExtInst %void {{%\d+}} DebugScope [[foo_bb]] [[inlined_at]] +; CHECK: [[foo:%\d+]] = OpFunction %v4float None + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %3 %4 + OpExecutionMode %main OriginUpperLeft + %5 = OpString "ps.hlsl" + OpSource HLSL 600 %5 + %6 = OpString "float" + %main_name = OpString "main" + %foo_name = OpString "foo" + OpDecorate %3 Location 0 + OpDecorate %4 Location 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 + %uint_5 = OpConstant %uint 5 + %uint_14 = OpConstant %uint 14 + %uint_32 = OpConstant %uint 32 + %float = OpTypeFloat 32 + %float_1 = OpConstant %float 1 + %v4float = OpTypeVector %float 4 + %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %18 = OpTypeFunction %void + %19 = OpTypeFunction %v4float + %3 = OpVariable %_ptr_Input_v4float Input + %4 = OpVariable %_ptr_Output_v4float Output + %20 = OpExtInst %void %1 DebugSource %5 + %21 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %20 %uint_5 + %22 = OpExtInst %void %1 DebugTypeBasic %6 %uint_32 %uint_3 %uint_0 + %23 = OpExtInst %void %1 DebugTypeVector %22 %uint_4 + %24 = OpExtInst %void %1 DebugTypeFunction %uint_3 %23 %23 + %25 = OpExtInst %void %1 DebugTypeFunction %uint_3 %23 + %dbg_main = OpExtInst %void %1 DebugFunction %main_name %24 %20 %uint_4 %uint_1 %21 %main_name %uint_3 %uint_4 + %dbg_foo = OpExtInst %void %1 DebugFunction %foo_name %25 %20 %uint_1 %uint_1 %21 %foo_name %uint_3 %uint_1 + %29 = OpExtInst %void %1 DebugLexicalBlock %20 %uint_1 %uint_14 %dbg_foo + %main = OpFunction %void None %18 + %30 = OpLabel +%dbg_main_def = OpExtInst %void %1 DebugFunctionDefinition %dbg_main %main + %31 = OpExtInst %void %1 DebugScope %dbg_main + %32 = OpFunctionCall %v4float %foo + %33 = OpLoad %v4float %3 + %34 = OpFAdd %v4float %32 %33 + OpStore %4 %34 + OpReturn + OpFunctionEnd + %foo = OpFunction %v4float None %19 + %36 = OpLabel +%dbg_foo_def = OpExtInst %void %1 DebugFunctionDefinition %dbg_foo %foo + %35 = OpExtInst %void %1 DebugScope %dbg_foo + %37 = OpExtInst %void %1 DebugScope %29 + OpReturnValue %14 + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + TEST_F(InlineTest, DebugNested) { // When function main() calls function zoo() and function zoo() calls // function bar() and function bar() calls function foo(), check that @@ -3462,6 +3662,103 @@ float4 main(float4 color : COLOR) : SV_TARGET { SinglePassRunAndMatch(text, true); } +TEST_F(InlineTest, ShaderDebugSimpleHLSLPixelShader) { + // Same as DebugSimpleHLSLPixelShader but for + // NonSemantic.Shader.DebugInfo.100. + const std::string text = R"( +; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} %uint_1 %uint_1 {{%\d+}} {{%\d+}} %uint_3 %uint_1 +; CHECK: [[lex_blk:%\d+]] = OpExtInst %void [[ext]] DebugLexicalBlock {{%\d+}} %uint_1 %uint_47 [[dbg_main]] +; CHECK: %main = OpFunction %void None +; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]] +; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare {{%\d+}} %param_var_color +; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[lex_blk]] +; CHECK: {{%\d+}} = OpExtInst %void %1 DebugLine {{%\d+}} %uint_2 %uint_2 %uint_10 %uint_10 +; CHECK: {{%\d+}} = OpLoad %v4float %param_var_color +; CHECK: {{%\d+}} = OpExtInst %void %1 DebugLine {{%\d+}} %uint_2 %uint_2 %uint_3 %uint_3 +; CHECK: OpFunctionEnd +; CHECK: %src_main = OpFunction %v4float None + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET + OpExecutionMode %main OriginUpperLeft + %5 = OpString "ps.hlsl" + OpSource HLSL 600 %5 + %14 = OpString "#line 1 \"ps.hlsl\" +float4 main(float4 color : COLOR) : SV_TARGET { + return color; +} +" + %17 = OpString "float" + %21 = OpString "src.main" + %24 = OpString "color" + OpName %in_var_COLOR "in.var.COLOR" + OpName %out_var_SV_TARGET "out.var.SV_TARGET" + OpName %main "main" + OpName %param_var_color "param.var.color" + OpName %src_main "src.main" + OpName %color "color" + OpName %bb_entry "bb.entry" + OpDecorate %in_var_COLOR Location 0 + OpDecorate %out_var_SV_TARGET Location 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 + %uint_5 = OpConstant %uint 5 + %uint_10 = OpConstant %uint 10 + %uint_20 = OpConstant %uint 20 + %uint_32 = OpConstant %uint 32 + %uint_47 = OpConstant %uint 47 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %27 = OpTypeFunction %void +%_ptr_Function_v4float = OpTypePointer Function %v4float + %33 = OpTypeFunction %v4float %_ptr_Function_v4float +%in_var_COLOR = OpVariable %_ptr_Input_v4float Input +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output + %13 = OpExtInst %void %1 DebugExpression + %15 = OpExtInst %void %1 DebugSource %5 %14 + %16 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %15 %uint_5 + %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 %uint_3 %uint_0 + %19 = OpExtInst %void %1 DebugTypeVector %18 %uint_4 + %20 = OpExtInst %void %1 DebugTypeFunction %uint_3 %19 %19 + %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 %uint_1 %uint_1 %16 %21 %uint_3 %uint_1 + %25 = OpExtInst %void %1 DebugLocalVariable %24 %19 %15 %uint_1 %uint_20 %22 %uint_4 %uint_0 + %26 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_1 %uint_47 %22 + %main = OpFunction %void None %27 + %28 = OpLabel +%param_var_color = OpVariable %_ptr_Function_v4float Function + %31 = OpLoad %v4float %in_var_COLOR + OpStore %param_var_color %31 + %32 = OpFunctionCall %v4float %src_main %param_var_color + OpStore %out_var_SV_TARGET %32 + OpReturn + OpFunctionEnd + %src_main = OpFunction %v4float None %33 + %color = OpFunctionParameter %_ptr_Function_v4float + %bb_entry = OpLabel + %140 = OpExtInst %void %1 DebugFunctionDefinition %22 %src_main + %141 = OpExtInst %void %1 DebugLine %5 %uint_1 %uint_1 %uint_1 %uint_1 + %34 = OpExtInst %void %1 DebugScope %22 + %36 = OpExtInst %void %1 DebugDeclare %25 %color %13 + %38 = OpExtInst %void %1 DebugScope %26 + %142 = OpExtInst %void %1 DebugLine %5 %uint_2 %uint_2 %uint_10 %uint_10 + %39 = OpLoad %v4float %color + %143 = OpExtInst %void %1 DebugLine %5 %uint_2 %uint_2 %uint_3 %uint_3 + OpReturnValue %39 + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + TEST_F(InlineTest, DebugDeclareForCalleeFunctionParam) { // Check that InlinePass correctly generates DebugDeclare instructions // for callee function's parameters and maps them to corresponding @@ -3937,6 +4234,105 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(InlineTest, CreateConstantForInlinedAt) { + // This shader causes CreateDebugInlinedAt to generate a constant. + // Using the Constant manager would attempt to build the invalidated + // DefUse manager during inlining which could cause an assert because + // the function is in an inconsistant state. This test verifies that + // CreateDebugInlinedAt detects that the DefUse manager is disabled + // and creates a duplicate constant safely without the Constant manager. + // + // int function1() { + // return 1; + // } + // + // void main() { + // function1(); + // } + + const std::string text = R"(OpCapability Shader +; CHECK: %uint_7 = OpConstant %uint 7 +; CHECK: %uint_7_0 = OpConstant %uint 7 +; CHECK: OpExtInst %void %1 DebugInlinedAt %uint_7_0 +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%3 = OpString "parent3.hlsl" +%8 = OpString "int" +%19 = OpString "function1" +%20 = OpString "" +%26 = OpString "main" +OpName %main "main" +OpName %src_main "src.main" +OpName %bb_entry "bb.entry" +OpName %function1 "function1" +OpName %bb_entry_0 "bb.entry" +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%uint = OpTypeInt 32 0 +%uint_32 = OpConstant %uint 32 +%void = OpTypeVoid +%uint_4 = OpConstant %uint 4 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%uint_1 = OpConstant %uint 1 +%uint_5 = OpConstant %uint 5 +%uint_2 = OpConstant %uint 2 +%uint_17 = OpConstant %uint 17 +%uint_6 = OpConstant %uint 6 +%uint_13 = OpConstant %uint 13 +%uint_7 = OpConstant %uint 7 +%31 = OpTypeFunction %void +%42 = OpTypeFunction %int +%10 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_4 %uint_0 +%13 = OpExtInst %void %1 DebugTypeFunction %uint_3 %10 +%15 = OpExtInst %void %1 DebugSource %3 +%16 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %15 %uint_5 +%21 = OpExtInst %void %1 DebugFunction %19 %13 %15 %uint_2 %uint_1 %16 %20 %uint_3 %uint_2 +%23 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_2 %uint_17 %21 +%25 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void +%27 = OpExtInst %void %1 DebugFunction %26 %25 %15 %uint_6 %uint_1 %16 %20 %uint_3 %uint_6 +%29 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_6 %uint_13 %27 +%main = OpFunction %void None %31 +%32 = OpLabel +%33 = OpFunctionCall %void %src_main +OpLine %3 8 1 +OpReturn +OpFunctionEnd +OpLine %3 6 1 +%src_main = OpFunction %void None %31 +OpNoLine +%bb_entry = OpLabel +%47 = OpExtInst %void %1 DebugScope %27 +%37 = OpExtInst %void %1 DebugFunctionDefinition %27 %src_main +%48 = OpExtInst %void %1 DebugScope %29 +OpLine %3 7 3 +%39 = OpFunctionCall %int %function1 +%49 = OpExtInst %void %1 DebugScope %27 +OpLine %3 8 1 +OpReturn +%50 = OpExtInst %void %1 DebugNoScope +OpFunctionEnd +OpLine %3 2 1 +%function1 = OpFunction %int None %42 +OpNoLine +%bb_entry_0 = OpLabel +%51 = OpExtInst %void %1 DebugScope %21 +%45 = OpExtInst %void %1 DebugFunctionDefinition %21 %function1 +%52 = OpExtInst %void %1 DebugScope %23 +OpLine %3 3 3 +OpReturnValue %int_1 +%53 = OpExtInst %void %1 DebugNoScope +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Empty modules diff --git a/third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp b/third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp index 41ead67a5a..95114b2397 100644 --- a/third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp +++ b/third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp @@ -615,6 +615,212 @@ OpFunctionEnd true, 7u, 23u); } +TEST_F(InstBuffAddrTest, StructLoad) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // #extension GL_ARB_gpu_shader_int64 : enable + // struct Test { + // float a; + // }; + // + // layout(buffer_reference, std430, buffer_reference_align = 16) buffer + // TestBuffer { Test test; }; + // + // Test GetTest(uint64_t ptr) { + // return TestBuffer(ptr).test; + // } + // + // void main() { + // GetTest(0xe0000000); + // } + + const std::string defs = + R"( +OpCapability Shader +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Fragment %main "main" +; CHECK: OpEntryPoint Fragment %main "main" %60 %99 %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_ARB_gpu_shader_int64" +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %Test "Test" +OpMemberName %Test 0 "a" +OpName %Test_0 "Test" +OpMemberName %Test_0 0 "a" +OpName %TestBuffer "TestBuffer" +OpMemberName %TestBuffer 0 "test" +)"; + + const std::string decorates = + R"( +OpMemberDecorate %Test_0 0 Offset 0 +OpMemberDecorate %TestBuffer 0 Offset 0 +OpDecorate %TestBuffer Block +; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 +; CHECK: OpDecorate %_struct_58 Block +; CHECK: OpMemberDecorate %_struct_58 0 Offset 0 +; CHECK: OpDecorate %60 DescriptorSet 7 +; CHECK: OpDecorate %60 Binding 2 +; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +; CHECK: OpDecorate %_struct_97 Block +; CHECK: OpMemberDecorate %_struct_97 0 Offset 0 +; CHECK: OpMemberDecorate %_struct_97 1 Offset 4 +; CHECK: OpDecorate %99 DescriptorSet 7 +; CHECK: OpDecorate %99 Binding 0 +; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)"; + + const std::string globals = + R"( +%void = OpTypeVoid +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%float = OpTypeFloat 32 +%Test = OpTypeStruct %float +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer +%Test_0 = OpTypeStruct %float +%TestBuffer = OpTypeStruct %Test_0 +%_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 +%ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 +; CHECK: %47 = OpTypeFunction %bool %ulong %uint +; CHECK: %_struct_58 = OpTypeStruct %_runtimearr_ulong +; CHECK: %60 = OpVariable %_ptr_StorageBuffer__struct_58 StorageBuffer +; CHECK: %90 = OpTypeFunction %void %uint %uint %uint %uint +; CHECK: %_struct_97 = OpTypeStruct %uint %_runtimearr_uint +; CHECK: %99 = OpVariable %_ptr_StorageBuffer__struct_97 StorageBuffer +; CHECK: %143 = OpConstantNull %Test_0 +)"; + + const std::string main = + R"( +%main = OpFunction %void None %3 +%5 = OpLabel +%37 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %ulong_18446744073172680704 +%38 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %37 %int_0 +%39 = OpLoad %Test_0 %38 Aligned 16 +; CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16 +; CHECK: %43 = OpConvertPtrToU %ulong %38 +; CHECK: %80 = OpFunctionCall %bool %45 %43 %uint_4 +; CHECK: OpSelectionMerge %81 None +; CHECK: OpBranchConditional %80 %82 %83 +; CHECK: %82 = OpLabel +; CHECK: %84 = OpLoad %Test_0 %38 Aligned 16 +; CHECK: OpBranch %81 +; CHECK: %83 = OpLabel +; CHECK: %85 = OpUConvert %uint %43 +; CHECK: %87 = OpShiftRightLogical %ulong %43 %uint_32 +; CHECK: %88 = OpUConvert %uint %87 +; CHECK: %142 = OpFunctionCall %void %89 %uint_37 %uint_2 %85 %88 +; CHECK: OpBranch %81 +; CHECK: %81 = OpLabel +; CHECK: %144 = OpPhi %Test_0 %84 %82 %143 %83 +%40 = OpCopyLogical %Test %39 +; CHECK-NOT: %40 = OpCopyLogical %Test %39 +; CHECK: %40 = OpCopyLogical %Test %144 +OpReturn +OpFunctionEnd +)"; + + const std::string output_funcs = + R"( +; CHECK: %45 = OpFunction %bool None %47 +; CHECK: %48 = OpFunctionParameter %ulong +; CHECK: %49 = OpFunctionParameter %uint +; CHECK: %50 = OpLabel +; CHECK: OpBranch %51 +; CHECK: %51 = OpLabel +; CHECK: %53 = OpPhi %uint %uint_1 %50 %54 %52 +; CHECK: OpLoopMerge %56 %52 None +; CHECK: OpBranch %52 +; CHECK: %52 = OpLabel +; CHECK: %54 = OpIAdd %uint %53 %uint_1 +; CHECK: %63 = OpAccessChain %_ptr_StorageBuffer_ulong %60 %uint_0 %54 +; CHECK: %64 = OpLoad %ulong %63 +; CHECK: %65 = OpUGreaterThan %bool %64 %48 +; CHECK: OpBranchConditional %65 %56 %51 +; CHECK: %56 = OpLabel +; CHECK: %66 = OpISub %uint %54 %uint_1 +; CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_ulong %60 %uint_0 %66 +; CHECK: %68 = OpLoad %ulong %67 +; CHECK: %69 = OpISub %ulong %48 %68 +; CHECK: %70 = OpUConvert %ulong %49 +; CHECK: %71 = OpIAdd %ulong %69 %70 +; CHECK: %72 = OpAccessChain %_ptr_StorageBuffer_ulong %60 %uint_0 %uint_0 +; CHECK: %73 = OpLoad %ulong %72 +; CHECK: %74 = OpUConvert %uint %73 +; CHECK: %75 = OpISub %uint %66 %uint_1 +; CHECK: %76 = OpIAdd %uint %75 %74 +; CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_ulong %60 %uint_0 %76 +; CHECK: %78 = OpLoad %ulong %77 +; CHECK: %79 = OpULessThanEqual %bool %71 %78 +; CHECK: OpReturnValue %79 +; CHECK: OpFunctionEnd +; CHECK: %89 = OpFunction %void None %90 +; CHECK: %91 = OpFunctionParameter %uint +; CHECK: %92 = OpFunctionParameter %uint +; CHECK: %93 = OpFunctionParameter %uint +; CHECK: %94 = OpFunctionParameter %uint +; CHECK: %95 = OpLabel +; CHECK: %101 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_0 +; CHECK: %103 = OpAtomicIAdd %uint %101 %uint_4 %uint_0 %uint_10 +; CHECK: %104 = OpIAdd %uint %103 %uint_10 +; CHECK: %105 = OpArrayLength %uint %99 1 +; CHECK: %106 = OpULessThanEqual %bool %104 %105 +; CHECK: OpSelectionMerge %107 None +; CHECK: OpBranchConditional %106 %108 %107 +; CHECK: %108 = OpLabel +; CHECK: %109 = OpIAdd %uint %103 %uint_0 +; CHECK: %110 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %109 +; CHECK: OpStore %110 %uint_10 +; CHECK: %112 = OpIAdd %uint %103 %uint_1 +; CHECK: %113 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %112 +; CHECK: OpStore %113 %uint_23 +; CHECK: %114 = OpIAdd %uint %103 %uint_2 +; CHECK: %115 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %114 +; CHECK: OpStore %115 %91 +; CHECK: %117 = OpIAdd %uint %103 %uint_3 +; CHECK: %118 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %117 +; CHECK: OpStore %118 %uint_4 +; CHECK: %122 = OpLoad %v4float %gl_FragCoord +; CHECK: %124 = OpBitcast %v4uint %122 +; CHECK: %125 = OpCompositeExtract %uint %124 0 +; CHECK: %126 = OpIAdd %uint %103 %uint_4 +; CHECK: %127 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %126 +; CHECK: OpStore %127 %125 +; CHECK: %128 = OpCompositeExtract %uint %124 1 +; CHECK: %130 = OpIAdd %uint %103 %uint_5 +; CHECK: %131 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %130 +; CHECK: OpStore %131 %128 +; CHECK: %133 = OpIAdd %uint %103 %uint_7 +; CHECK: %134 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %133 +; CHECK: OpStore %134 %92 +; CHECK: %136 = OpIAdd %uint %103 %uint_8 +; CHECK: %137 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %136 +; CHECK: OpStore %137 %93 +; CHECK: %139 = OpIAdd %uint %103 %uint_9 +; CHECK: %140 = OpAccessChain %_ptr_StorageBuffer_uint %99 %uint_1 %139 +; CHECK: OpStore %140 %94 +; CHECK: OpBranch %107 +; CHECK: %107 = OpLabel +; CHECK: OpReturn +; CHECK: OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch( + defs + decorates + globals + main + output_funcs, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/ir_loader_test.cpp b/third_party/spirv-tools/test/opt/ir_loader_test.cpp index 475dd2351e..ccdd032ee1 100644 --- a/third_party/spirv-tools/test/opt/ir_loader_test.cpp +++ b/third_party/spirv-tools/test/opt/ir_loader_test.cpp @@ -105,6 +105,22 @@ TEST(IrBuilder, RoundTripIncompleteFunction) { DoRoundTripCheck("%2 = OpFunction %1 None %3\n"); } +TEST(IrBuilder, RoundTripFunctionPointer) { + DoRoundTripCheck( + "OpCapability Linkage\n" + "OpCapability FunctionPointersINTEL\n" + "OpName %some_function \"some_function\"\n" + "OpName %ptr_to_function \"ptr_to_function\"\n" + "OpDecorate %some_function LinkageAttributes \"some_function\" Import\n" + "%float = OpTypeFloat 32\n" + "%4 = OpTypeFunction %float %float\n" + "%_ptr_Function_4 = OpTypePointer Function %4\n" + "%ptr_to_function = OpConstantFunctionPointerINTEL %_ptr_Function_4 " + "%some_function\n" + "%some_function = OpFunction %float Const %4\n" + "%6 = OpFunctionParameter %float\n" + "OpFunctionEnd\n"); +} TEST(IrBuilder, KeepLineDebugInfo) { // #version 310 es // void main() {} diff --git a/third_party/spirv-tools/test/opt/local_single_block_elim.cpp b/third_party/spirv-tools/test/opt/local_single_block_elim.cpp index 8e1cee6157..28b8a07d1f 100644 --- a/third_party/spirv-tools/test/opt/local_single_block_elim.cpp +++ b/third_party/spirv-tools/test/opt/local_single_block_elim.cpp @@ -84,6 +84,56 @@ OpFunctionEnd predefs_before + before, predefs_before + after, true, true); } +TEST_F(LocalSingleBlockLoadStoreElimTest, LSBElimForLinkage) { + const std::string predefs_before = + R"(OpCapability Shader +OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %v "v" +OpName %BaseColor "BaseColor" +OpName %gl_FragColor "gl_FragColor" +OpDecorate %main LinkageAttributes "main" Export +%void = OpTypeVoid +%7 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v4float = OpTypePointer Input %v4float +%BaseColor = OpVariable %_ptr_Input_v4float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%gl_FragColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string before = + R"(%main = OpFunction %void None %7 +%13 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%14 = OpLoad %v4float %BaseColor +OpStore %v %14 +%15 = OpLoad %v4float %v +OpStore %gl_FragColor %15 +OpReturn +OpFunctionEnd +)"; + + const std::string after = + R"(%main = OpFunction %void None %7 +%13 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%14 = OpLoad %v4float %BaseColor +OpStore %v %14 +OpStore %gl_FragColor %14 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck( + predefs_before + before, predefs_before + after, true, true); +} + TEST_F(LocalSingleBlockLoadStoreElimTest, SimpleLoadLoadElim) { // #version 140 // diff --git a/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp b/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp index c94ff372b3..5d910c4e79 100644 --- a/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp @@ -126,6 +126,91 @@ OpFunctionEnd predefs + after, true, true); } +TEST_F(LocalSingleStoreElimTest, LSSElimForLinkage) { + const std::string predefs = + R"(OpCapability Shader +OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %v "v" +OpName %BaseColor "BaseColor" +OpName %f "f" +OpName %fi "fi" +OpName %gl_FragColor "gl_FragColor" +OpDecorate %main LinkageAttributes "main" Export +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v4float = OpTypePointer Input %v4float +%BaseColor = OpVariable %_ptr_Input_v4float Input +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Input_float = OpTypePointer Input %float +%fi = OpVariable %_ptr_Input_float Input +%float_0 = OpConstant %float 0 +%bool = OpTypeBool +%_ptr_Output_v4float = OpTypePointer Output %v4float +%gl_FragColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string before = + R"(%main = OpFunction %void None %9 +%19 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%f = OpVariable %_ptr_Function_float Function +%20 = OpLoad %v4float %BaseColor +OpStore %v %20 +%21 = OpLoad %float %fi +OpStore %f %21 +%22 = OpLoad %float %f +%23 = OpFOrdLessThan %bool %22 %float_0 +OpSelectionMerge %24 None +OpBranchConditional %23 %25 %24 +%25 = OpLabel +OpStore %f %float_0 +OpBranch %24 +%24 = OpLabel +%26 = OpLoad %v4float %v +%27 = OpLoad %float %f +%28 = OpCompositeConstruct %v4float %27 %27 %27 %27 +%29 = OpFAdd %v4float %26 %28 +OpStore %gl_FragColor %29 +OpReturn +OpFunctionEnd +)"; + + const std::string after = + R"(%main = OpFunction %void None %9 +%19 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%f = OpVariable %_ptr_Function_float Function +%20 = OpLoad %v4float %BaseColor +OpStore %v %20 +%21 = OpLoad %float %fi +OpStore %f %21 +%22 = OpLoad %float %f +%23 = OpFOrdLessThan %bool %22 %float_0 +OpSelectionMerge %24 None +OpBranchConditional %23 %25 %24 +%25 = OpLabel +OpStore %f %float_0 +OpBranch %24 +%24 = OpLabel +%27 = OpLoad %float %f +%28 = OpCompositeConstruct %v4float %27 %27 %27 %27 +%29 = OpFAdd %v4float %20 %28 +OpStore %gl_FragColor %29 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(predefs + before, + predefs + after, true, true); +} + TEST_F(LocalSingleStoreElimTest, ThreeStores) { // Three stores to multiple loads of v is not optimized. diff --git a/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp b/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp index ca9aba334c..4b7542fede 100644 --- a/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp @@ -2165,6 +2165,140 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(LocalSSAElimTest, ShaderDebugForLoop) { + const std::string text = R"( +; CHECK: [[f_name:%\w+]] = OpString "f" +; CHECK: [[i_name:%\w+]] = OpString "i" +; CHECK: [[dbg_f:%\w+]] = OpExtInst %void [[ext:%\d+]] DebugLocalVariable [[f_name]] +; CHECK: [[dbg_i:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[i_name]] + +; CHECK: OpStore %f %float_0 +; CHECK-NEXT: OpExtInst %void [[ext]] DebugValue [[dbg_f]] %float_0 +; CHECK-NEXT: OpStore %i %int_0 +; CHECK-NEXT: OpExtInst %void [[ext]] DebugValue [[dbg_i]] %int_0 + +; CHECK-NOT: DebugDeclare + +; CHECK: [[loop_head:%\w+]] = OpLabel +; CHECK: [[phi0:%\w+]] = OpPhi %float %float_0 +; CHECK: [[phi1:%\w+]] = OpPhi %int %int_0 +; CHECK-NEXT: OpExtInst %void [[ext]] DebugValue [[dbg_f]] [[phi0]] +; CHECK-NEXT: OpExtInst %void [[ext]] DebugValue [[dbg_i]] [[phi1]] +; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] None +; CHECK-NEXT: OpBranch [[loop_body:%\w+]] + +; CHECK-NEXT: [[loop_body]] = OpLabel +; CHECK: OpBranchConditional {{%\w+}} [[bb:%\w+]] [[loop_merge]] + +; CHECK: [[bb]] = OpLabel +; CHECK: OpStore %f [[f_val:%\w+]] +; CHECK-NEXT: OpExtInst %void [[ext]] DebugValue [[dbg_f]] [[f_val]] +; CHECK-NEXT: OpBranch [[loop_cont]] + +; CHECK: [[loop_cont]] = OpLabel +; CHECK: OpStore %i [[i_val:%\w+]] +; CHECK-NEXT: OpExtInst %void [[ext]] DebugValue [[dbg_i]] [[i_val]] +; CHECK-NEXT: OpBranch [[loop_head]] + +; CHECK: [[loop_merge]] = OpLabel + +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "GLSL.std.450" +%ext = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %BC %fo +OpExecutionMode %main OriginUpperLeft +%file_name = OpString "test" +OpSource GLSL 140 +%float_name = OpString "float" +%main_name = OpString "main" +%f_name = OpString "f" +%i_name = OpString "i" +OpName %main "main" +OpName %f "f" +OpName %i "i" +OpName %BC "BC" +OpName %fo "fo" +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 1 +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_10 = OpConstant %uint 10 +%uint_32 = OpConstant %uint 32 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +%int_4 = OpConstant %int 4 +%bool = OpTypeBool +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%BC = OpVariable %_ptr_Input_v4float Input +%_ptr_Input_float = OpTypePointer Input %float +%int_1 = OpConstant %int 1 +%_ptr_Output_float = OpTypePointer Output %float +%fo = OpVariable %_ptr_Output_float Output +%null_expr = OpExtInst %void %ext DebugExpression +%src = OpExtInst %void %ext DebugSource %file_name +%cu = OpExtInst %void %ext DebugCompilationUnit %uint_1 %uint_4 %src %uint_5 +%dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 %uint_3 %uint_0 +%dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_tf %uint_4 +%main_ty = OpExtInst %void %ext DebugTypeFunction %uint_3 %dbg_v4f %dbg_v4f +%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src %uint_0 %uint_0 %cu %main_name %uint_3 %uint_10 +%dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_v4f %src %uint_0 %uint_0 %dbg_main %uint_4 +%dbg_i = OpExtInst %void %ext DebugLocalVariable %i_name %dbg_v4f %src %uint_0 %uint_0 %dbg_main %uint_4 +%main = OpFunction %void None %8 +%22 = OpLabel +%s0 = OpExtInst %void %ext DebugScope %dbg_main +%f = OpVariable %_ptr_Function_float Function +%i = OpVariable %_ptr_Function_int Function +OpStore %f %float_0 +OpStore %i %int_0 +%decl0 = OpExtInst %void %ext DebugDeclare %dbg_f %f %null_expr +%decl1 = OpExtInst %void %ext DebugDeclare %dbg_i %i %null_expr +OpBranch %23 +%23 = OpLabel +%s1 = OpExtInst %void %ext DebugScope %dbg_main +OpLoopMerge %24 %25 None +OpBranch %26 +%26 = OpLabel +%s2 = OpExtInst %void %ext DebugScope %dbg_main +%27 = OpLoad %int %i +%28 = OpSLessThan %bool %27 %int_4 +OpBranchConditional %28 %29 %24 +%29 = OpLabel +%s3 = OpExtInst %void %ext DebugScope %dbg_main +%30 = OpLoad %float %f +%31 = OpLoad %int %i +%32 = OpAccessChain %_ptr_Input_float %BC %31 +%33 = OpLoad %float %32 +%34 = OpFAdd %float %30 %33 +OpStore %f %34 +OpBranch %25 +%25 = OpLabel +%s4 = OpExtInst %void %ext DebugScope %dbg_main +%35 = OpLoad %int %i +%36 = OpIAdd %int %35 %int_1 +OpStore %i %36 +OpBranch %23 +%24 = OpLabel +%s5 = OpExtInst %void %ext DebugScope %dbg_main +%37 = OpLoad %float %f +OpStore %fo %37 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + TEST_F(LocalSSAElimTest, AddDebugValueForFunctionParameterWithPhi) { // Test the distribution of DebugValue for a parameter of an inlined function // and the visibility of Phi instruction. The ssa-rewrite pass must add @@ -4091,6 +4225,32 @@ TEST_F(LocalSSAElimTest, PointerVariables) { SinglePassRunAndMatch(text, true); } +TEST_F(LocalSSAElimTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // No optimization in the presence of diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/unroll_assumptions.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/unroll_assumptions.cpp index 0f93302187..159e4a1430 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/unroll_assumptions.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/unroll_assumptions.cpp @@ -42,6 +42,10 @@ class PartialUnrollerTestPass : public Pass { Status Process() override { bool changed = false; for (Function& f : *context()->module()) { + if (f.IsDeclaration()) { + continue; + } + LoopDescriptor& loop_descriptor = *context()->GetLoopDescriptor(&f); for (auto& loop : loop_descriptor) { LoopUtils loop_utils{context(), &loop}; @@ -1510,6 +1514,33 @@ OpFunctionEnd SinglePassRunAndCheck>(text, text, false); } +TEST_F(PassClassTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); + SinglePassRunAndCheck>(text, text, false); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp index 6a3cb6ee52..ac0dfde787 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp @@ -378,6 +378,185 @@ OpFunctionEnd)"; SinglePassRunAndMatch(text, true); } +TEST_F(PassClassTest, SimpleFullyUnrollWithShaderDebugInstructions) { + // We must preserve the debug information including + // NonSemantic.Shader.DebugInfo.100 instructions and DebugLine instructions. + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "GLSL.std.450" +%ext = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" %3 +OpExecutionMode %2 OriginUpperLeft +OpSource GLSL 330 +%file_name = OpString "test" +%float_name = OpString "float" +%main_name = OpString "main" +%f_name = OpString "f" +%i_name = OpString "i" +OpName %2 "main" +OpName %5 "x" +OpName %3 "c" +OpDecorate %3 Location 0 +%6 = OpTypeVoid +%7 = OpTypeFunction %6 +%8 = OpTypeInt 32 1 +%9 = OpTypePointer Function %8 +%10 = OpConstant %8 0 +%11 = OpConstant %8 4 +%12 = OpTypeBool +%13 = OpTypeFloat 32 +%14 = OpTypeInt 32 0 +%uint_0 = OpConstant %14 0 +%uint_1 = OpConstant %14 1 +%uint_2 = OpConstant %14 2 +%uint_3 = OpConstant %14 3 +%uint_4 = OpConstant %14 4 +%uint_5 = OpConstant %14 5 +%uint_6 = OpConstant %14 6 +%uint_7 = OpConstant %14 7 +%uint_8 = OpConstant %14 8 +%uint_10 = OpConstant %14 10 +%uint_32 = OpConstant %14 32 +%15 = OpConstant %14 4 +%16 = OpTypeArray %13 %15 +%17 = OpTypePointer Function %16 +%18 = OpConstant %13 1 +%19 = OpTypePointer Function %13 +%20 = OpConstant %8 1 +%21 = OpTypeVector %13 4 +%22 = OpTypePointer Output %21 +%3 = OpVariable %22 Output +%null_expr = OpExtInst %6 %ext DebugExpression +%deref = OpExtInst %6 %ext DebugOperation %uint_0 +%deref_expr = OpExtInst %6 %ext DebugExpression %deref +%src = OpExtInst %6 %ext DebugSource %file_name +%cu = OpExtInst %6 %ext DebugCompilationUnit %uint_1 %uint_4 %src %uint_5 +%dbg_tf = OpExtInst %6 %ext DebugTypeBasic %float_name %uint_32 %uint_3 %uint_0 +%dbg_v4f = OpExtInst %6 %ext DebugTypeVector %dbg_tf %uint_4 +%main_ty = OpExtInst %6 %ext DebugTypeFunction %uint_3 %dbg_v4f %dbg_v4f +%dbg_main = OpExtInst %6 %ext DebugFunction %main_name %main_ty %src %uint_0 %uint_0 %cu %main_name %uint_3 %uint_10 +%bb = OpExtInst %6 %ext DebugLexicalBlock %src %uint_0 %uint_0 %dbg_main +%dbg_f = OpExtInst %6 %ext DebugLocalVariable %f_name %dbg_v4f %src %uint_0 %uint_0 %dbg_main %uint_4 +%dbg_i = OpExtInst %6 %ext DebugLocalVariable %i_name %dbg_v4f %src %uint_1 %uint_0 %bb %uint_4 + +; CHECK: [[f:%\w+]] = OpString "f" +; CHECK: [[i:%\w+]] = OpString "i" +; CHECK: [[int_0:%\w+]] = OpConstant {{%\w+}} 0 + +; CHECK: [[null_expr:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugExpression +; CHECK: [[deref:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugOperation %uint_0 +; CHECK: [[deref_expr:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugExpression [[deref]] +; CHECK: [[dbg_fn:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugFunction +; CHECK: [[dbg_bb:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLexicalBlock +; CHECK: [[dbg_f:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLocalVariable [[f]] {{%\w+}} {{%\w+}} %uint_0 %uint_0 [[dbg_fn]] +; CHECK: [[dbg_i:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLocalVariable [[i]] {{%\w+}} {{%\w+}} %uint_1 %uint_0 [[dbg_bb]] + +%2 = OpFunction %6 None %7 +%23 = OpLabel + +; The first block has DebugDeclare and DebugValue with Deref +; +; CHECK: OpLabel +; CHECK: %x = OpVariable %_ptr_Function__arr_float_uint_4_0 Function +; CHECK: OpBranch +; CHECK: OpLabel +; CHECK: DebugScope [[dbg_fn]] +; CHECK: DebugValue [[dbg_f]] [[int_0]] [[null_expr]] +; CHECK: OpBranch +; CHECK: DebugScope [[dbg_fn]] +; CHECK: DebugLine {{%\w+}} %uint_1 %uint_1 %uint_1 %uint_1 +; CHECK: OpSLessThan +; CHECK: DebugLine {{%\w+}} %uint_2 %uint_2 %uint_0 %uint_0 +; CHECK: OpBranch +; CHECK: OpLabel +; CHECK: DebugScope [[dbg_bb]] +; CHECK: DebugDeclare [[dbg_f]] %x [[null_expr]] +; CHECK: DebugValue [[dbg_i]] %x [[deref_expr]] +; CHECK: DebugLine {{%\w+}} %uint_3 %uint_3 %uint_0 %uint_0 +; +; CHECK: DebugLine {{%\w+}} %uint_6 %uint_6 %uint_0 %uint_0 +; CHECK: [[add:%\w+]] = OpIAdd +; CHECK: DebugValue [[dbg_f]] [[add]] [[null_expr]] +; CHECK: DebugLine {{%\w+}} %uint_7 %uint_7 %uint_0 %uint_0 + +; Other blocks do not have DebugDeclare and DebugValue with Deref +; +; CHECK: DebugScope [[dbg_fn]] +; CHECK: DebugLine {{%\w+}} %uint_1 %uint_1 %uint_1 %uint_1 +; CHECK: OpSLessThan +; CHECK: DebugLine {{%\w+}} %uint_2 %uint_2 %uint_0 %uint_0 +; CHECK: OpBranch +; CHECK: OpLabel +; +; CHECK: DebugScope [[dbg_bb]] +; CHECK-NOT: DebugDeclare [[dbg_f]] %x [[null_expr]] +; CHECK-NOT: DebugValue [[dbg_i]] %x [[deref_expr]] +; CHECK: DebugLine {{%\w+}} %uint_3 %uint_3 %uint_0 %uint_0 +; +; CHECK: DebugLine {{%\w+}} %uint_6 %uint_6 %uint_0 %uint_0 +; CHECK: [[add:%\w+]] = OpIAdd +; CHECK: DebugValue [[dbg_f]] [[add]] [[null_expr]] +; CHECK: DebugLine {{%\w+}} %uint_7 %uint_7 %uint_0 %uint_0 +; +; CHECK-NOT: DebugDeclare [[dbg_f]] %x [[null_expr]] +; CHECK-NOT: DebugValue [[dbg_i]] %x [[deref_expr]] +; CHECK: DebugScope [[dbg_fn]] +; CHECK: DebugLine {{%\w+}} %uint_8 %uint_8 %uint_0 %uint_0 +; CHECK: OpReturn + +%5 = OpVariable %17 Function +OpBranch %24 +%24 = OpLabel +%35 = OpPhi %8 %10 %23 %34 %26 +%s1 = OpExtInst %6 %ext DebugScope %dbg_main +%d10 = OpExtInst %6 %ext DebugLine %file_name %uint_1 %uint_1 %uint_0 %uint_0 +%value0 = OpExtInst %6 %ext DebugValue %dbg_f %35 %null_expr +OpLoopMerge %25 %26 Unroll +OpBranch %27 +%27 = OpLabel +%s2 = OpExtInst %6 %ext DebugScope %dbg_main +%d1 = OpExtInst %6 %ext DebugLine %file_name %uint_1 %uint_1 %uint_1 %uint_1 +%29 = OpSLessThan %12 %35 %11 +%d2 = OpExtInst %6 %ext DebugLine %file_name %uint_2 %uint_2 %uint_0 %uint_0 +OpBranchConditional %29 %30 %25 +%30 = OpLabel +%s3 = OpExtInst %6 %ext DebugScope %bb +%decl0 = OpExtInst %6 %ext DebugDeclare %dbg_f %5 %null_expr +%decl1 = OpExtInst %6 %ext DebugValue %dbg_i %5 %deref_expr +%d3 = OpExtInst %6 %ext DebugLine %file_name %uint_3 %uint_3 %uint_0 %uint_0 +%32 = OpAccessChain %19 %5 %35 +%d4 = OpExtInst %6 %ext DebugLine %file_name %uint_4 %uint_4 %uint_0 %uint_0 +OpStore %32 %18 +%d5 = OpExtInst %6 %ext DebugLine %file_name %uint_5 %uint_5 %uint_0 %uint_0 +OpBranch %26 +%26 = OpLabel +%s4 = OpExtInst %6 %ext DebugScope %dbg_main +%d6 = OpExtInst %6 %ext DebugLine %file_name %uint_6 %uint_6 %uint_0 %uint_0 +%34 = OpIAdd %8 %35 %20 +%value1 = OpExtInst %6 %ext DebugValue %dbg_f %34 %null_expr +%d7 = OpExtInst %6 %ext DebugLine %file_name %uint_7 %uint_7 %uint_0 %uint_0 +OpBranch %24 +%25 = OpLabel +%s5 = OpExtInst %6 %ext DebugScope %dbg_main +%d8 = OpExtInst %6 %ext DebugLine %file_name %uint_8 %uint_8 %uint_0 %uint_0 +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + Module* module = context->module(); + EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n" + << text << std::endl; + + LoopUnroller loop_unroller; + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + SinglePassRunAndMatch(text, true); +} + template class PartialUnrollerTestPass : public Pass { public: diff --git a/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp b/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp index fd97efab53..21960d1799 100644 --- a/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp +++ b/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp @@ -2567,6 +2567,39 @@ TEST_F(MergeReturnPassTest, ChainedPointerUsedAfterLoop) { SinglePassRunAndMatch(before, true); } +TEST_F(MergeReturnPassTest, OverflowTest1) { + const std::string text = + R"( +; CHECK: OpReturn +; CHECK-NOT: OpReturn +; CHECK: OpFunctionEnd + OpCapability ClipDistance + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + %void = OpTypeVoid + %6 = OpTypeFunction %void + %2 = OpFunction %void None %6 + %4194303 = OpLabel + OpBranch %18 + %18 = OpLabel + OpLoopMerge %19 %20 None + OpBranch %21 + %21 = OpLabel + OpReturn + %20 = OpLabel + OpBranch %18 + %19 = OpLabel + OpUnreachable + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = + SinglePassRunToBinary(text, /* skip_nop = */ true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp b/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp index 7672e8f309..abb5cde670 100644 --- a/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp +++ b/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp @@ -17,6 +17,12 @@ #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" +namespace { + +const double kDefaultLoadReductionThreshold = 0.9; + +} // namespace + namespace spvtools { namespace opt { namespace { @@ -104,7 +110,8 @@ TEST_F(ReduceLoadSizeTest, cbuffer_load_extract) { SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); - SinglePassRunAndMatch(test, false); + SinglePassRunAndMatch(test, false, + kDefaultLoadReductionThreshold); } TEST_F(ReduceLoadSizeTest, cbuffer_load_extract_not_affected_by_debug_instr) { @@ -202,7 +209,8 @@ TEST_F(ReduceLoadSizeTest, cbuffer_load_extract_not_affected_by_debug_instr) { SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); - SinglePassRunAndMatch(test, false); + SinglePassRunAndMatch(test, false, + kDefaultLoadReductionThreshold); } TEST_F(ReduceLoadSizeTest, cbuffer_load_extract_vector) { @@ -280,7 +288,8 @@ OpFunctionEnd SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); - SinglePassRunAndCheck(test, test, true, false); + SinglePassRunAndCheck(test, test, true, false, + kDefaultLoadReductionThreshold); } TEST_F(ReduceLoadSizeTest, cbuffer_load_5_extract) { @@ -351,7 +360,8 @@ OpFunctionEnd SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); - SinglePassRunAndCheck(test, test, true, false); + SinglePassRunAndCheck(test, test, true, false, + kDefaultLoadReductionThreshold); } TEST_F(ReduceLoadSizeTest, cbuffer_load_fully_used) { @@ -416,7 +426,76 @@ OpFunctionEnd SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); - SinglePassRunAndCheck(test, test, true, false); + SinglePassRunAndCheck(test, test, true, false, + kDefaultLoadReductionThreshold); +} + +TEST_F(ReduceLoadSizeTest, replace_cbuffer_load_fully_used) { + const std::string test = + R"( + OpCapability Shader + OpCapability SampledBuffer + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %out_var_SV_Target0 + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + OpName %type_MaterialInstancing_cbuffer "type.MaterialInstancing_cbuffer" + OpMemberName %type_MaterialInstancing_cbuffer 0 "MaterialInstancing_constants" + OpName %MaterialInstancing_Constants "MaterialInstancing_Constants" + OpMemberName %MaterialInstancing_Constants 0 "offset0" + OpMemberName %MaterialInstancing_Constants 1 "params" + OpName %InstancingParams_Constants "InstancingParams_Constants" + OpMemberName %InstancingParams_Constants 0 "offset1" + OpName %MaterialInstancing_cbuffer "MaterialInstancing_cbuffer" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %main "main" + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %MaterialInstancing_cbuffer DescriptorSet 6 + OpDecorate %MaterialInstancing_cbuffer Binding 0 + OpMemberDecorate %InstancingParams_Constants 0 Offset 0 + OpMemberDecorate %MaterialInstancing_Constants 0 Offset 0 + OpMemberDecorate %MaterialInstancing_Constants 1 Offset 16 + OpMemberDecorate %type_MaterialInstancing_cbuffer 0 Offset 0 + OpDecorate %type_MaterialInstancing_cbuffer Block + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %v4int = OpTypeVector %int 4 +%InstancingParams_Constants = OpTypeStruct %v4int +%MaterialInstancing_Constants = OpTypeStruct %v4int %InstancingParams_Constants +%type_MaterialInstancing_cbuffer = OpTypeStruct %MaterialInstancing_Constants +%_ptr_Uniform_type_MaterialInstancing_cbuffer = OpTypePointer Uniform %type_MaterialInstancing_cbuffer +%_ptr_Output_int = OpTypePointer Output %int + %void = OpTypeVoid + %60 = OpTypeFunction %void +%_ptr_Uniform_MaterialInstancing_Constants = OpTypePointer Uniform %MaterialInstancing_Constants +%MaterialInstancing_cbuffer = OpVariable %_ptr_Uniform_type_MaterialInstancing_cbuffer Uniform +%out_var_SV_Target0 = OpVariable %_ptr_Output_int Output + %main = OpFunction %void None %60 + %80 = OpLabel + %131 = OpAccessChain %_ptr_Uniform_MaterialInstancing_Constants %MaterialInstancing_cbuffer %int_0 + %132 = OpLoad %MaterialInstancing_Constants %131 +; CHECK: [[ac1:%\w+]] = OpAccessChain {{%\w+}} %MaterialInstancing_cbuffer %int_0 +; CHECK: [[ac2:%\w+]] = OpAccessChain {{%\w+}} [[ac1]] %uint_0 +; CHECK: OpLoad %v4int [[ac2]] + +; CHECK: [[ac3:%\w+]] = OpAccessChain {{%\w+}} [[ac1]] %uint_1 +; CHECK: [[ac4:%\w+]] = OpAccessChain {{%\w+}} [[ac3]] %uint_0 +; CHECK: OpLoad %v4int [[ac4]] + %134 = OpCompositeExtract %v4int %132 0 + %135 = OpCompositeExtract %InstancingParams_Constants %132 1 + %136 = OpCompositeExtract %v4int %135 0 + %149 = OpCompositeExtract %int %134 0 + %185 = OpCompositeExtract %int %136 0 + %156 = OpIAdd %int %149 %185 + OpStore %out_var_SV_Target0 %156 + OpReturn + OpFunctionEnd + )"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + SinglePassRunAndMatch(test, false, 1.1); } } // namespace diff --git a/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp b/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp index 474f466164..28eda73eff 100644 --- a/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp +++ b/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp @@ -335,6 +335,32 @@ TEST_F(RedundancyEliminationTest, OpenCLDebugInfo100) { SinglePassRunAndMatch(text, false); } +TEST_F(RedundancyEliminationTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + } // namespace } // namespace opt -} // namespace spvtools +} // namespace spvtools \ No newline at end of file diff --git a/third_party/spirv-tools/test/opt/relax_float_ops_test.cpp b/third_party/spirv-tools/test/opt/relax_float_ops_test.cpp index 14cde0b94d..b9cb0de097 100644 --- a/third_party/spirv-tools/test/opt/relax_float_ops_test.cpp +++ b/third_party/spirv-tools/test/opt/relax_float_ops_test.cpp @@ -137,6 +137,86 @@ OpFunctionEnd true); } +TEST_F(RelaxFloatOpsTest, RelaxFloatOpsForLinkage) { + const std::string defs0 = + R"(OpCapability Shader +OpCapability Linkage +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpSource HLSL 630 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %i_Tex0 "i.Tex0" +OpName %i_Tex1 "i.Tex1" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %main LinkageAttributes "main" Export +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpDecorate %i_Tex0 Location 0 +OpDecorate %i_Tex1 Location 1 +OpDecorate %_entryPointOutput_Color Location 0 +)"; + + const std::string defs1 = + R"(%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%17 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant +%21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 +%g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant +%25 = OpTypeSampledImage %17 +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%i_Tex1 = OpVariable %_ptr_Input_float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%float_0_5 = OpConstant %float 0.5 +%116 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 +)"; + + const std::string relax_decos = + R"(OpDecorate %60 RelaxedPrecision +OpDecorate %63 RelaxedPrecision +OpDecorate %82 RelaxedPrecision +OpDecorate %88 RelaxedPrecision +OpDecorate %91 RelaxedPrecision +OpDecorate %94 RelaxedPrecision +)"; + + const std::string func_orig = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%60 = OpLoad %float %i_Tex0 +%63 = OpLoad %float %i_Tex1 +%77 = OpLoad %17 %g_tTex1df4 +%78 = OpLoad %21 %g_sSamp +%79 = OpSampledImage %25 %77 %78 +%82 = OpImageSampleImplicitLod %v4float %79 %60 +%83 = OpLoad %17 %g_tTex1df4 +%84 = OpLoad %21 %g_sSamp +%85 = OpSampledImage %25 %83 %84 +%88 = OpImageSampleImplicitLod %v4float %85 %63 +%91 = OpFAdd %v4float %82 %88 +%94 = OpFMul %v4float %91 %116 +OpStore %_entryPointOutput_Color %94 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs0 + defs1 + func_orig, defs0 + relax_decos + defs1 + func_orig, true, + true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/replace_desc_array_access_using_var_index_test.cpp b/third_party/spirv-tools/test/opt/replace_desc_array_access_using_var_index_test.cpp new file mode 100644 index 0000000000..ca62581265 --- /dev/null +++ b/third_party/spirv-tools/test/opt/replace_desc_array_access_using_var_index_test.cpp @@ -0,0 +1,411 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 "gmock/gmock.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using ReplaceDescArrayAccessUsingVarIndexTest = PassTest<::testing::Test>; + +TEST_F(ReplaceDescArrayAccessUsingVarIndexTest, + ReplaceAccessChainToTextureArray) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %psmain "psmain" %gl_FragCoord %in_var_INSTANCEID %out_var_SV_TARGET + OpExecutionMode %psmain OriginUpperLeft + OpSource HLSL 600 + OpName %type_sampler "type.sampler" + OpName %Sampler0 "Sampler0" + OpName %type_2d_image "type.2d.image" + OpName %Tex0 "Tex0" + OpName %in_var_INSTANCEID "in.var.INSTANCEID" + OpName %out_var_SV_TARGET "out.var.SV_TARGET" + OpName %psmain "psmain" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %in_var_INSTANCEID Flat + OpDecorate %in_var_INSTANCEID Location 0 + OpDecorate %out_var_SV_TARGET Location 0 + OpDecorate %Sampler0 DescriptorSet 0 + OpDecorate %Sampler0 Binding 1 + OpDecorate %Tex0 DescriptorSet 0 + OpDecorate %Tex0 Binding 2 + %bool = OpTypeBool +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 + %float = OpTypeFloat 32 +%type_2d_image = OpTypeImage %float 2D 2 0 0 0 Unknown +%_arr_type_2d_image_uint_3 = OpTypeArray %type_2d_image %uint_3 +%_ptr_UniformConstant__arr_type_2d_image_uint_3 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_3 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %21 = OpTypeFunction %void +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %v2float = OpTypeVector %float 2 + %v2uint = OpTypeVector %uint 2 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %27 = OpConstantComposite %v2uint %uint_0 %uint_1 +%type_sampled_image = OpTypeSampledImage %type_2d_image + %Sampler0 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %Tex0 = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_3 UniformConstant +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%in_var_INSTANCEID = OpVariable %_ptr_Input_uint Input +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output + %uint_2 = OpConstant %uint 2 + %66 = OpConstantNull %v4float + +; CHECK: [[null_value:%\w+]] = OpConstantNull %v4float + + %psmain = OpFunction %void None %21 + %39 = OpLabel + %29 = OpLoad %v4float %gl_FragCoord + %30 = OpLoad %uint %in_var_INSTANCEID + %37 = OpIEqual %bool %30 %uint_2 + OpSelectionMerge %38 None + OpBranchConditional %37 %28 %40 + +; CHECK: [[var_index:%\w+]] = OpLoad %uint %in_var_INSTANCEID +; CHECK: OpSelectionMerge [[cond_branch_merge:%\w+]] None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} [[bb_cond_br:%\w+]] + + %28 = OpLabel + %31 = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %30 + %32 = OpLoad %type_2d_image %31 + OpImageWrite %32 %27 %29 + +; CHECK: OpSelectionMerge [[merge:%\w+]] None +; CHECK: OpSwitch [[var_index]] [[default:%\w+]] 0 [[case0:%\w+]] 1 [[case1:%\w+]] 2 [[case2:%\w+]] +; CHECK: [[case0]] = OpLabel +; CHECK: OpAccessChain +; CHECK: OpLoad +; CHECK: OpImageWrite +; CHECK: OpBranch [[merge]] +; CHECK: [[case1]] = OpLabel +; CHECK: OpAccessChain +; CHECK: OpLoad +; CHECK: OpImageWrite +; CHECK: OpBranch [[merge]] +; CHECK: [[case2]] = OpLabel +; CHECK: OpAccessChain +; CHECK: OpLoad +; CHECK: OpImageWrite +; CHECK: OpBranch [[merge]] +; CHECK: [[default]] = OpLabel +; CHECK: OpBranch [[merge]] +; CHECK: [[merge]] = OpLabel + + %33 = OpLoad %type_sampler %Sampler0 + %34 = OpVectorShuffle %v2float %29 %29 0 1 + %35 = OpSampledImage %type_sampled_image %32 %33 + %36 = OpImageSampleImplicitLod %v4float %35 %34 None + +; CHECK: OpSelectionMerge [[merge:%\w+]] None +; CHECK: OpSwitch [[var_index]] [[default:%\w+]] 0 [[case0:%\w+]] 1 [[case1:%\w+]] 2 [[case2:%\w+]] +; CHECK: [[case0]] = OpLabel +; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_0 +; CHECK: [[sam:%\w+]] = OpLoad %type_sampler %Sampler0 +; CHECK: [[img:%\w+]] = OpLoad %type_2d_image [[ac]] +; CHECK: [[sampledImg:%\w+]] = OpSampledImage %type_sampled_image [[img]] [[sam]] +; CHECK: [[value0:%\w+]] = OpImageSampleImplicitLod %v4float [[sampledImg]] +; CHECK: OpBranch [[merge]] +; CHECK: [[case1]] = OpLabel +; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_1 +; CHECK: [[sam:%\w+]] = OpLoad %type_sampler %Sampler0 +; CHECK: [[img:%\w+]] = OpLoad %type_2d_image [[ac]] +; CHECK: [[sampledImg:%\w+]] = OpSampledImage %type_sampled_image [[img]] [[sam]] +; CHECK: [[value1:%\w+]] = OpImageSampleImplicitLod %v4float [[sampledImg]] +; CHECK: OpBranch [[merge]] +; CHECK: [[case2]] = OpLabel +; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_2 +; CHECK: [[sam:%\w+]] = OpLoad %type_sampler %Sampler0 +; CHECK: [[img:%\w+]] = OpLoad %type_2d_image [[ac]] +; CHECK: [[sampledImg:%\w+]] = OpSampledImage %type_sampled_image [[img]] [[sam]] +; CHECK: [[value2:%\w+]] = OpImageSampleImplicitLod %v4float [[sampledImg]] +; CHECK: OpBranch [[merge]] +; CHECK: [[default]] = OpLabel +; CHECK: OpBranch [[merge]] +; CHECK: [[merge]] = OpLabel +; CHECK: [[phi0:%\w+]] = OpPhi %v4float [[value0]] [[case0]] [[value1]] [[case1]] [[value2]] [[case2]] [[null_value]] [[default]] + + OpBranch %38 + %40 = OpLabel + OpBranch %38 + %38 = OpLabel + %41 = OpPhi %v4float %36 %28 %29 %40 + +; CHECK: OpBranch [[cond_branch_merge]] +; CHECK: [[bb_cond_br]] = OpLabel +; CHECK: OpBranch [[cond_branch_merge]] +; CHECK: [[cond_branch_merge]] = OpLabel +; CHECK: [[phi1:%\w+]] = OpPhi %v4float [[phi0]] [[merge]] {{%\w+}} [[bb_cond_br]] +; CHECK: OpStore {{%\w+}} [[phi1]] + + OpStore %out_var_SV_TARGET %41 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(ReplaceDescArrayAccessUsingVarIndexTest, + ReplaceAccessChainToTextureArrayAndSamplerArray) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %psmain "psmain" %gl_FragCoord %in_var_INSTANCEID %out_var_SV_TARGET + OpExecutionMode %psmain OriginUpperLeft + OpSource HLSL 600 + OpName %type_sampler "type.sampler" + OpName %Sampler0 "Sampler0" + OpName %type_2d_image "type.2d.image" + OpName %Tex0 "Tex0" + OpName %in_var_INSTANCEID "in.var.INSTANCEID" + OpName %out_var_SV_TARGET "out.var.SV_TARGET" + OpName %psmain "psmain" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %in_var_INSTANCEID Flat + OpDecorate %in_var_INSTANCEID Location 0 + OpDecorate %out_var_SV_TARGET Location 0 + OpDecorate %Sampler0 DescriptorSet 0 + OpDecorate %Sampler0 Binding 1 + OpDecorate %Tex0 DescriptorSet 0 + OpDecorate %Tex0 Binding 2 +%type_sampler = OpTypeSampler + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%_arr_type_sampler_uint_2 = OpTypeArray %type_sampler %uint_2 +%_ptr_UniformConstant__arr_type_sampler_uint_2 = OpTypePointer UniformConstant %_arr_type_sampler_uint_2 + %float = OpTypeFloat 32 +%type_2d_image = OpTypeImage %float 2D 2 0 0 0 Unknown +%_arr_type_2d_image_uint_2 = OpTypeArray %type_2d_image %uint_2 +%_ptr_UniformConstant__arr_type_2d_image_uint_2 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_2 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %21 = OpTypeFunction %void +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %v2float = OpTypeVector %float 2 + %v2uint = OpTypeVector %uint 2 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %27 = OpConstantComposite %v2uint %uint_0 %uint_1 +%type_sampled_image = OpTypeSampledImage %type_2d_image + %Sampler0 = OpVariable %_ptr_UniformConstant__arr_type_sampler_uint_2 UniformConstant + %Tex0 = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_2 UniformConstant +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%in_var_INSTANCEID = OpVariable %_ptr_Input_uint Input +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output + %66 = OpConstantNull %v4float + %psmain = OpFunction %void None %21 + %28 = OpLabel + %29 = OpLoad %v4float %gl_FragCoord + %30 = OpLoad %uint %in_var_INSTANCEID + %31 = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %30 + %32 = OpLoad %type_2d_image %31 + OpImageWrite %32 %27 %29 + +; CHECK: [[null_value:%\w+]] = OpConstantNull %v4float + +; CHECK: [[var_index:%\w+]] = OpLoad %uint %in_var_INSTANCEID +; CHECK: OpSelectionMerge [[merge:%\w+]] None +; CHECK: OpSwitch [[var_index]] [[default:%\w+]] 0 [[case0:%\w+]] 1 [[case1:%\w+]] +; CHECK: [[case0]] = OpLabel +; CHECK: OpAccessChain +; CHECK: OpLoad +; CHECK: OpImageWrite +; CHECK: OpBranch [[merge]] +; CHECK: [[case1]] = OpLabel +; CHECK: OpAccessChain +; CHECK: OpLoad +; CHECK: OpImageWrite +; CHECK: OpBranch [[merge]] +; CHECK: [[default]] = OpLabel +; CHECK: OpBranch [[merge]] +; CHECK: [[merge]] = OpLabel + + %33 = OpAccessChain %_ptr_UniformConstant_type_sampler %Sampler0 %30 + %37 = OpLoad %type_sampler %33 + %34 = OpVectorShuffle %v2float %29 %29 0 1 + %35 = OpSampledImage %type_sampled_image %32 %37 + %36 = OpImageSampleImplicitLod %v4float %35 %34 None + +; SPIR-V instructions to be replaced (will be killed by ADCE) +; CHECK: OpSelectionMerge +; CHECK: OpSwitch + +; CHECK: OpSelectionMerge [[merge_sampler:%\w+]] None +; CHECK: OpSwitch [[var_index]] [[default_sampler:%\w+]] 0 [[case_sampler0:%\w+]] 1 [[case_sampler1:%\w+]] + +; CHECK: [[case_sampler0]] = OpLabel +; CHECK: OpSelectionMerge [[merge_texture0:%\w+]] None +; CHECK: OpSwitch [[var_index]] [[default_texture:%\w+]] 0 [[case_texture0:%\w+]] 1 [[case_texture1:%\w+]] +; CHECK: [[case_texture0]] = OpLabel +; CHECK: [[pt0:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_0 +; CHECK: [[ps0:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_sampler %Sampler0 %uint_0 +; CHECK: [[s0:%\w+]] = OpLoad %type_sampler [[ps0]] +; CHECK: [[t0:%\w+]] = OpLoad %type_2d_image [[pt0]] +; CHECK: [[sampledImg0:%\w+]] = OpSampledImage %type_sampled_image [[t0]] [[s0]] +; CHECK: [[value0:%\w+]] = OpImageSampleImplicitLod %v4float [[sampledImg0]] +; CHECK: OpBranch [[merge_texture0]] +; CHECK: [[case_texture1]] = OpLabel +; CHECK: [[pt1:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_1 +; CHECK: [[ps0:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_sampler %Sampler0 %uint_0 +; CHECK: [[s0:%\w+]] = OpLoad %type_sampler [[ps0]] +; CHECK: [[t1:%\w+]] = OpLoad %type_2d_image [[pt1]] +; CHECK: [[sampledImg1:%\w+]] = OpSampledImage %type_sampled_image [[t1]] [[s0]] +; CHECK: [[value1:%\w+]] = OpImageSampleImplicitLod %v4float [[sampledImg1]] +; CHECK: OpBranch [[merge_texture0]] +; CHECK: [[default_texture]] = OpLabel +; CHECK: OpBranch [[merge_texture0]] +; CHECK: [[merge_texture0]] = OpLabel +; CHECK: [[phi0:%\w+]] = OpPhi %v4float [[value0]] [[case_texture0]] [[value1]] [[case_texture1]] [[null_value]] [[default_texture]] +; CHECK: OpBranch [[merge_sampler]] + +; CHECK: [[case_sampler1]] = OpLabel +; CHECK: OpSelectionMerge [[merge_texture1:%\w+]] None +; CHECK: OpSwitch [[var_index]] [[default_texture:%\w+]] 0 [[case_texture0:%\w+]] 1 [[case_texture1:%\w+]] +; CHECK: [[case_texture0]] = OpLabel +; CHECK: [[pt0:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_0 +; CHECK: [[ps1:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_sampler %Sampler0 %uint_1 +; CHECK: [[s1:%\w+]] = OpLoad %type_sampler [[ps1]] +; CHECK: [[t0:%\w+]] = OpLoad %type_2d_image [[pt0]] +; CHECK: [[sampledImg0:%\w+]] = OpSampledImage %type_sampled_image [[t0]] [[s1]] +; CHECK: [[value0:%\w+]] = OpImageSampleImplicitLod %v4float [[sampledImg0]] +; CHECK: OpBranch [[merge_texture1]] +; CHECK: [[case_texture1]] = OpLabel +; CHECK: [[pt1:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_1 +; CHECK: [[ps1:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_sampler %Sampler0 %uint_1 +; CHECK: [[s1:%\w+]] = OpLoad %type_sampler [[ps1]] +; CHECK: [[t1:%\w+]] = OpLoad %type_2d_image [[pt1]] +; CHECK: [[sampledImg1:%\w+]] = OpSampledImage %type_sampled_image [[t1]] [[s1]] +; CHECK: [[value1:%\w+]] = OpImageSampleImplicitLod %v4float [[sampledImg1]] +; CHECK: OpBranch [[merge_texture1]] +; CHECK: [[default_texture]] = OpLabel +; CHECK: OpBranch [[merge_texture1]] +; CHECK: [[merge_texture1]] = OpLabel +; CHECK: [[phi1:%\w+]] = OpPhi %v4float [[value0]] [[case_texture0]] [[value1]] [[case_texture1]] [[null_value]] [[default_texture]] + +; CHECK: [[default_sampler]] = OpLabel +; CHECK: OpBranch [[merge_sampler]] +; CHECK: [[merge_sampler]] = OpLabel +; CHECK: OpPhi %v4float [[phi0]] [[merge_texture0]] [[phi1]] [[merge_texture1]] [[null_value]] [[default_sampler]] +; CHECK: OpStore + + OpStore %out_var_SV_TARGET %36 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(ReplaceDescArrayAccessUsingVarIndexTest, + ReplaceAccessChainToTextureArrayWithSingleElement) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %psmain "psmain" %gl_FragCoord %in_var_INSTANCEID %out_var_SV_TARGET + OpExecutionMode %psmain OriginUpperLeft + OpSource HLSL 600 + OpName %type_sampler "type.sampler" + OpName %Sampler0 "Sampler0" + OpName %type_2d_image "type.2d.image" + OpName %Tex0 "Tex0" + OpName %in_var_INSTANCEID "in.var.INSTANCEID" + OpName %out_var_SV_TARGET "out.var.SV_TARGET" + OpName %psmain "psmain" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %in_var_INSTANCEID Flat + OpDecorate %in_var_INSTANCEID Location 0 + OpDecorate %out_var_SV_TARGET Location 0 + OpDecorate %Sampler0 DescriptorSet 0 + OpDecorate %Sampler0 Binding 1 + OpDecorate %Tex0 DescriptorSet 0 + OpDecorate %Tex0 Binding 2 +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %float = OpTypeFloat 32 +%type_2d_image = OpTypeImage %float 2D 2 0 0 0 Unknown +%_arr_type_2d_image_uint_1 = OpTypeArray %type_2d_image %uint_1 +%_ptr_UniformConstant__arr_type_2d_image_uint_1 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_1 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %21 = OpTypeFunction %void +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %v2float = OpTypeVector %float 2 + %v2uint = OpTypeVector %uint 2 + %uint_0 = OpConstant %uint 0 + %27 = OpConstantComposite %v2uint %uint_0 %uint_1 +%type_sampled_image = OpTypeSampledImage %type_2d_image + %Sampler0 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %Tex0 = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_1 UniformConstant +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%in_var_INSTANCEID = OpVariable %_ptr_Input_uint Input +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output + %uint_2 = OpConstant %uint 2 + %66 = OpConstantNull %v4float + %psmain = OpFunction %void None %21 + %28 = OpLabel + %29 = OpLoad %v4float %gl_FragCoord + %30 = OpLoad %uint %in_var_INSTANCEID + %31 = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %30 + %32 = OpLoad %type_2d_image %31 + OpImageWrite %32 %27 %29 + +; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %Tex0 %uint_0 +; CHECK-NOT: OpAccessChain +; CHECK-NOT: OpSwitch +; CHECK-NOT: OpPhi + + %33 = OpLoad %type_sampler %Sampler0 + %34 = OpVectorShuffle %v2float %29 %29 0 1 + %35 = OpSampledImage %type_sampled_image %32 %33 + %36 = OpImageSampleImplicitLod %v4float %35 %34 None + + OpStore %out_var_SV_TARGET %36 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp b/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp index 8115f5fb57..8cb888c93e 100644 --- a/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp +++ b/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp @@ -1935,12 +1935,12 @@ OpName %6 "simple_struct" ; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable ; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]] ; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function -; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_3 ; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function -; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2 ; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function -; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 ; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function +; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_3 +; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2 +; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 ; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0 ; CHECK-NOT: DebugDeclare %decl = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr @@ -2058,10 +2058,10 @@ OpName %6 "simple_struct" ; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_float Function %float_1 ; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_32 ; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_float Function %float_1 +; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_32 ; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_2 ; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 %int_0 ; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_1 %int_1 -; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_32 ; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0 ; CHECK-NOT: DebugDeclare %decl = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr @@ -2174,12 +2174,12 @@ OpName %6 "simple_struct" ; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugLocalVariable ; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function -; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr:%\w+]] %int_3 ; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function -; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2 ; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function -; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 ; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function +; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr:%\w+]] %int_3 +; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2 +; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 ; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0 OpBranch %20 @@ -2237,6 +2237,32 @@ OpFunctionEnd SinglePassRunAndMatch(text, false); } +TEST_F(ScalarReplacementTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp b/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp index 5e63862e9a..f1dd50eee3 100644 --- a/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp +++ b/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp @@ -935,6 +935,98 @@ INSTANTIATE_TEST_SUITE_P( "%2 = OpSpecConstantTrue %bool\n" "%3 = OpSpecConstantTrue %bool\n", }, + // 19. 16-bit signed int type. + { + // code + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "%short = OpTypeInt 16 1\n" + "%1 = OpSpecConstant %short 10\n" + "%2 = OpSpecConstant %short 11\n" + "%3 = OpSpecConstant %short 11\n", + // default values + SpecIdToValueBitPatternMap{ + {100, {32767}}, {101, {0xffff}}, {102, {0xffffffd6}}}, + // expected. These are sign-extended + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "%short = OpTypeInt 16 1\n" + "%1 = OpSpecConstant %short 32767\n" + "%2 = OpSpecConstant %short -1\n" + "%3 = OpSpecConstant %short -42\n", + }, + // 20. 16-bit unsigned int type. + { + // code + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "%ushort = OpTypeInt 16 0\n" + "%1 = OpSpecConstant %ushort 10\n" + "%2 = OpSpecConstant %ushort 11\n" + "%3 = OpSpecConstant %ushort 11\n", + // default values + SpecIdToValueBitPatternMap{ + {100, {32767}}, {101, {0xffff}}, {102, {0xffffffd6}}}, + // expected. Upper bits are always zero. + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "%ushort = OpTypeInt 16 0\n" + "%1 = OpSpecConstant %ushort 32767\n" + "%2 = OpSpecConstant %ushort 65535\n" + "%3 = OpSpecConstant %ushort 65494\n", + }, + // 21. 8-bit signed int type. + { + // code + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "%char = OpTypeInt 8 1\n" + "%1 = OpSpecConstant %char 10\n" + "%2 = OpSpecConstant %char 11\n" + "%3 = OpSpecConstant %char 11\n", + // default values + SpecIdToValueBitPatternMap{ + {100, {127}}, {101, {128}}, {102, {0xd6}}}, + // expected. These are sign extended + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "%char = OpTypeInt 8 1\n" + "%1 = OpSpecConstant %char 127\n" + "%2 = OpSpecConstant %char -128\n" + "%3 = OpSpecConstant %char -42\n", + }, + // 22. 8-bit unsigned int type. + { + // code + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "OpDecorate %4 SpecId 103\n" + "%uchar = OpTypeInt 8 0\n" + "%1 = OpSpecConstant %uchar 10\n" + "%2 = OpSpecConstant %uchar 11\n" + "%3 = OpSpecConstant %uchar 11\n" + "%4 = OpSpecConstant %uchar 11\n", + // default values + SpecIdToValueBitPatternMap{ + {100, {127}}, {101, {128}}, {102, {256}}, {103, {0xffffffd6}}}, + // expected. Upper bits are always zero. + "OpDecorate %1 SpecId 100\n" + "OpDecorate %2 SpecId 101\n" + "OpDecorate %3 SpecId 102\n" + "OpDecorate %4 SpecId 103\n" + "%uchar = OpTypeInt 8 0\n" + "%1 = OpSpecConstant %uchar 127\n" + "%2 = OpSpecConstant %uchar 128\n" + "%3 = OpSpecConstant %uchar 0\n" + "%4 = OpSpecConstant %uchar 214\n", + }, })); INSTANTIATE_TEST_SUITE_P( diff --git a/third_party/spirv-tools/test/opt/simplification_test.cpp b/third_party/spirv-tools/test/opt/simplification_test.cpp index 7a9696eab4..7727f5673d 100644 --- a/third_party/spirv-tools/test/opt/simplification_test.cpp +++ b/third_party/spirv-tools/test/opt/simplification_test.cpp @@ -360,6 +360,31 @@ OpFunctionEnd SinglePassRunAndMatch(spirv, true); } +TEST_F(SimplificationTest, FunctionDeclaration) { + // Make sure the pass works with a function declaration that is called. + const std::string text = R"(OpCapability Addresses +OpCapability Linkage +OpCapability Kernel +OpCapability Int8 +%1 = OpExtInstImport "OpenCL.std" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" +OpExecutionMode %2 ContractionOff +OpSource Unknown 0 +OpDecorate %3 LinkageAttributes "julia_error_7712" Import +%void = OpTypeVoid +%5 = OpTypeFunction %void +%3 = OpFunction %void None %5 +OpFunctionEnd +%2 = OpFunction %void None %5 +%6 = OpLabel +%7 = OpFunctionCall %void %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp b/third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp index 7f64ffd7cf..2cd3c7dfb5 100644 --- a/third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp +++ b/third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp @@ -404,7 +404,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpDecorate %param Coherent -OpDecorate %param ArrayStride 4 +OpDecorate %ptr_int_StorageBuffer ArrayStride 4 %void = OpTypeVoid %bool = OpTypeBool %int = OpTypeInt 32 0 diff --git a/third_party/spirv-tools/test/opt/vector_dce_test.cpp b/third_party/spirv-tools/test/opt/vector_dce_test.cpp index 9bdad375bc..b14e2256ee 100644 --- a/third_party/spirv-tools/test/opt/vector_dce_test.cpp +++ b/third_party/spirv-tools/test/opt/vector_dce_test.cpp @@ -1351,6 +1351,72 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(VectorDCETest, OutOfBoundsExtract) { + // It tests that the vector DCE pass is able to handle an extract with an + // index that is out of bounds. + const std::string text = R"( +; CHECK: [[undef:%\w+]] = OpUndef %v4float +; CHECK: OpCompositeExtract %float [[undef]] 8 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %OutColor + OpExecutionMode %main OriginUpperLeft + OpDecorate %OutColor Location 0 + %void = OpTypeVoid + %10 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_float = OpTypePointer Output %float + %OutColor = OpVariable %_ptr_Output_float Output + %null = OpConstantNull %v4float + %float_1 = OpConstant %float 1 + %main = OpFunction %void None %10 + %28 = OpLabel + %33 = OpCompositeInsert %v4float %float_1 %null 1 + %extract = OpCompositeExtract %float %33 8 + OpStore %OutColor %extract + OpReturn + OpFunctionEnd +)"; + + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + SinglePassRunAndMatch(text, false); +} + +TEST_F(VectorDCETest, OutOfBoundsShuffle) { + // It tests that the vector DCE pass is able to handle a shuffle with an + // index that is out of bounds. + const std::string text = R"( +; CHECK: [[undef:%\w+]] = OpUndef %v4float +; CHECK: OpVectorShuffle %v4float [[undef]] [[undef]] 9 10 11 12 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %OutColor + OpExecutionMode %main OriginUpperLeft + OpDecorate %OutColor Location 0 + %void = OpTypeVoid + %10 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %OutColor = OpVariable %_ptr_Output_v4float Output + %null = OpConstantNull %v4float + %float_1 = OpConstant %float 1 + %main = OpFunction %void None %10 + %28 = OpLabel + %33 = OpCompositeInsert %v4float %float_1 %null 1 + %shuffle = OpVectorShuffle %v4float %33 %33 9 10 11 12 + OpStore %OutColor %shuffle + OpReturn + OpFunctionEnd +)"; + + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + SinglePassRunAndMatch(text, false); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/text_to_binary_test.cpp b/third_party/spirv-tools/test/text_to_binary_test.cpp index 57f0a6ce0b..99d9ed6869 100644 --- a/third_party/spirv-tools/test/text_to_binary_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary_test.cpp @@ -247,12 +247,6 @@ INSTANTIATE_TEST_SUITE_P( {"0x1.804p4", 0x00004e01}, })); -TEST(CreateContext, InvalidEnvironment) { - spv_target_env env; - std::memset(&env, 99, sizeof(env)); - EXPECT_THAT(spvContextCreate(env), IsNull()); -} - TEST(CreateContext, UniversalEnvironment) { auto c = spvContextCreate(SPV_ENV_UNIVERSAL_1_0); EXPECT_THAT(c, NotNull()); diff --git a/third_party/spirv-tools/test/val/CMakeLists.txt b/third_party/spirv-tools/test/val/CMakeLists.txt index b1e12ac03c..64eba44616 100644 --- a/third_party/spirv-tools/test/val/CMakeLists.txt +++ b/third_party/spirv-tools/test/val/CMakeLists.txt @@ -23,6 +23,7 @@ set(VAL_TEST_COMMON_SRCS add_spvtools_unittest(TARGET val_abcde SRCS val_adjacency_test.cpp + val_annotation_test.cpp val_arithmetics_test.cpp val_atomics_test.cpp val_barriers_test.cpp @@ -45,6 +46,7 @@ add_spvtools_unittest(TARGET val_abcde val_extension_spv_khr_bit_instructions.cpp val_extension_spv_khr_terminate_invocation.cpp val_ext_inst_test.cpp + val_ext_inst_debug_test.cpp ${VAL_TEST_COMMON_SRCS} LIBS ${SPIRV_TOOLS_FULL_VISIBILITY} PCH_FILE pch_test_val diff --git a/third_party/spirv-tools/test/val/val_annotation_test.cpp b/third_party/spirv-tools/test/val/val_annotation_test.cpp new file mode 100644 index 0000000000..889c76caea --- /dev/null +++ b/third_party/spirv-tools/test/val/val_annotation_test.cpp @@ -0,0 +1,951 @@ +// Copyright (c) 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Validation tests for decorations + +#include +#include + +#include "gmock/gmock.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Combine; +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::Values; + +using DecorationTest = spvtest::ValidateBase; + +TEST_F(DecorationTest, WorkgroupSizeShader) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ones BuiltIn WorkgroupSize +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%int_1 = OpConstant %int 1 +%ones = OpConstantComposite %int3 %int_1 %int_1 %int_1 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(DecorationTest, WorkgroupSizeKernel) { + const std::string text = R"( +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +OpDecorate %var BuiltIn WorkgroupSize +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%ptr = OpTypePointer Input %int3 +%var = OpVariable %ptr Input +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +using MemberOnlyDecorations = spvtest::ValidateBase; + +TEST_P(MemberOnlyDecorations, MemberDecoration) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpMemberDecorate %struct 0 )" + + deco + R"( +%float = OpTypeFloat 32 +%float2 = OpTypeVector %float 2 +%float2x2 = OpTypeMatrix %float2 2 +%struct = OpTypeStruct %float2x2 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(MemberOnlyDecorations, Decoration) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %struct )" + deco + + R"( +%float = OpTypeFloat 32 +%float2 = OpTypeVector %float 2 +%float2x2 = OpTypeMatrix %float2 2 +%struct = OpTypeStruct %float2x2 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("can only be applied to structure members")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateMemberOnlyDecorations, MemberOnlyDecorations, + Values("RowMajor", "ColMajor", "MatrixStride 16" + // SPIR-V spec bug? + /*,"Offset 0"*/)); + +using NonMemberOnlyDecorations = spvtest::ValidateBase; + +TEST_P(NonMemberOnlyDecorations, MemberDecoration) { + const auto deco = GetParam(); + const auto text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpCapability InputAttachment +OpCapability Addresses +OpCapability PhysicalStorageBufferAddresses +OpCapability ShaderNonUniform +OpExtension "SPV_KHR_no_integer_wrap_decoration" +OpExtension "SPV_KHR_physical_storage_buffer" +OpExtension "SPV_GOOGLE_hlsl_functionality1" +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %struct 0 )" + + deco + R"( +%float = OpTypeFloat 32 +%float2 = OpTypeVector %float 2 +%float2x2 = OpTypeMatrix %float2 2 +%struct = OpTypeStruct %float2x2 +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("cannot be applied to structure members")); +} + +INSTANTIATE_TEST_SUITE_P( + ValidateNonMemberOnlyDecorations, NonMemberOnlyDecorations, + Values("SpecId 1", "Block", "BufferBlock", "ArrayStride 4", "GLSLShared", + "GLSLPacked", "CPacked", + // TODO: https://github.com/KhronosGroup/glslang/issues/703: + // glslang applies Restrict to structure members. + //"Restrict", + "Aliased", "Constant", "Uniform", "SaturatedConversion", "Index 0", + "Binding 0", "DescriptorSet 0", "FuncParamAttr Zext", + "FPRoundingMode RTE", "FPFastMathMode None", + "LinkageAttributes \"ext\" Import", "NoContraction", + "InputAttachmentIndex 0", "Alignment 4", "MaxByteOffset 4", + "AlignmentId %float", "MaxByteOffsetId %float", "NoSignedWrap", + "NoUnsignedWrap", "NonUniform", "RestrictPointer", "AliasedPointer", + "CounterBuffer %float")); + +using StructDecorations = spvtest::ValidateBase; + +TEST_P(StructDecorations, Struct) { + const std::string deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %struct )" + deco + + R"( +%struct = OpTypeStruct +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(StructDecorations, OtherType) { + const std::string deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %int )" + deco + R"( +%int = OpTypeInt 32 0 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type")); +} + +TEST_P(StructDecorations, Variable) { + const std::string deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var )" + deco + R"( +%int = OpTypeInt 32 0 +%ptr = OpTypePointer Private %int +%var = OpVariable %ptr Private +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type")); +} + +TEST_P(StructDecorations, FunctionParameter) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %func LinkageAttributes "import" Import +OpDecorate %param )" + deco + + R"( +%int = OpTypeInt 32 0 +%void = OpTypeVoid +%fn = OpTypeFunction %void %int +%func = OpFunction %void None %fn +%param = OpFunctionParameter %int +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type")); +} + +TEST_P(StructDecorations, Constant) { + const std::string deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %int_0 )" + deco + + R"( +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateStructDecorations, StructDecorations, + Values("Block", "BufferBlock", "GLSLShared", + "GLSLPacked", "CPacked")); + +using ArrayDecorations = spvtest::ValidateBase; + +TEST_P(ArrayDecorations, Array) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %array )" + deco + + R"( +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%array = OpTypeArray %int %int_4 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ArrayDecorations, RuntimeArray) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %array )" + deco + + R"( +%int = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %int +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ArrayDecorations, Pointer) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ptr )" + deco + R"( +%int = OpTypeInt 32 0 +%ptr = OpTypePointer Workgroup %int +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ArrayDecorations, Struct) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %struct )" + deco + + R"( +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be an array or pointer type")); +} + +TEST_P(ArrayDecorations, Variable) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var )" + deco + R"( +%int = OpTypeInt 32 0 +%ptr = OpTypePointer Private %int +%var = OpVariable %ptr Private +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be an array or pointer type")); +} + +TEST_P(ArrayDecorations, FunctionParameter) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %func LinkageAttributes "import" Import +OpDecorate %param )" + deco + + R"( +%int = OpTypeInt 32 0 +%void = OpTypeVoid +%fn = OpTypeFunction %void %int +%func = OpFunction %void None %fn +%param = OpFunctionParameter %int +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be an array or pointer type")); +} + +TEST_P(ArrayDecorations, Constant) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %null )" + deco + + R"( +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%array = OpTypeArray %int %int_4 +%null = OpConstantNull %array +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be an array or pointer type")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateArrayDecorations, ArrayDecorations, + Values("ArrayStride 4")); + +using BuiltInDecorations = spvtest::ValidateBase; + +TEST_P(BuiltInDecorations, Variable) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var BuiltIn )" + + deco + R"( +%int = OpTypeInt 32 0 +%ptr = OpTypePointer Input %int +%var = OpVariable %ptr Input +)"; + + CompileSuccessfully(text); + if (deco != "WorkgroupSize") { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be a constant for WorkgroupSize")); + } +} + +TEST_P(BuiltInDecorations, IntegerType) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %int BuiltIn )" + + deco + R"( +%int = OpTypeInt 32 0 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("BuiltIns can only target variables, structure members " + "or constants")); +} + +TEST_P(BuiltInDecorations, FunctionParameter) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %func LinkageAttributes "import" Import +OpDecorate %param BuiltIn )" + + deco + R"( +%int = OpTypeInt 32 0 +%void = OpTypeVoid +%fn = OpTypeFunction %void %int +%func = OpFunction %void None %fn +%param = OpFunctionParameter %int +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("BuiltIns can only target variables, structure members " + "or constants")); +} + +TEST_P(BuiltInDecorations, Constant) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %const BuiltIn )" + + deco + R"( +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%int_1 = OpConstant %int 1 +%const = OpConstantComposite %int3 %int_1 %int_1 %int_1 +)"; + + CompileSuccessfully(text); + if (deco == "WorkgroupSize") { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable")); + } +} + +TEST_P(BuiltInDecorations, SpecConstant) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %const BuiltIn )" + + deco + R"( +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%int_1 = OpConstant %int 1 +%const = OpSpecConstantComposite %int3 %int_1 %int_1 %int_1 +)"; + + CompileSuccessfully(text); + if (deco == "WorkgroupSize") { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable")); + } +} + +INSTANTIATE_TEST_SUITE_P(ValidateBuiltInDecorations, BuiltInDecorations, + Values("Position", "PointSize", "VertexId", + "InstanceId", "FragCoord", "FrontFacing", + "NumWorkgroups", "WorkgroupSize", + "LocalInvocationId", "GlobalInvocationId")); + +using MemoryObjectDecorations = spvtest::ValidateBase; + +TEST_P(MemoryObjectDecorations, Variable) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpCapability SampleRateShading +OpCapability TransformFeedback +OpCapability GeometryStreams +OpCapability Tessellation +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_KHR_physical_storage_buffer" +OpMemoryModel Logical GLSL450 +OpDecorate %var )" + deco + R"( +%float = OpTypeFloat 32 +%ptr = OpTypePointer Input %float +%var = OpVariable %ptr Input +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(MemoryObjectDecorations, FunctionParameterGood) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpCapability SampleRateShading +OpCapability TransformFeedback +OpCapability GeometryStreams +OpCapability Tessellation +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_KHR_physical_storage_buffer" +OpMemoryModel Logical GLSL450 +OpDecorate %func LinkageAttributes "import" Import +OpDecorate %param )" + deco + + R"( +%float = OpTypeFloat 32 +%ptr = OpTypePointer Input %float +%void = OpTypeVoid +%fn = OpTypeFunction %void %ptr +%func = OpFunction %void None %fn +%param = OpFunctionParameter %ptr +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(MemoryObjectDecorations, FunctionParameterNotAPointer) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpCapability SampleRateShading +OpCapability TransformFeedback +OpCapability GeometryStreams +OpCapability Tessellation +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_KHR_physical_storage_buffer" +OpMemoryModel Logical GLSL450 +OpDecorate %func LinkageAttributes "import" Import +OpDecorate %param )" + deco + + R"( +%float = OpTypeFloat 32 +%void = OpTypeVoid +%fn = OpTypeFunction %void %float +%func = OpFunction %void None %fn +%param = OpFunctionParameter %float +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a pointer type")); +} + +TEST_P(MemoryObjectDecorations, FloatType) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpCapability SampleRateShading +OpCapability TransformFeedback +OpCapability GeometryStreams +OpCapability Tessellation +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_KHR_physical_storage_buffer" +OpMemoryModel Logical GLSL450 +OpDecorate %float )" + deco + + R"( +%float = OpTypeFloat 32 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be a memory object declaration")); +} + +TEST_P(MemoryObjectDecorations, Constant) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpCapability SampleRateShading +OpCapability TransformFeedback +OpCapability GeometryStreams +OpCapability Tessellation +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_KHR_physical_storage_buffer" +OpMemoryModel Logical GLSL450 +OpDecorate %const )" + deco + + R"( +%float = OpTypeFloat 32 +%const = OpConstant %float 0 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be a memory object declaration")); +} + +// NonWritable and NonReadable are covered by other tests. +INSTANTIATE_TEST_SUITE_P( + ValidateMemoryObjectDecorations, MemoryObjectDecorations, + Values("NoPerspective", "Flat", "Patch", "Centroid", "Component 0", + "Sample", "Restrict", "Aliased", "Volatile", "Coherent", "Stream 0", + "XfbBuffer 1", "XfbStride 1", "AliasedPointer", "RestrictPointer")); + +using VariableDecorations = spvtest::ValidateBase; + +TEST_P(VariableDecorations, Variable) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpCapability InputAttachment +OpMemoryModel Logical GLSL450 +OpDecorate %var )" + deco + R"( +%float = OpTypeFloat 32 +%ptr = OpTypePointer Input %float +%var = OpVariable %ptr Input +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(VariableDecorations, FunctionParameter) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpCapability InputAttachment +OpMemoryModel Logical GLSL450 +OpDecorate %func LinkageAttributes "import" Import +OpDecorate %param )" + deco + + R"( +%float = OpTypeFloat 32 +%void = OpTypeVoid +%fn = OpTypeFunction %void %float +%func = OpFunction %void None %fn +%param = OpFunctionParameter %float +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable")); +} + +TEST_P(VariableDecorations, FloatType) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpCapability InputAttachment +OpMemoryModel Logical GLSL450 +OpDecorate %float )" + deco + + R"( +%float = OpTypeFloat 32 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable")); +} + +TEST_P(VariableDecorations, Constant) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Linkage +OpCapability InputAttachment +OpMemoryModel Logical GLSL450 +OpDecorate %const )" + deco + + R"( +%float = OpTypeFloat 32 +%const = OpConstant %float 0 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateVariableDecorations, VariableDecorations, + Values("Invariant", "Constant", "Location 0", + "Index 0", "Binding 0", "DescriptorSet 0")); + +using VulkanIOStorageClass = + spvtest::ValidateBase>; + +TEST_P(VulkanIOStorageClass, Invalid) { + const auto deco = std::get<0>(GetParam()); + const auto sc = std::get<1>(GetParam()); + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %var )" + deco + R"( 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%ptr = OpTypePointer )" + + sc + + R"( %float +%var = OpVariable %ptr )" + sc + + R"( +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("decoration must not be applied to this storage class")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateVulkanIOStorageClass, VulkanIOStorageClass, + Combine(Values("Location", "Component"), + Values("StorageBuffer", "Uniform", + "UniformConstant", "Workgroup", + "Private"))); + +using VulkanResourceStorageClass = + spvtest::ValidateBase>; + +TEST_P(VulkanResourceStorageClass, Invalid) { + const auto deco = std::get<0>(GetParam()); + const auto sc = std::get<1>(GetParam()); + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %var )" + deco + R"( 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%ptr = OpTypePointer )" + + sc + + R"( %float +%var = OpVariable %ptr )" + sc + + R"( +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be in the StorageBuffer, Uniform, or " + "UniformConstant storage class")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateVulkanResourceStorageClass, + VulkanResourceStorageClass, + Combine(Values("DescriptorSet", "Binding"), + Values("Private", "Input", "Output", + "Workgroup"))); + +using VulkanInterpolationStorageClass = spvtest::ValidateBase; + +TEST_P(VulkanInterpolationStorageClass, Input) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability SampleRateShading +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %var )" + deco + R"( +%void = OpTypeVoid +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%ptr = OpTypePointer Input %float +%var = OpVariable %ptr Input +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_P(VulkanInterpolationStorageClass, Output) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability SampleRateShading +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpDecorate %var )" + deco + R"( +%void = OpTypeVoid +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%ptr = OpTypePointer Output %float +%var = OpVariable %ptr Output +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_P(VulkanInterpolationStorageClass, Private) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability SampleRateShading +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %var )" + deco + R"( +%void = OpTypeVoid +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%ptr = OpTypePointer Private %float +%var = OpVariable %ptr Private +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("storage class must be Input or Output")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("[VUID-StandaloneSpirv-Flat-04670")); +} + +TEST_P(VulkanInterpolationStorageClass, Uniform) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability SampleRateShading +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %var )" + deco + R"( +OpDecorate %var Binding 0 +OpDecorate %var DescriptorSet 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%ptr = OpTypePointer Uniform %float +%var = OpVariable %ptr Uniform +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("storage class must be Input or Output")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("[VUID-StandaloneSpirv-Flat-04670")); +} + +TEST_P(VulkanInterpolationStorageClass, StorageBuffer) { + const auto deco = GetParam(); + const std::string text = R"( +OpCapability Shader +OpCapability SampleRateShading +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %var )" + deco + R"( +OpDecorate %var Binding 0 +OpDecorate %var DescriptorSet 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%ptr = OpTypePointer StorageBuffer %float +%var = OpVariable %ptr StorageBuffer +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("storage class must be Input or Output")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("[VUID-StandaloneSpirv-Flat-04670")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateVulkanInterpolationStorageClass, + VulkanInterpolationStorageClass, + Values("Flat", "NoPerspective", "Centroid", "Sample")); + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_arithmetics_test.cpp b/third_party/spirv-tools/test/val/val_arithmetics_test.cpp index b82fc97e12..856ad02c18 100644 --- a/third_party/spirv-tools/test/val/val_arithmetics_test.cpp +++ b/third_party/spirv-tools/test/val/val_arithmetics_test.cpp @@ -1309,6 +1309,57 @@ TEST_F(ValidateArithmetics, CoopMatDimFail) { HasSubstr("Cooperative matrix 'M' mismatch: CooperativeMatrixMulAddNV")); } +TEST_F(ValidateArithmetics, CoopMatComponentTypeNotScalarNumeric) { + const std::string types = R"( +%bad = OpTypeCooperativeMatrixNV %bool %subgroup %u32_8 %u32_8 +)"; + + CompileSuccessfully(GenerateCoopMatCode(types, "").c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpTypeCooperativeMatrixNV Component Type " + "'4[%bool]' is not a scalar numerical type.")); +} + +TEST_F(ValidateArithmetics, CoopMatScopeNotConstantInt) { + const std::string types = R"( +%bad = OpTypeCooperativeMatrixNV %f16 %f32_1 %u32_8 %u32_8 +)"; + + CompileSuccessfully(GenerateCoopMatCode(types, "").c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeCooperativeMatrixNV Scope '17[%float_1]' is not a " + "constant instruction with scalar integer type.")); +} + +TEST_F(ValidateArithmetics, CoopMatRowsNotConstantInt) { + const std::string types = R"( +%bad = OpTypeCooperativeMatrixNV %f16 %subgroup %f32_1 %u32_8 +)"; + + CompileSuccessfully(GenerateCoopMatCode(types, "").c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeCooperativeMatrixNV Rows '17[%float_1]' is not a " + "constant instruction with scalar integer type.")); +} + +TEST_F(ValidateArithmetics, CoopMatColumnsNotConstantInt) { + const std::string types = R"( +%bad = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %f32_1 +)"; + + CompileSuccessfully(GenerateCoopMatCode(types, "").c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeCooperativeMatrixNV Cols '17[%float_1]' is not a " + "constant instruction with scalar integer type.")); +} + TEST_F(ValidateArithmetics, IAddCarrySuccess) { const std::string body = R"( %val1 = OpIAddCarry %struct_u32_u32 %u32_0 %u32_1 diff --git a/third_party/spirv-tools/test/val/val_atomics_test.cpp b/third_party/spirv-tools/test/val/val_atomics_test.cpp index b7f6948efb..d1a030a87a 100644 --- a/third_party/spirv-tools/test/val/val_atomics_test.cpp +++ b/third_party/spirv-tools/test/val/val_atomics_test.cpp @@ -2679,6 +2679,39 @@ OpFunctionEnd "CooperativeMatrixNV capability is present")); } +TEST_F(ValidateAtomics, IIncrementBadPointerDataType) { + const std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + %uint = OpTypeInt 32 0 +%_ptr_Input_uint = OpTypePointer Input %uint + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %16 = OpTypeFunction %void +%uint_538976288 = OpConstant %uint 538976288 + %int = OpTypeInt 32 1 +%_runtimearr_int = OpTypeRuntimeArray %int + %_struct_5 = OpTypeStruct %_runtimearr_int +%_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 + %3 = OpVariable %_ptr_Input_v3uint Input + %7 = OpVariable %_ptr_Uniform__struct_5 Uniform + %8224 = OpFunction %void None %16 + %65312 = OpLabel + %25 = OpAccessChain %_ptr_Input_uint %3 %uint_538976288 + %26 = OpLoad %uint %25 + %2097184 = OpAtomicIIncrement %int %7 %uint_538976288 %26 + OpUnreachable + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicIIncrement: expected Pointer to point to a " + "value of type Result Type")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_builtins_test.cpp b/third_party/spirv-tools/test/val/val_builtins_test.cpp index 2116fff26a..dff9adfef9 100644 --- a/third_party/spirv-tools/test/val/val_builtins_test.cpp +++ b/third_party/spirv-tools/test/val/val_builtins_test.cpp @@ -767,18 +767,18 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotGLCompute, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", - "WorkgroupId"), - Values("Vertex", "Fragment", "Geometry", "TessellationControl", - "TessellationEvaluation"), - Values("Input"), Values("%u32vec3"), - Values("VUID-GlobalInvocationId-GlobalInvocationId-04236 " - "VUID-LocalInvocationId-LocalInvocationId-04281 " - "VUID-NumWorkgroups-NumWorkgroups-04296 " - "VUID-WorkgroupId-WorkgroupId-04422"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with GLCompute execution model")))); + Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", + "WorkgroupId"), + Values("Vertex", "Fragment", "Geometry", "TessellationControl", + "TessellationEvaluation"), + Values("Input"), Values("%u32vec3"), + Values("VUID-GlobalInvocationId-GlobalInvocationId-04236 " + "VUID-LocalInvocationId-LocalInvocationId-04281 " + "VUID-NumWorkgroups-NumWorkgroups-04296 " + "VUID-WorkgroupId-WorkgroupId-04422"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with GLCompute, MeshNV, or " + "TaskNV execution model")))); INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotInput, @@ -2828,9 +2828,10 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeFragment) { CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Vulkan spec allows BuiltIn WorkgroupSize to be used " - "only with GLCompute execution model")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Vulkan spec allows BuiltIn WorkgroupSize to be used " + "only with GLCompute, MeshNV, or TaskNV execution model")); EXPECT_THAT(getDiagnosticString(), HasSubstr("is referencing ID <2> (OpConstantComposite) which is " "decorated with BuiltIn WorkgroupSize in function <1> " @@ -2860,9 +2861,9 @@ OpDecorate %copy BuiltIn WorkgroupSize CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("BuiltIns can only target variables, structs or constants")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("BuiltIns can only target variables, structure " + "members or constants")); } CodeGenerator GetWorkgroupSizeNotVectorGenerator() { @@ -3481,35 +3482,6 @@ OpDecorate %gl_ViewportIndex PerPrimitiveNV 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 - OpDecorate %12 Location 0 - OpDecorate %17 Location 0 - %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")); -} - TEST_P(ValidateVulkanSubgroupBuiltIns, InMain) { const char* const built_in = std::get<0>(GetParam()); const char* const execution_model = std::get<1>(GetParam()); @@ -3711,13 +3683,13 @@ OpFunctionEnd INSTANTIATE_TEST_SUITE_P( SubgroupNumAndIdNotCompute, ValidateVulkanSubgroupBuiltIns, - Combine( - Values("SubgroupId", "NumSubgroups"), Values("Vertex"), Values("Input"), - Values("%u32"), - Values("VUID-SubgroupId-SubgroupId-04367 " - "VUID-NumSubgroups-NumSubgroups-04293"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with GLCompute execution model")))); + Combine(Values("SubgroupId", "NumSubgroups"), Values("Vertex"), + Values("Input"), Values("%u32"), + Values("VUID-SubgroupId-SubgroupId-04367 " + "VUID-NumSubgroups-NumSubgroups-04293"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with GLCompute, MeshNV, or " + "TaskNV execution model")))); INSTANTIATE_TEST_SUITE_P( SubgroupNumAndIdNotU32, ValidateVulkanSubgroupBuiltIns, @@ -3780,9 +3752,9 @@ OpDecorate %void BuiltIn Position CompileSuccessfully(text); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("BuiltIns can only target variables, structs or constants")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("BuiltIns can only target variables, structure members " + "or constants")); } TEST_F(ValidateBuiltIns, TargetIsVariable) { @@ -3800,47 +3772,6 @@ OpDecorate %wg_var BuiltIn Position EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateBuiltIns, TargetIsStruct) { - const std::string text = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -OpDecorate %struct BuiltIn Position -%struct = OpTypeStruct -)"; - - CompileSuccessfully(text); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateBuiltIns, TargetIsConstant) { - const std::string text = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -OpDecorate %int0 BuiltIn Position -%int = OpTypeInt 32 0 -%int0 = OpConstant %int 0 -)"; - - CompileSuccessfully(text); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateBuiltIns, TargetIsSpecConstant) { - const std::string text = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -OpDecorate %int0 BuiltIn Position -%int = OpTypeInt 32 0 -%int0 = OpSpecConstant %int 0 -)"; - - CompileSuccessfully(text); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - INSTANTIATE_TEST_SUITE_P( PrimitiveShadingRateOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, diff --git a/third_party/spirv-tools/test/val/val_capability_test.cpp b/third_party/spirv-tools/test/val/val_capability_test.cpp index 82f8d38196..c432c3cfaf 100644 --- a/third_party/spirv-tools/test/val/val_capability_test.cpp +++ b/third_party/spirv-tools/test/val/val_capability_test.cpp @@ -1205,8 +1205,10 @@ INSTANTIATE_TEST_SUITE_P(Decoration, ValidateCapability, Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt RelaxedPrecision\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var RelaxedPrecision\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Private %intt\n" + "%var = OpVariable %ptr Private\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + // Block applies to struct type. @@ -1224,93 +1226,125 @@ std::make_pair(std::string(kOpenCLMemoryModel) + ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt RowMajor\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpMemberDecorate %structt 0 RowMajor\n" + "%floatt = OpTypeFloat 32\n" + "%float2 = OpTypeVector %floatt 2\n" + "%mat2x2 = OpTypeMatrix %float2 2\n" + "%structt = OpTypeStruct %mat2x2\n" + std::string(kVoidFVoid), MatrixDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt ColMajor\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpMemberDecorate %structt 0 ColMajor\n" + "%floatt = OpTypeFloat 32\n" + "%float2 = OpTypeVector %floatt 2\n" + "%mat2x2 = OpTypeMatrix %float2 2\n" + "%structt = OpTypeStruct %mat2x2\n" + std::string(kVoidFVoid), MatrixDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt ArrayStride 1\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %array ArrayStride 4\n" + "%intt = OpTypeInt 32 0\n" + "%array = OpTypeRuntimeArray %intt\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt MatrixStride 1\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpMemberDecorate %structt 0 MatrixStride 8\n" + "%floatt = OpTypeFloat 32\n" + "%float2 = OpTypeVector %floatt 2\n" + "%mat2x2 = OpTypeMatrix %float2 2\n" + "%structt = OpTypeStruct %mat2x2\n" + std::string(kVoidFVoid), MatrixDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt GLSLShared\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %struct GLSLShared\n" + "%struct = OpTypeStruct\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt GLSLPacked\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %struct GLSLPacked\n" + "%struct = OpTypeStruct\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" - "OpDecorate %intt CPacked\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %struct CPacked\n" + "%struct = OpTypeStruct\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt NoPerspective\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var NoPerspective\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Flat\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Flat\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Patch\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Patch\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Centroid\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Centroid\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Sample\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Sample\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Invariant\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Invariant\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Restrict\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Restrict\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Aliased\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Aliased\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Volatile\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Volatile\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" - "OpDecorate %intt Constant\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Constant\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Coherent\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Coherent\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + // NonWritable must target something valid, such as a storage image. @@ -1324,8 +1358,12 @@ std::make_pair(std::string(kOpenCLMemoryModel) + AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt NonReadable\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var NonReadable " + "%float = OpTypeFloat 32 " + "%imstor = OpTypeImage %float 2D 0 0 0 2 Unknown " + "%ptr = OpTypePointer UniformConstant %imstor " + "%var = OpVariable %ptr UniformConstant " + + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + // Uniform must target a non-void value. @@ -1342,8 +1380,10 @@ std::make_pair(std::string(kGLSL450MemoryModel) + KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Stream 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Stream 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Output %intt\n" + "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), std::vector{"GeometryStreams"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" @@ -1360,33 +1400,44 @@ std::make_pair(std::string(kOpenCLMemoryModel) + ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Index 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Index 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Binding 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Binding 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Uniform %intt\n" + "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt DescriptorSet 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var DescriptorSet 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Uniform %intt\n" + "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Offset 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpMemberDecorate %structt 0 Offset 0\n" + "%intt = OpTypeInt 32 0\n" + "%structt = OpTypeStruct %intt\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt XfbBuffer 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var XfbBuffer 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Uniform %intt\n" + "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), std::vector{"TransformFeedback"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt XfbStride 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var XfbStride 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Uniform %intt\n" + "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), std::vector{"TransformFeedback"}), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" @@ -1410,8 +1461,10 @@ std::make_pair(std::string(kOpenCLMemoryModel) + ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt InputAttachmentIndex 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var InputAttachmentIndex 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer UniformConstant %intt\n" + "%var = OpVariable %ptr UniformConstant\n" + std::string(kVoidFVoid), std::vector{"InputAttachment"}), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" @@ -1471,264 +1524,300 @@ INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapability, Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn Position\n" + "OpDecorate %var BuiltIn Position\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), // Just mentioning PointSize, ClipDistance, or CullDistance as a BuiltIn does // not trigger the requirement for the associated capability. // See https://github.com/KhronosGroup/SPIRV-Tools/issues/365 std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn PointSize\n" + "OpDecorate %var BuiltIn PointSize\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn ClipDistance\n" + "OpDecorate %var BuiltIn ClipDistance\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn CullDistance\n" + "OpDecorate %var BuiltIn CullDistance\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn VertexId\n" + "OpDecorate %var BuiltIn VertexId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn InstanceId\n" + "OpDecorate %var BuiltIn InstanceId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn PrimitiveId\n" + "OpDecorate %var BuiltIn PrimitiveId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), GeometryTessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn InvocationId\n" + "OpDecorate %var BuiltIn InvocationId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), GeometryTessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn Layer\n" + "OpDecorate %var BuiltIn Layer\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn ViewportIndex\n" + "OpDecorate %var BuiltIn ViewportIndex\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"MultiViewport"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn TessLevelOuter\n" + "OpDecorate %var BuiltIn TessLevelOuter\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn TessLevelInner\n" + "OpDecorate %var BuiltIn TessLevelInner\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn TessCoord\n" + "OpDecorate %var BuiltIn TessCoord\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn PatchVertices\n" + "OpDecorate %var BuiltIn PatchVertices\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn FragCoord\n" + "OpDecorate %var BuiltIn FragCoord\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn PointCoord\n" + "OpDecorate %var BuiltIn PointCoord\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn FrontFacing\n" + "OpDecorate %var BuiltIn FrontFacing\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn SampleId\n" + "OpDecorate %var BuiltIn SampleId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn SamplePosition\n" + "OpDecorate %var BuiltIn SamplePosition\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn SampleMask\n" + "OpDecorate %var BuiltIn SampleMask\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn FragDepth\n" + "OpDecorate %var BuiltIn FragDepth\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn HelperInvocation\n" + "OpDecorate %var BuiltIn HelperInvocation\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn VertexIndex\n" + "OpDecorate %var BuiltIn VertexIndex\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn InstanceIndex\n" + "OpDecorate %var BuiltIn InstanceIndex\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn NumWorkgroups\n" + "OpDecorate %var BuiltIn NumWorkgroups\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn WorkgroupSize\n" + "OpDecorate %var BuiltIn WorkgroupId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn WorkgroupId\n" + "OpDecorate %var BuiltIn LocalInvocationId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn LocalInvocationId\n" + "OpDecorate %var BuiltIn GlobalInvocationId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn GlobalInvocationId\n" + "OpDecorate %var BuiltIn LocalInvocationIndex\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), - AllCapabilities()), -std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn LocalInvocationIndex\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn WorkDim\n" + "OpDecorate %var BuiltIn WorkDim\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn GlobalSize\n" + "OpDecorate %var BuiltIn GlobalSize\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn EnqueuedWorkgroupSize\n" + "OpDecorate %var BuiltIn EnqueuedWorkgroupSize\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn GlobalOffset\n" + "OpDecorate %var BuiltIn GlobalOffset\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn GlobalLinearId\n" + "OpDecorate %var BuiltIn GlobalLinearId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn SubgroupSize\n" + "OpDecorate %var BuiltIn SubgroupSize\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn SubgroupMaxSize\n" + "OpDecorate %var BuiltIn SubgroupMaxSize\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn NumSubgroups\n" + "OpDecorate %var BuiltIn NumSubgroups\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn NumEnqueuedSubgroups\n" + "OpDecorate %var BuiltIn NumEnqueuedSubgroups\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn SubgroupId\n" + "OpDecorate %var BuiltIn SubgroupId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn SubgroupLocalInvocationId\n" + "OpDecorate %var BuiltIn SubgroupLocalInvocationId\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn VertexIndex\n" + "OpDecorate %var BuiltIn VertexIndex\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %int0 BuiltIn InstanceIndex\n" + "OpDecorate %var BuiltIn InstanceIndex\n" "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()) ))); @@ -1742,11 +1831,11 @@ INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapabilityVulkan10, ValuesIn(AllSpirV10Capabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" - "OpMemberDecorate %block 0 BuiltIn PointSize\n" - "%f32 = OpTypeFloat 32\n" - "%block = OpTypeStruct %f32\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn PointSize\n" + "%float = OpTypeFloat 32\n" + "%ptr_output_float = OpTypePointer Output %float\n" + "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), // Capabilities which should succeed. AllVulkan10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + @@ -1775,22 +1864,31 @@ INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapabilityOpenGL40, ValuesIn(AllSpirV10Capabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn PointSize\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn PointSize\n" + "%float = OpTypeFloat 32\n" + "%ptr_output_float = OpTypePointer Output %float\n" + "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn ClipDistance\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn ClipDistance\n" + "%float = OpTypeFloat 32\n" + "%int = OpTypeInt 32 0\n" + "%int_1 = OpConstant %int 1\n" + "%array = OpTypeArray %float %int_1\n" + "%ptr = OpTypePointer Output %array\n" + "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn CullDistance\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn CullDistance\n" + "%float = OpTypeFloat 32\n" + "%int = OpTypeInt 32 0\n" + "%int_1 = OpConstant %int 1\n" + "%array = OpTypeArray %float %int_1\n" + "%ptr = OpTypePointer Output %array\n" + "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()) ))); @@ -1800,16 +1898,21 @@ INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan11, ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn PointSize\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn PointSize\n" + "%float = OpTypeFloat 32\n" + "%ptr_output_float = OpTypePointer Output %float\n" + "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), AllVulkan11Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn CullDistance\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn CullDistance\n" + "%float = OpTypeFloat 32\n" + "%int = OpTypeInt 32 0\n" + "%int_1 = OpConstant %int 1\n" + "%array = OpTypeArray %float %int_1\n" + "%ptr = OpTypePointer Output %array\n" + "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllVulkan11Capabilities()) ))); @@ -1819,16 +1922,21 @@ INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan12, ValuesIn(AllSpirV15Capabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn PointSize\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn PointSize\n" + "%float = OpTypeFloat 32\n" + "%ptr_output_float = OpTypePointer Output %float\n" + "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), AllVulkan12Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %int0 BuiltIn CullDistance\n" - "%intt = OpTypeInt 32 0\n" - "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + "OpEntryPoint Vertex %func \"shader\" %var\n" + + "OpDecorate %var BuiltIn CullDistance\n" + "%float = OpTypeFloat 32\n" + "%int = OpTypeInt 32 0\n" + "%int_1 = OpConstant %int 1\n" + "%array = OpTypeArray %float %int_1\n" + "%ptr = OpTypePointer Output %array\n" + "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllVulkan12Capabilities()) ))); diff --git a/third_party/spirv-tools/test/val/val_cfg_test.cpp b/third_party/spirv-tools/test/val/val_cfg_test.cpp index 6ae2ee6db9..311cfa7713 100644 --- a/third_party/spirv-tools/test/val/val_cfg_test.cpp +++ b/third_party/spirv-tools/test/val/val_cfg_test.cpp @@ -4229,6 +4229,67 @@ OpFunctionEnd ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateCFG, StructuredSelections_RegisterBothTrueAndFalse) { + // In this test, we try to make a case where the false branches + // to %20 and %60 from blocks %10 and %50 must be registered + // during the validity check for sturctured selections. + // However, an error is caught earlier in the flow, that the + // branches from %100 to %20 and %60 violate dominance. + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + + %void = OpTypeVoid + %void_fn = OpTypeFunction %void + + %bool = OpTypeBool + %cond = OpUndef %bool + + %main = OpFunction %void None %void_fn + + %1 = OpLabel + OpSelectionMerge %999 None + OpBranchConditional %cond %10 %100 + + %10 = OpLabel + OpSelectionMerge %30 None ; force registration of %30 + OpBranchConditional %cond %30 %20 ; %20 should be registered too + + %20 = OpLabel + OpBranch %30 + + %30 = OpLabel ; merge for first if + OpBranch %50 + + + %50 = OpLabel + OpSelectionMerge %70 None ; force registration of %70 + OpBranchConditional %cond %70 %60 ; %60 should be registered + + %60 = OpLabel + OpBranch %70 + + %70 = OpLabel ; merge for second if + OpBranch %999 + + %100 = OpLabel + OpBranchConditional %cond %20 %60 ; should require a merge + + %999 = OpLabel + OpReturn + + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The selection construct with the selection header " + "8[%8] does not dominate the merge block 10[%10]\n")); +} + TEST_F(ValidateCFG, UnreachableIsStaticallyReachable) { const std::string text = R"( OpCapability Shader @@ -4399,6 +4460,125 @@ OpFunctionEnd "1[%BAD], but not via a structured exit")); } +TEST_F(ValidateCFG, SwitchSelectorNotAnInt) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_1 = OpConstant %float 1 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %default None +OpSwitch %float_1 %default +%default = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Selector type must be OpTypeInt")); +} + +TEST_F(ValidateCFG, SwitchDefaultNotALabel) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %default None +OpSwitch %int_1 %int_1 +%default = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Default must be an OpLabel instruction")); +} + +TEST_F(ValidateCFG, BlockDepthRecursion) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%1 = OpLabel +OpBranch %2 +%2 = OpLabel +OpLoopMerge %3 %4 None +OpBranchConditional %undef %3 %4 +%4 = OpLabel +OpBranch %2 +%3 = OpLabel +OpBranch %5 +%5 = OpLabel +OpSelectionMerge %2 None +OpBranchConditional %undef %6 %7 +%6 = OpLabel +OpReturn +%7 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); +} + +TEST_F(ValidateCFG, BadStructuredExitBackwardsMerge) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%1 = OpLabel +OpBranch %2 +%2 = OpLabel +OpLoopMerge %4 %5 None +OpBranchConditional %undef %4 %6 +%6 = OpLabel +OpSelectionMerge %7 None +OpBranchConditional %undef %8 %9 +%7 = OpLabel +OpReturn +%8 = OpLabel +OpBranch %5 +%9 = OpLabel +OpSelectionMerge %6 None +OpBranchConditional %undef %5 %5 +%5 = OpLabel +OpBranch %2 +%4 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_composites_test.cpp b/third_party/spirv-tools/test/val/val_composites_test.cpp index bf7caa9fae..507ee88945 100644 --- a/third_party/spirv-tools/test/val/val_composites_test.cpp +++ b/third_party/spirv-tools/test/val/val_composites_test.cpp @@ -86,10 +86,10 @@ OpCapability Float64 %f32mat23_121212 = OpConstantComposite %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12 %f32vec2arr3 = OpTypeArray %f32vec2 %u32_3 -%f32vec2rarr = OpTypeRuntimeArray %f32vec2 +%f32vec2arr2 = OpTypeArray %f32vec2 %u32_2 %f32u32struct = OpTypeStruct %f32 %u32 -%big_struct = OpTypeStruct %f32 %f32vec4 %f32mat23 %f32vec2arr3 %f32vec2rarr %f32u32struct +%big_struct = OpTypeStruct %f32 %f32vec4 %f32mat23 %f32vec2arr3 %f32vec2arr2 %f32u32struct %ptr_big_struct = OpTypePointer Uniform %big_struct %var_big_struct = OpVariable %ptr_big_struct Uniform @@ -150,7 +150,6 @@ OpMemoryModel Logical GLSL450 ; uniform blockName { ; S s; ; bool cond; -; RunTimeArray arr; ; } %f32arr = OpTypeRuntimeArray %float @@ -161,7 +160,7 @@ OpMemoryModel Logical GLSL450 %_ptr_Function_vec4 = OpTypePointer Function %v4float %_ptr_Uniform_vec4 = OpTypePointer Uniform %v4float %struct_s = OpTypeStruct %int %array5_vec4 %int %array5_mat4x3 -%struct_blockName = OpTypeStruct %struct_s %int %f32arr +%struct_blockName = OpTypeStruct %struct_s %int %_ptr_Uniform_blockName = OpTypePointer Uniform %struct_blockName %_ptr_Uniform_struct_s = OpTypePointer Uniform %struct_s %_ptr_Uniform_array5_mat4x3 = OpTypePointer Uniform %array5_mat4x3 @@ -644,8 +643,8 @@ TEST_F(ValidateComposites, CompositeExtractSuccess) { %val12 = OpCompositeExtract %f32 %struct 2 2 1 %val13 = OpCompositeExtract %f32vec2 %struct 3 2 %val14 = OpCompositeExtract %f32 %struct 3 2 1 -%val15 = OpCompositeExtract %f32vec2 %struct 4 100 -%val16 = OpCompositeExtract %f32 %struct 4 1000 1 +%val15 = OpCompositeExtract %f32vec2 %struct 4 1 +%val16 = OpCompositeExtract %f32 %struct 4 0 1 %val17 = OpCompositeExtract %f32 %struct 5 0 %val18 = OpCompositeExtract %u32 %struct 5 1 )"; @@ -868,8 +867,8 @@ TEST_F(ValidateComposites, CompositeInsertSuccess) { %val12 = OpCompositeInsert %big_struct %f32_3 %struct 2 2 1 %val13 = OpCompositeInsert %big_struct %f32vec2_01 %struct 3 2 %val14 = OpCompositeInsert %big_struct %f32_3 %struct 3 2 1 -%val15 = OpCompositeInsert %big_struct %f32vec2_01 %struct 4 100 -%val16 = OpCompositeInsert %big_struct %f32_3 %struct 4 1000 1 +%val15 = OpCompositeInsert %big_struct %f32vec2_01 %struct 4 1 +%val16 = OpCompositeInsert %big_struct %f32_3 %struct 4 0 1 %val17 = OpCompositeInsert %big_struct %f32_3 %struct 5 0 %val18 = OpCompositeInsert %big_struct %u32_3 %struct 5 1 )"; @@ -1382,8 +1381,8 @@ TEST_F(ValidateComposites, CompositeExtractStructIndexOutOfBoundBad) { EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Index is out of bounds, can not find index 3 in the " - "structure '25'. This structure has 3 members. " - "Largest valid index is 2.")); + "structure '25'. This structure has 2 members. " + "Largest valid index is 1.")); } // Invalid. Index into a struct is larger than the number of struct members. @@ -1403,8 +1402,8 @@ TEST_F(ValidateComposites, CompositeInsertStructIndexOutOfBoundBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr("Index is out of bounds, can not find index 3 in the structure " - " '25'. This structure has 3 members. Largest valid index " - "is 2.")); + " '25'. This structure has 2 members. Largest valid index " + "is 1.")); } // #1403: Ensure that the default spec constant value is not used to check the diff --git a/third_party/spirv-tools/test/val/val_decoration_test.cpp b/third_party/spirv-tools/test/val/val_decoration_test.cpp index 096fd172dd..f2953edcc4 100644 --- a/third_party/spirv-tools/test/val/val_decoration_test.cpp +++ b/third_party/spirv-tools/test/val/val_decoration_test.cpp @@ -687,8 +687,7 @@ TEST_F(ValidateDecorations, BlockDecoratingArrayBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Block decoration on a non-struct type")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type")); } TEST_F(ValidateDecorations, BlockDecoratingIntBad) { @@ -713,8 +712,7 @@ TEST_F(ValidateDecorations, BlockDecoratingIntBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Block decoration on a non-struct type")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type")); } TEST_F(ValidateDecorations, BlockMissingOffsetBad) { @@ -6129,9 +6127,7 @@ TEST_F(ValidateDecorations, NonWritableLabelTargetBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration must be a " - "memory object declaration (a variable or a function " - "parameter)\n %label = OpLabel")); + HasSubstr("must be a memory object declaration")); } TEST_F(ValidateDecorations, NonWritableTypeTargetBad) { @@ -6140,9 +6136,7 @@ TEST_F(ValidateDecorations, NonWritableTypeTargetBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration must be a " - "memory object declaration (a variable or a function " - "parameter)\n %void = OpTypeVoid")); + HasSubstr("must be a memory object declaration")); } TEST_F(ValidateDecorations, NonWritableValueTargetBad) { @@ -6151,9 +6145,7 @@ TEST_F(ValidateDecorations, NonWritableValueTargetBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration must be a " - "memory object declaration (a variable or a function " - "parameter)\n %float_0 = OpConstant %float 0")); + HasSubstr("must be a memory object declaration")); } TEST_F(ValidateDecorations, NonWritableValueParamBad) { @@ -6161,10 +6153,7 @@ TEST_F(ValidateDecorations, NonWritableValueParamBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %param_f = OpFunctionParameter %float")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a pointer type")); } TEST_F(ValidateDecorations, NonWritablePointerParamButWrongTypeBad) { @@ -6467,8 +6456,7 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of Component decoration must be " - "a memory object declaration")); + HasSubstr("must be a memory object declaration")); } TEST_F(ValidateDecorations, ComponentDecorationBadStorageClass) { @@ -6767,8 +6755,8 @@ TEST_F(ValidateDecorations, ComponentDecorationFunctionParameter) { )"; CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); - EXPECT_THAT(getDiagnosticString(), Eq("")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a pointer type")); } TEST_F(ValidateDecorations, VulkanStorageBufferBlock) { @@ -7164,9 +7152,7 @@ OpDecorate %struct Location 0 CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Location decoration can only be applied to a variable " - "or member of a structure type")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable")); } TEST_F(ValidateDecorations, LocationFloatBad) { @@ -7180,9 +7166,7 @@ OpDecorate %float Location 0 CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Location decoration can only be applied to a variable " - "or member of a structure type")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable")); } TEST_F(ValidateDecorations, WorkgroupSingleBlockVariable) { @@ -7571,9 +7555,7 @@ TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableNotAStruct) { CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Block decoration on a non-struct type")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type")); } TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableMissingLayout) { @@ -7648,6 +7630,213 @@ TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableBadLayout) { "member 0 at offset 1 is not aligned to 4")); } +TEST_F(ValidateDecorations, BadMatrixStrideUniform) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 MatrixStride 3 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float4 = OpTypeVector %float 4 +%matrix4x4 = OpTypeMatrix %float4 4 +%block = OpTypeStruct %matrix4x4 +%block_ptr = OpTypePointer Uniform %block +%var = OpVariable %block_ptr Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Structure id 2 decorated as Block for variable in Uniform storage " + "class must follow standard uniform buffer layout rules: member 0 is " + "a matrix with stride 3 not satisfying alignment to 16")); +} + +TEST_F(ValidateDecorations, BadMatrixStrideStorageBuffer) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 MatrixStride 3 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float4 = OpTypeVector %float 4 +%matrix4x4 = OpTypeMatrix %float4 4 +%block = OpTypeStruct %matrix4x4 +%block_ptr = OpTypePointer StorageBuffer %block +%var = OpVariable %block_ptr StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Structure id 2 decorated as Block for variable in StorageBuffer " + "storage class must follow standard storage buffer layout rules: " + "member 0 is a matrix with stride 3 not satisfying alignment to 16")); +} + +TEST_F(ValidateDecorations, BadMatrixStridePushConstant) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 MatrixStride 3 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float4 = OpTypeVector %float 4 +%matrix4x4 = OpTypeMatrix %float4 4 +%block = OpTypeStruct %matrix4x4 +%block_ptr = OpTypePointer PushConstant %block +%var = OpVariable %block_ptr PushConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Structure id 2 decorated as Block for variable in PushConstant " + "storage class must follow standard storage buffer layout rules: " + "member 0 is a matrix with stride 3 not satisfying alignment to 16")); +} + +TEST_F(ValidateDecorations, BadMatrixStrideStorageBufferScalarLayout) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 MatrixStride 3 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float4 = OpTypeVector %float 4 +%matrix4x4 = OpTypeMatrix %float4 4 +%block = OpTypeStruct %matrix4x4 +%block_ptr = OpTypePointer StorageBuffer %block +%var = OpVariable %block_ptr StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + options_->scalar_block_layout = true; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Structure id 2 decorated as Block for variable in StorageBuffer " + "storage class must follow scalar storage buffer layout rules: " + "member 0 is a matrix with stride 3 not satisfying alignment to 4")); +} + +TEST_F(ValidateDecorations, MissingOffsetStructNestedInArray) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %array ArrayStride 4 +OpDecorate %outer Block +OpMemberDecorate %outer 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%inner = OpTypeStruct %int +%array = OpTypeArray %inner %int_4 +%outer = OpTypeStruct %array +%ptr_ssbo_outer = OpTypePointer StorageBuffer %outer +%var = OpVariable %ptr_ssbo_outer StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 3 decorated as Block must be explicitly " + "laid out with Offset decorations")); +} + +TEST_F(ValidateDecorations, AllOnesOffset) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %outer Block +OpMemberDecorate %outer 0 Offset 0 +OpMemberDecorate %struct 0 Offset 4294967295 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%outer = OpTypeStruct %struct +%ptr = OpTypePointer Uniform %outer +%var = OpVariable %ptr Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("decorated as Block must be explicitly laid out with " + "Offset decorations")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_derivatives_test.cpp b/third_party/spirv-tools/test/val/val_derivatives_test.cpp index 606abb93dd..0a8466107c 100644 --- a/third_party/spirv-tools/test/val/val_derivatives_test.cpp +++ b/third_party/spirv-tools/test/val/val_derivatives_test.cpp @@ -160,6 +160,31 @@ TEST_F(ValidateDerivatives, OpDPdxWrongExecutionModel) { "execution model: DPdx")); } +TEST_F(ValidateDerivatives, NoExecutionModeGLCompute) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float4 = OpTypeVector %float 4 +%undef = OpUndef %float4 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%derivative = OpDPdy %float4 %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Derivative instructions require " + "DerivativeGroupQuadsNV or DerivativeGroupLinearNV " + "execution mode for GLCompute execution model")); +} + using ValidateHalfDerivatives = spvtest::ValidateBase; TEST_P(ValidateHalfDerivatives, ScalarFailure) { diff --git a/third_party/spirv-tools/test/val/val_ext_inst_debug_test.cpp b/third_party/spirv-tools/test/val/val_ext_inst_debug_test.cpp new file mode 100644 index 0000000000..307a800959 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_ext_inst_debug_test.cpp @@ -0,0 +1,5313 @@ +// 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 validation rules of GLSL.450.std and OpenCL.std extended instructions. +// Doesn't test OpenCL.std vector size 2, 3, 4, 8 or 16 rules (not supported +// by standard SPIR-V). + +#include +#include +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::Not; + +using ValidateOldDebugInfo = spvtest::ValidateBase; +using ValidateOpenCL100DebugInfo = spvtest::ValidateBase; +using ValidateXDebugInfo = spvtest::ValidateBase; +using ValidateLocalDebugInfoOutOfFunction = spvtest::ValidateBase; +using ValidateOpenCL100DebugInfoDebugTypedef = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugTypedef = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugTypeEnum = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugTypeEnum = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugTypeComposite = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugTypeComposite = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugTypeMember = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugTypeMember = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugTypeInheritance = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugFunction = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugFunction = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugFunctionDeclaration = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugFunctionDeclaration = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugLexicalBlock = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugLexicalBlock = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugLocalVariable = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugLocalVariable = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugGlobalVariable = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugGlobalVariable = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugDeclare = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugDeclare = + spvtest::ValidateBase>; +using ValidateOpenCL100DebugInfoDebugValue = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfoDebugValue = + spvtest::ValidateBase>; +using ValidateVulkan100DebugInfo = spvtest::ValidateBase; + +std::string GenerateShaderCodeForDebugInfo( + const std::string& op_string_instructions, + const std::string& op_const_instructions, + const std::string& debug_instructions_before_main, const std::string& body, + const std::string& capabilities_and_extensions = "", + const std::string& execution_model = "Fragment") { + std::ostringstream ss; + ss << R"( +OpCapability Shader +OpCapability Float16 +OpCapability Float64 +OpCapability Int16 +OpCapability Int64 +)"; + + ss << capabilities_and_extensions; + ss << "%extinst = OpExtInstImport \"GLSL.std.450\"\n"; + ss << "OpMemoryModel Logical GLSL450\n"; + ss << "OpEntryPoint " << execution_model << " %main \"main\"" + << " %f32_output" + << " %f32vec2_output" + << " %u32_output" + << " %u32vec2_output" + << " %u64_output" + << " %f32_input" + << " %f32vec2_input" + << " %u32_input" + << " %u32vec2_input" + << " %u64_input" + << "\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } + + ss << op_string_instructions; + + ss << R"( +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%f64 = OpTypeFloat 64 +%u32 = OpTypeInt 32 0 +%s32 = OpTypeInt 32 1 +%u64 = OpTypeInt 64 0 +%s64 = OpTypeInt 64 1 +%u16 = OpTypeInt 16 0 +%s16 = OpTypeInt 16 1 +%f32vec2 = OpTypeVector %f32 2 +%f32vec3 = OpTypeVector %f32 3 +%f32vec4 = OpTypeVector %f32 4 +%f64vec2 = OpTypeVector %f64 2 +%f64vec3 = OpTypeVector %f64 3 +%f64vec4 = OpTypeVector %f64 4 +%u32vec2 = OpTypeVector %u32 2 +%u32vec3 = OpTypeVector %u32 3 +%s32vec2 = OpTypeVector %s32 2 +%u32vec4 = OpTypeVector %u32 4 +%s32vec4 = OpTypeVector %s32 4 +%u64vec2 = OpTypeVector %u64 2 +%s64vec2 = OpTypeVector %s64 2 +%f64mat22 = OpTypeMatrix %f64vec2 2 +%f32mat22 = OpTypeMatrix %f32vec2 2 +%f32mat23 = OpTypeMatrix %f32vec2 3 +%f32mat32 = OpTypeMatrix %f32vec3 2 +%f32mat33 = OpTypeMatrix %f32vec3 3 + +%f32_0 = OpConstant %f32 0 +%f32_1 = OpConstant %f32 1 +%f32_2 = OpConstant %f32 2 +%f32_3 = OpConstant %f32 3 +%f32_4 = OpConstant %f32 4 +%f32_h = OpConstant %f32 0.5 +%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 +%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 +%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 +%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 +%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 +%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 + +%f64_0 = OpConstant %f64 0 +%f64_1 = OpConstant %f64 1 +%f64_2 = OpConstant %f64 2 +%f64_3 = OpConstant %f64 3 +%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1 +%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2 +%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3 + +%f16_0 = OpConstant %f16 0 +%f16_1 = OpConstant %f16 1 +%f16_h = OpConstant %f16 0.5 + +%u32_0 = OpConstant %u32 0 +%u32_1 = OpConstant %u32 1 +%u32_2 = OpConstant %u32 2 +%u32_3 = OpConstant %u32 3 + +%s32_0 = OpConstant %s32 0 +%s32_1 = OpConstant %s32 1 +%s32_2 = OpConstant %s32 2 +%s32_3 = OpConstant %s32 3 + +%u64_0 = OpConstant %u64 0 +%u64_1 = OpConstant %u64 1 +%u64_2 = OpConstant %u64 2 +%u64_3 = OpConstant %u64 3 + +%s64_0 = OpConstant %s64 0 +%s64_1 = OpConstant %s64 1 +%s64_2 = OpConstant %s64 2 +%s64_3 = OpConstant %s64 3 +)"; + + ss << op_const_instructions; + + ss << R"( +%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1 +%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 + +%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2 +%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 + +%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3 +%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 + +%s64vec2_01 = OpConstantComposite %s64vec2 %s64_0 %s64_1 +%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1 + +%f32mat22_1212 = OpConstantComposite %f32mat22 %f32vec2_12 %f32vec2_12 +%f32mat23_121212 = OpConstantComposite %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12 + +%f32_ptr_output = OpTypePointer Output %f32 +%f32vec2_ptr_output = OpTypePointer Output %f32vec2 + +%u32_ptr_output = OpTypePointer Output %u32 +%u32vec2_ptr_output = OpTypePointer Output %u32vec2 + +%u64_ptr_output = OpTypePointer Output %u64 + +%f32_output = OpVariable %f32_ptr_output Output +%f32vec2_output = OpVariable %f32vec2_ptr_output Output + +%u32_output = OpVariable %u32_ptr_output Output +%u32vec2_output = OpVariable %u32vec2_ptr_output Output + +%u64_output = OpVariable %u64_ptr_output Output + +%f32_ptr_input = OpTypePointer Input %f32 +%f32vec2_ptr_input = OpTypePointer Input %f32vec2 + +%u32_ptr_input = OpTypePointer Input %u32 +%u32vec2_ptr_input = OpTypePointer Input %u32vec2 + +%u64_ptr_input = OpTypePointer Input %u64 + +%f32_ptr_function = OpTypePointer Function %f32 + +%f32_input = OpVariable %f32_ptr_input Input +%f32vec2_input = OpVariable %f32vec2_ptr_input Input + +%u32_input = OpVariable %u32_ptr_input Input +%u32vec2_input = OpVariable %u32vec2_ptr_input Input + +%u64_input = OpVariable %u64_ptr_input Input + +%u32_ptr_function = OpTypePointer Function %u32 + +%struct_f16_u16 = OpTypeStruct %f16 %u16 +%struct_f32_f32 = OpTypeStruct %f32 %f32 +%struct_f32_f32_f32 = OpTypeStruct %f32 %f32 %f32 +%struct_f32_u32 = OpTypeStruct %f32 %u32 +%struct_f32_u32_f32 = OpTypeStruct %f32 %u32 %f32 +%struct_u32_f32 = OpTypeStruct %u32 %f32 +%struct_u32_u32 = OpTypeStruct %u32 %u32 +%struct_f32_f64 = OpTypeStruct %f32 %f64 +%struct_f32vec2_f32vec2 = OpTypeStruct %f32vec2 %f32vec2 +%struct_f32vec2_u32vec2 = OpTypeStruct %f32vec2 %u32vec2 +)"; + + ss << debug_instructions_before_main; + + ss << R"( +%main = OpFunction %void None %func +%main_entry = OpLabel +)"; + + ss << body; + + ss << R"( +OpReturn +OpFunctionEnd)"; + + return ss.str(); +} + +TEST_F(ValidateOldDebugInfo, UseDebugInstructionOutOfFunction) { + const std::string src = R"( +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%cu = OpExtInst %void %DbgExt DebugCompilationUnit %code 1 1 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "DebugInfo" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, UseDebugInstructionOutOfFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugSourceInFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", "", dbg_inst, + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Debug info extension instructions other than DebugScope, " + "DebugNoScope, DebugDeclare, DebugValue must appear between " + "section 9 (types, constants, global variables) and section 10 " + "(function declarations)")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugSourceInFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", "", dbg_inst, + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Debug info extension instructions other than DebugScope, " + "DebugNoScope, DebugDeclare, DebugValue must appear between " + "section 9 (types, constants, global variables) and section 10 " + "(function declarations)")); +} + +TEST_P(ValidateLocalDebugInfoOutOfFunction, OpenCLDebugInfo100DebugScope) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%int_name = OpString "int" +%foo_name = OpString "foo" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %u32_0 Signed +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %int_info %dbg_src 1 1 %main_info FlagIsLocal +%expr = OpExtInst %void %DbgExt DebugExpression +)"; + + const std::string body = R"( +%foo = OpVariable %u32_ptr_function Function +%foo_val = OpLoad %u32 %foo +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header + GetParam(), body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("DebugScope, DebugNoScope, DebugDeclare, DebugValue " + "of debug info extension must appear in a function " + "body")); +} + +TEST_P(ValidateLocalDebugInfoOutOfFunction, VulkanDebugInfo100DebugScope) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%int_name = OpString "int" +%foo_name = OpString "foo" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %u32_0 %u32_1 %u32_0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_1 %u32_1 %comp_unit %main_linkage_name %u32_3 %u32_1 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %int_info %dbg_src %u32_1 %u32_1 %main_info %u32_4 +%expr = OpExtInst %void %DbgExt DebugExpression +)"; + + const std::string body = R"( +%foo = OpVariable %u32_ptr_function Function +%main_def = OpExtInst %void %DbgExt DebugFunctionDefinition %main_info %main +%foo_val = OpLoad %u32 %foo +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header + GetParam(), body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("DebugScope, DebugNoScope, DebugDeclare, DebugValue " + "of debug info extension must appear in a function " + "body")); +} + +INSTANTIATE_TEST_SUITE_P( + AllLocalDebugInfo, ValidateLocalDebugInfoOutOfFunction, + ::testing::ValuesIn(std::vector{ + "%main_scope = OpExtInst %void %DbgExt DebugScope %main_info", + "%no_scope = OpExtInst %void %DbgExt DebugNoScope", + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionForwardReference) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionMissingOpFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string dbg_inst_header = R"( +%dbgNone = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %dbgNone +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugScopeBeforeOpVariableInFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info +%foo = OpVariable %f32_ptr_function Function +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeSizeDebugInfoNone) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%ty_name = OpString "struct VS_OUTPUT" +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name Class %dbg_src 1 1 %comp_unit %ty_name %dbg_none FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst_header, + "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeForwardReference) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; + float4 color : COLOR; +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_color_name = OpString "color : COLOR" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic +%VS_OUTPUT_color_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_color_name %v4float_info %dbg_src 3 3 %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeMissingReference) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; + float4 color : COLOR; +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_color_name = OpString "color : COLOR" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("forward referenced IDs have not been defined")); +} + +TEST_P(ValidateXDebugInfo, DebugSourceWrongResultType) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %bool %DbgExt DebugSource %src %code +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + GetParam(), "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected result type must be a result id of " + "OpTypeVoid")); +} + +TEST_P(ValidateXDebugInfo, DebugSourceFailFile) { + const std::string src = R"( +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %DbgExt %code +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + GetParam(), "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand File must be a result id of " + "OpString")); +} + +TEST_P(ValidateXDebugInfo, DebugSourceFailSource) { + const std::string src = R"( +%src = OpString "simple.hlsl" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %DbgExt +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + GetParam(), "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Text must be a result id of " + "OpString")); +} + +TEST_P(ValidateXDebugInfo, DebugSourceNoText) { + const std::string src = R"( +%src = OpString "simple.hlsl" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + GetParam(), "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +INSTANTIATE_TEST_SUITE_P(OpenCLAndVkDebugInfo100, ValidateXDebugInfo, + ::testing::ValuesIn(std::vector{ + R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)", + R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)", + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugCompilationUnit) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugCompilationUnitFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %src HLSL +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Source must be a result id of " + "DebugSource")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugCompilationUnitFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %src %u32_5 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, dbg_inst, + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Source must be a result id of " + "DebugSource")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeBasicFailName) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %int_32 %int_32 Float +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Name must be a result id of " + "OpString")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeBasicFailName) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %u32_32 %u32_32 %u32_3 %u32_0 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Name must be a result id of " + "OpString")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeBasicFailSize) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %float_name Float +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Size must be a result id of " + "OpConstant")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeBasicFailSize) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %float_name %u32_3 %u32_0 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Size must be a result id of " + "OpConstant")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypePointer) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%pfloat_info = OpExtInst %void %DbgExt DebugTypePointer %float_info Function FlagIsLocal +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypePointerFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%pfloat_info = OpExtInst %void %DbgExt DebugTypePointer %dbg_src Function FlagIsLocal +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type must be a result id of " + "DebugTypeBasic")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeQualifier) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%cfloat_info = OpExtInst %void %DbgExt DebugTypeQualifier %float_info ConstType +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeQualifierFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%cfloat_info = OpExtInst %void %DbgExt DebugTypeQualifier %comp_unit ConstType +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type must be a result id of " + "DebugTypeBasic")); +} +TEST_F(ValidateVulkan100DebugInfo, DebugTypeQualifier) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%cfloat_info = OpExtInst %void %DbgExt DebugTypeQualifier %float_info %u32_0 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeQualifierFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%cfloat_info = OpExtInst %void %DbgExt DebugTypeQualifier %comp_unit %u32_0 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type must be a result id of " + "DebugTypeBasic")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArray) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %int_32 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayWithVariableSize) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%int_name = OpString "int" +%main_name = OpString "main" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%uint_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %int_32 Unsigned +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %uint_info %dbg_src 1 1 %main_info FlagIsLocal +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %foo_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailBaseType) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %comp_unit %int_32 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type is not a valid debug " + "type")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailComponentCount) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %float_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailComponentCountFloat) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %f32_4 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailComponentCountZero) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %u32_0 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailVariableSizeTypeFloat) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%main_name = OpString "main" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 1 %main_info FlagIsLocal +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %foo_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeArray) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %u32_32 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayWithVariableSize) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%uint_name = OpString "uint" +%main_name = OpString "main" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_6 = OpConstant %u32 6 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%uint_info = OpExtInst %void %DbgExt DebugTypeBasic %uint_name %u32_32 %u32_6 %u32_0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_1 %u32_1 %comp_unit %main_name %u32_3 %u32_1 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %uint_info %dbg_src %u32_1 %u32_1 %main_info %u32_4 +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %foo_info +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayFailBaseType) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %comp_unit %u32_32 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type is not a valid debug " + "type")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayFailComponentCount) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %float_info +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayFailComponentCountFloat) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %f32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayFailComponentCountZero) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %u32_0 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayFailVariableSizeTypeFloat) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%main_name = OpString "main" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_6 = OpConstant %u32 6 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_1 %u32_1 %comp_unit %main_name %u32_3 %u32_1 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src %u32_1 %u32_1 %main_info %u32_4 +%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %foo_info +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be OpConstant with a 32- or " + "64-bits integer scalar type or DebugGlobalVariable or " + "DebugLocalVariable with a 32- or 64-bits unsigned " + "integer scalar type")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVector) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVectorFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %dbg_src 4 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type must be a result id of " + "DebugTypeBasic")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVectorFailComponentZero) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %dbg_src 0 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type must be a result id of " + "DebugTypeBasic")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVectorFailComponentFive) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %dbg_src 5 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type must be a result id of " + "DebugTypeBasic")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeVector) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeVectorFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %dbg_src %u32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Base Type must be a result id of " + "DebugTypeBasic")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeVectorFailComponentZero) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_0 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be positive " + "integer less than or equal to 4")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeVectorFailComponentFive) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_5 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component Count must be positive " + "integer less than or equal to 4")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypedef) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo_info = OpExtInst %void %DbgExt DebugTypedef %foo_name %float_info %dbg_src 1 1 %comp_unit +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugTypedef, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo_info = OpExtInst %void %DbgExt DebugTypedef )"; + ss << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second + + " must be a result id of ")); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypedef, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%dbg_src %float_info %dbg_src 1 1 %comp_unit)", + "Name"), + std::make_pair(R"(%foo_name %dbg_src %dbg_src 1 1 %comp_unit)", + "Base Type"), + std::make_pair(R"(%foo_name %float_info %comp_unit 1 1 %comp_unit)", + "Source"), + std::make_pair(R"(%foo_name %float_info %dbg_src 1 1 %dbg_src)", + "Parent"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugTypedef) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo_info = OpExtInst %void %DbgExt DebugTypedef %foo_name %float_info %dbg_src %u32_1 %u32_1 %comp_unit +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugTypedef, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo_info = OpExtInst %void %DbgExt DebugTypedef )"; + ss << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second + + " must be a result id of ")); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugTypedef, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%dbg_src %float_info %dbg_src %u32_1 %u32_1 %comp_unit)", + "Name"), + std::make_pair( + R"(%foo_name %dbg_src %dbg_src %u32_1 %u32_1 %comp_unit)", + "Base Type"), + std::make_pair( + R"(%foo_name %float_info %comp_unit %u32_1 %u32_1 %comp_unit)", + "Source"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_1 %u32_1 %dbg_src)", + "Parent"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%main_type_info1 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_type_info2 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %float_info +%main_type_info3 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %float_info %float_info +%main_type_info4 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void %float_info %float_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeFunctionFailReturn) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %dbg_src %float_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("expected operand Return Type is not a valid debug type")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeFunctionFailParam) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%float_name = OpString "float" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %float_info %void +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("expected operand Parameter Types is not a valid debug type")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeFunctionAndParams) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%main_type_info1 = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_type_info2 = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %float_info +%main_type_info3 = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %float_info %float_info +%main_type_info4 = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void %float_info %float_info +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeFunctionFailReturn) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %dbg_src %float_info +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("expected operand Return Type is not a valid debug type")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeFunctionFailParam) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%float_name = OpString "float" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %float_info %void +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("expected operand Parameter Types is not a valid debug type")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeEnum) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%none = OpExtInst %void %DbgExt DebugInfoNone +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo_info1 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name %u32_1 %foo_name +%foo_info2 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %none %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name %u32_1 %foo_name +%foo_info3 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %none %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugTypeEnum, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo_info = OpExtInst %void %DbgExt DebugTypeEnum )"; + ss << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeEnum, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%dbg_src %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name)", + "Name"), + std::make_pair( + R"(%foo_name %dbg_src %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name)", + "Underlying Types"), + std::make_pair( + R"(%foo_name %float_info %comp_unit 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name)", + "Source"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 1 1 %dbg_src %int_32 FlagIsPublic %u32_0 %foo_name)", + "Parent"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %void FlagIsPublic %u32_0 %foo_name)", + "Size"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %u32_0 FlagIsPublic %u32_0 %foo_name)", + "Size"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %foo_name %foo_name)", + "Value"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %u32_1)", + "Name"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeEnum) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%none = OpExtInst %void %DbgExt DebugInfoNone +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo_info1 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %float_info %dbg_src %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 %u32_0 %foo_name %u32_1 %foo_name +%foo_info2 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %none %dbg_src %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 %u32_0 %foo_name %u32_1 %foo_name +%foo_info3 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %none %dbg_src %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugTypeEnum, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo_info = OpExtInst %void %DbgExt DebugTypeEnum )"; + ss << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugTypeEnum, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%dbg_src %float_info %dbg_src %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 %u32_0 %foo_name)", + "Name"), + std::make_pair( + R"(%foo_name %dbg_src %dbg_src %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 %u32_0 %foo_name)", + "Underlying Types"), + std::make_pair( + R"(%foo_name %float_info %comp_unit %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 %u32_0 %foo_name)", + "Source"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_1 %u32_1 %dbg_src %u32_32 %u32_3 %u32_0 %foo_name)", + "Parent"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_1 %u32_1 %comp_unit %void %u32_3 %u32_0 %foo_name)", + "Size"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_1 %u32_1 %comp_unit %u32_0 %u32_3 %u32_0 %foo_name)", + "Size"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 %foo_name %foo_name)", + "Value"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_1 %u32_1 %comp_unit %u32_32 %u32_3 %u32_0 %u32_1)", + "Name"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeFunctionAndInheritance) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +struct foo : VS_OUTPUT { +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%foo_name = OpString "foo" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main +%foo_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Structure %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic +%child = OpExtInst %void %DbgExt DebugTypeInheritance %foo_info %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugTypeComposite, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +struct foo : VS_OUTPUT { +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%foo_name = OpString "foo" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite )"; + ss << param.first; + ss << R"( +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main +%foo_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Structure %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic +%child = OpExtInst %void %DbgExt DebugTypeInheritance %foo_info %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second + " must be ")); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeComposite, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%dbg_src Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", + "Name"), + std::make_pair( + R"(%VS_OUTPUT_name Structure %comp_unit 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", + "Source"), + std::make_pair( + R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %dbg_src %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", + "Parent"), + std::make_pair( + R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %int_128 %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", + "Linkage Name"), + std::make_pair( + R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %dbg_src FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", + "Size"), + std::make_pair( + R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %dbg_src %main_info %child)", + "Members"), + std::make_pair( + R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %dbg_src %child)", + "Members"), + std::make_pair( + R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %dbg_src)", + "Members"), + })); + +TEST_P(ValidateOpenCL100DebugInfoDebugTypeMember, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float pos : SV_POSITION; +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_32 FlagIsPublic %VS_OUTPUT_pos_info +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember )"; + ss << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + if (!param.second.empty()) { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second + + " must be a result id of ")); + } +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeMember, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%dbg_src %float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_32 FlagIsPublic)", + "Name"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %dbg_src %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_32 FlagIsPublic)", + ""), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %float_info 2 3 %VS_OUTPUT_info %u32_0 %int_32 FlagIsPublic)", + "Source"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %dbg_src 2 3 %float_info %u32_0 %int_32 FlagIsPublic)", + "Parent"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %dbg_src 2 3 %VS_OUTPUT_info %void %int_32 FlagIsPublic)", + "Offset"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %void FlagIsPublic)", + "Size"), + })); + +TEST_P(ValidateOpenCL100DebugInfoDebugTypeInheritance, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT {}; +struct foo : VS_OUTPUT {}; +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%foo_name = OpString "foo" +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_name %u32_0 FlagIsPublic %child +%foo_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Structure %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic +%bar_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Union %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic +%child = OpExtInst %void %DbgExt DebugTypeInheritance )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeInheritance, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%dbg_src %VS_OUTPUT_info %u32_0 %u32_0 FlagIsPublic)", + "Child must be a result id of"), + std::make_pair(R"(%foo_info %dbg_src %u32_0 %u32_0 FlagIsPublic)", + "Parent must be a result id of"), + std::make_pair( + R"(%bar_info %VS_OUTPUT_info %u32_0 %u32_0 FlagIsPublic)", + "Child must be class or struct debug type"), + std::make_pair(R"(%foo_info %bar_info %u32_0 %u32_0 FlagIsPublic)", + "Parent must be class or struct debug type"), + std::make_pair(R"(%foo_info %VS_OUTPUT_info %void %u32_0 FlagIsPublic)", + "Offset"), + std::make_pair(R"(%foo_info %VS_OUTPUT_info %u32_0 %void FlagIsPublic)", + "Size"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeComposite) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +struct foo : VS_OUTPUT { +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%foo_name = OpString "foo" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +%u32_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src %u32_2 %u32_3 %u32_0 %u32_128 %u32_3 +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %VS_OUTPUT_linkage_name %u32_128 %u32_3 %VS_OUTPUT_pos_info +%foo_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %foo_name %u32_0 %u32_3 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugTypeComposite, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +struct foo : VS_OUTPUT { +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%foo_name = OpString "foo" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +%u32_128 = OpConstant %u32 128 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src %u32_2 %u32_3 %u32_0 %u32_128 %u32_3 +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite )"; + ss << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second + " must be ")); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugTypeComposite, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%dbg_src %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %VS_OUTPUT_linkage_name %u32_128 %u32_3 %VS_OUTPUT_pos_info)", + "Name"), + std::make_pair( + R"(%VS_OUTPUT_name %u32_1 %comp_unit %u32_1 %u32_1 %comp_unit %VS_OUTPUT_linkage_name %u32_128 %u32_3 %VS_OUTPUT_pos_info)", + "Source"), + std::make_pair( + R"(%VS_OUTPUT_name %u32_1 %dbg_src %u32_1 %u32_1 %dbg_src %VS_OUTPUT_linkage_name %u32_128 %u32_3 %VS_OUTPUT_pos_info)", + "Parent"), + std::make_pair( + R"(%VS_OUTPUT_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %u32_128 %u32_128 %u32_3 %VS_OUTPUT_pos_info)", + "Linkage Name"), + std::make_pair( + R"(%VS_OUTPUT_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %VS_OUTPUT_linkage_name %dbg_src %u32_3 %VS_OUTPUT_pos_info)", + "Size"), + std::make_pair( + R"(%VS_OUTPUT_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %VS_OUTPUT_linkage_name %u32_128 %dbg_src %VS_OUTPUT_pos_info)", + "Flags"), + std::make_pair( + R"(%VS_OUTPUT_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %VS_OUTPUT_linkage_name %u32_128 %u32_3 %dbg_src)", + "Members"), + })); + +TEST_P(ValidateVulkan100DebugInfoDebugTypeMember, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float pos : SV_POSITION; +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +%u32_128 = OpConstant %u32 128 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember )"; + ss << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + if (!param.second.empty()) { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second + + " must be a result id of ")); + } +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugTypeMember, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%dbg_src %float_info %dbg_src %u32_2 %u32_3 %u32_0 %u32_32 %u32_3)", + "Name"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %dbg_src %dbg_src %u32_2 %u32_3 %u32_0 %u32_32 %u32_3)", + ""), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %float_info %u32_2 %u32_3 %u32_0 %u32_32 %u32_3)", + "Source"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %dbg_src %u32_2 %u32_3 %void %u32_32 %u32_3)", + "Offset"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %dbg_src %u32_2 %u32_3 %u32_0 %void %u32_3)", + "Size"), + std::make_pair( + R"(%VS_OUTPUT_pos_name %float_info %dbg_src %u32_2 %u32_3 %u32_0 %u32_32 %void)", + "Flags"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionDeclaration) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +main() {} +" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst_header, + "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugFunction, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +main() {} +" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic +%main_info = OpExtInst %void %DbgExt DebugFunction )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugFunction, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%u32_0 %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)", + "Name"), + std::make_pair( + R"(%main_name %dbg_src %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)", + "Type"), + std::make_pair( + R"(%main_name %main_type_info %comp_unit 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)", + "Source"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src 12 1 %dbg_src %main_linkage_name FlagIsPublic 13 %main)", + "Parent"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %void FlagIsPublic 13 %main)", + "Linkage Name"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %void)", + "Function"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main %dbg_src)", + "Declaration"), + })); + +TEST_P(ValidateOpenCL100DebugInfoDebugFunctionDeclaration, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +main() {} +" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, + ValidateOpenCL100DebugInfoDebugFunctionDeclaration, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%u32_0 %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic)", + "Name"), + std::make_pair( + R"(%main_name %dbg_src %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic)", + "Type"), + std::make_pair( + R"(%main_name %main_type_info %comp_unit 12 1 %comp_unit %main_linkage_name FlagIsPublic)", + "Source"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src 12 1 %dbg_src %main_linkage_name FlagIsPublic)", + "Parent"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %void FlagIsPublic)", + "Linkage Name"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugFunctionDeclaration) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +main() {} +" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_12 = OpConstant %u32 12 +%u32_13 = OpConstant %u32 13 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration %main_name %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3 +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3 %u32_13 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugFunction, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +main() {} +" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_12 = OpConstant %u32 12 +%u32_13 = OpConstant %u32 13 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration %main_name %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3 +%main_info = OpExtInst %void %DbgExt DebugFunction )" + << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugFunction, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%u32_0 %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3 %u32_13)", + "Name"), + std::make_pair( + R"(%main_name %dbg_src %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3 %u32_13)", + "Type"), + std::make_pair( + R"(%main_name %main_type_info %comp_unit %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3 %u32_13)", + "Source"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src %u32_12 %u32_1 %dbg_src %main_linkage_name %u32_3 %u32_13)", + "Parent"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %void %u32_3 %u32_13)", + "Linkage Name"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3 %u32_13 %dbg_src)", + "Declaration"), + })); + +TEST_P(ValidateVulkan100DebugInfoDebugFunctionDeclaration, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; +}; +main() {} +" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_12 = OpConstant %u32 12 +%u32_13 = OpConstant %u32 13 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration )" + << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, + ValidateVulkan100DebugInfoDebugFunctionDeclaration, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%u32_0 %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3)", + "Name"), + std::make_pair( + R"(%main_name %dbg_src %dbg_src %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3)", + "Type"), + std::make_pair( + R"(%main_name %main_type_info %comp_unit %u32_12 %u32_1 %comp_unit %main_linkage_name %u32_3)", + "Source"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src %u32_12 %u32_1 %dbg_src %main_linkage_name %u32_3)", + "Parent"), + std::make_pair( + R"(%main_name %main_type_info %dbg_src %u32_12 %u32_1 %comp_unit %void %u32_3)", + "Linkage Name"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugLexicalBlock) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_block = OpExtInst %void %DbgExt DebugLexicalBlock %dbg_src 1 1 %comp_unit %main_name)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst_header, + "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugLexicalBlock, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_block = OpExtInst %void %DbgExt DebugLexicalBlock )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugLexicalBlock, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%comp_unit 1 1 %comp_unit %main_name)", "Source"), + std::make_pair(R"(%dbg_src 1 1 %dbg_src %main_name)", "Parent"), + std::make_pair(R"(%dbg_src 1 1 %comp_unit %void)", "Name"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugScopeFailScope) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %dbg_src +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Scope")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugScopeFailInlinedAt) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %comp_unit %dbg_src +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Inlined At")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugLexicalBlock) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_block = OpExtInst %void %DbgExt DebugLexicalBlock %dbg_src %u32_1 %u32_1 %comp_unit %main_name +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugLexicalBlock, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +%main_name = OpString "main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_block = OpExtInst %void %DbgExt DebugLexicalBlock )" + << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugLexicalBlock, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%comp_unit %u32_1 %u32_1 %comp_unit %main_name)", + "Source"), + std::make_pair(R"(%dbg_src %u32_1 %u32_1 %dbg_src %main_name)", + "Parent"), + std::make_pair(R"(%dbg_src %u32_1 %u32_1 %comp_unit %void)", "Name"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugScopeFailScope) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %dbg_src +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Scope")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugScopeFailInlinedAt) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %comp_unit %dbg_src +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Inlined At")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugLocalVariable) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugLocalVariable, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo = OpExtInst %void %DbgExt DebugLocalVariable )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugLocalVariable, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%void %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0)", + "Name"), + std::make_pair( + R"(%foo_name %dbg_src %dbg_src 1 10 %comp_unit FlagIsLocal 0)", + "Type"), + std::make_pair( + R"(%foo_name %float_info %comp_unit 1 10 %comp_unit FlagIsLocal 0)", + "Source"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 1 10 %dbg_src FlagIsLocal 0)", + "Parent"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugLocalVariable) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_10 = OpConstant %u32 10 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src %u32_1 %u32_10 %comp_unit %u32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugLocalVariable, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_10 = OpConstant %u32 10 +%u32_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo = OpExtInst %void %DbgExt DebugLocalVariable )" + << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugLocalVariable, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%void %float_info %dbg_src %u32_1 %u32_10 %comp_unit %u32_3 %u32_0)", + "Name"), + std::make_pair( + R"(%foo_name %dbg_src %dbg_src %u32_1 %u32_10 %comp_unit %u32_3 %u32_0)", + "Type"), + std::make_pair( + R"(%foo_name %float_info %comp_unit %u32_1 %u32_10 %comp_unit %u32_3 %u32_0)", + "Source"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_1 %u32_10 %dbg_src %u32_3 %u32_0)", + "Parent"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugDeclare) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 +)"; + + const std::string body = R"( +%foo = OpVariable %f32_ptr_function Function +%decl = OpExtInst %void %DbgExt DebugDeclare %foo_info %foo %null_expr +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugDeclareParam) { + CompileSuccessfully(R"( + OpCapability Shader + %1 = OpExtInstImport "OpenCL.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %in_var_COLOR + %4 = OpString "test.hlsl" + OpSource HLSL 620 %4 "#line 1 \"test.hlsl\" +void main(float foo:COLOR) {} +" + %11 = OpString "#line 1 \"test.hlsl\" +void main(float foo:COLOR) {} +" + %14 = OpString "float" + %17 = OpString "src.main" + %20 = OpString "foo" + OpName %in_var_COLOR "in.var.COLOR" + OpName %main "main" + OpName %param_var_foo "param.var.foo" + OpName %src_main "src.main" + OpName %foo "foo" + OpName %bb_entry "bb.entry" + OpDecorate %in_var_COLOR Location 0 + %uint = OpTypeInt 32 0 + %uint_32 = OpConstant %uint 32 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %void = OpTypeVoid + %23 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float + %29 = OpTypeFunction %void %_ptr_Function_float + OpLine %4 1 21 +%in_var_COLOR = OpVariable %_ptr_Input_float Input + %10 = OpExtInst %void %1 DebugExpression + %12 = OpExtInst %void %1 DebugSource %4 %11 + %13 = OpExtInst %void %1 DebugCompilationUnit 1 4 %12 HLSL + %15 = OpExtInst %void %1 DebugTypeBasic %14 %uint_32 Float + %16 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %void %15 + %18 = OpExtInst %void %1 DebugFunction %17 %16 %12 1 1 %13 %17 FlagIsProtected|FlagIsPrivate 1 %src_main + %21 = OpExtInst %void %1 DebugLocalVariable %20 %15 %12 1 17 %18 FlagIsLocal 0 + %22 = OpExtInst %void %1 DebugLexicalBlock %12 1 28 %18 + OpLine %4 1 1 + %main = OpFunction %void None %23 + %24 = OpLabel + OpLine %4 1 17 +%param_var_foo = OpVariable %_ptr_Function_float Function + %27 = OpLoad %float %in_var_COLOR + OpLine %4 1 1 + %28 = OpFunctionCall %void %src_main %param_var_foo + OpReturn + OpFunctionEnd + %src_main = OpFunction %void None %29 + OpLine %4 1 17 + %foo = OpFunctionParameter %_ptr_Function_float + %31 = OpExtInst %void %1 DebugDeclare %21 %foo %10 + %bb_entry = OpLabel + OpLine %4 1 29 + OpReturn + OpFunctionEnd +)"); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugDeclare, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%foo = OpVariable %f32_ptr_function Function +%decl = OpExtInst %void %DbgExt DebugDeclare )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, ss.str(), extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugDeclare, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%dbg_src %foo %null_expr)", "Local Variable"), + std::make_pair(R"(%foo_info %void %null_expr)", "Variable"), + std::make_pair(R"(%foo_info %foo %dbg_src)", "Expression"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugDeclare) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_10 = OpConstant %u32 10 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src %u32_1 %u32_10 %comp_unit %u32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string body = R"( +%foo = OpVariable %f32_ptr_function Function +%decl = OpExtInst %void %DbgExt DebugDeclare %foo_info %foo %null_expr +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugDeclareParam) { + CompileSuccessfully(R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %in_var_COLOR + %4 = OpString "test.hlsl" + OpSource HLSL 620 %4 "#line 1 \"test.hlsl\" +void main(float foo:COLOR) {} +" + %11 = OpString "#line 1 \"test.hlsl\" +void main(float foo:COLOR) {} +" + %14 = OpString "float" + %17 = OpString "src.main" + %20 = OpString "foo" + OpName %in_var_COLOR "in.var.COLOR" + OpName %main "main" + OpName %param_var_foo "param.var.foo" + OpName %src_main "src.main" + OpName %foo "foo" + OpName %bb_entry "bb.entry" + OpDecorate %in_var_COLOR Location 0 + %uint = OpTypeInt 32 0 + %u32_0 = OpConstant %uint 0 + %u32_1 = OpConstant %uint 1 + %u32_2 = OpConstant %uint 2 + %u32_3 = OpConstant %uint 3 + %u32_4 = OpConstant %uint 4 + %u32_5 = OpConstant %uint 5 + %u32_10 = OpConstant %uint 10 + %u32_17 = OpConstant %uint 17 + %u32_28 = OpConstant %uint 28 + %u32_32 = OpConstant %uint 32 + %uint_32 = OpConstant %uint 32 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %void = OpTypeVoid + %23 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float + %29 = OpTypeFunction %void %_ptr_Function_float + OpLine %4 1 21 +%in_var_COLOR = OpVariable %_ptr_Input_float Input + %10 = OpExtInst %void %1 DebugExpression + %12 = OpExtInst %void %1 DebugSource %4 %11 + %13 = OpExtInst %void %1 DebugCompilationUnit %u32_1 %u32_4 %12 %u32_5 + %15 = OpExtInst %void %1 DebugTypeBasic %14 %uint_32 %u32_3 %u32_0 + %16 = OpExtInst %void %1 DebugTypeFunction %u32_3 %void %15 + %18 = OpExtInst %void %1 DebugFunction %17 %16 %12 %u32_1 %u32_1 %13 %17 %u32_3 %u32_1 + %21 = OpExtInst %void %1 DebugLocalVariable %20 %15 %12 %u32_1 %u32_17 %18 %u32_4 %u32_0 + %22 = OpExtInst %void %1 DebugLexicalBlock %12 %u32_1 %u32_28 %18 + %main = OpFunction %void None %23 + %24 = OpLabel +%param_var_foo = OpVariable %_ptr_Function_float Function + %27 = OpLoad %float %in_var_COLOR + %28 = OpFunctionCall %void %src_main %param_var_foo + OpReturn + OpFunctionEnd + %src_main = OpFunction %void None %29 + %foo = OpFunctionParameter %_ptr_Function_float + %31 = OpExtInst %void %1 DebugDeclare %21 %foo %10 + %bb_entry = OpLabel + OpReturn + OpFunctionEnd +)"); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugDeclare, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_10 = OpConstant %u32 10 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src %u32_1 %u32_10 %comp_unit %u32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%foo = OpVariable %f32_ptr_function Function +%decl = OpExtInst %void %DbgExt DebugDeclare )" + << param.first; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, ss.str(), extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllVulkan100DebugInfoFail, ValidateVulkan100DebugInfoDebugDeclare, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%dbg_src %foo %null_expr)", "Local Variable"), + std::make_pair(R"(%foo_info %void %null_expr)", "Variable"), + std::make_pair(R"(%foo_info %foo %dbg_src)", "Expression"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugExpression) { + const std::string dbg_inst_header = R"( +%op0 = OpExtInst %void %DbgExt DebugOperation Deref +%op1 = OpExtInst %void %DbgExt DebugOperation Plus +%null_expr = OpExtInst %void %DbgExt DebugExpression %op0 %op1 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo("", "", dbg_inst_header, + "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugExpressionFail) { + const std::string dbg_inst_header = R"( +%op = OpExtInst %void %DbgExt DebugOperation Deref +%null_expr = OpExtInst %void %DbgExt DebugExpression %op %void +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo("", "", dbg_inst_header, + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "expected operand Operation must be a result id of DebugOperation")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugExpression) { + const std::string dbg_inst_header = R"( +%op0 = OpExtInst %void %DbgExt DebugOperation %u32_0 +%op1 = OpExtInst %void %DbgExt DebugOperation %u32_1 +%null_expr = OpExtInst %void %DbgExt DebugExpression %op0 %op1 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo("", "", dbg_inst_header, + "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugExpressionFail) { + const std::string dbg_inst_header = R"( +%op = OpExtInst %void %DbgExt DebugOperation %u32_0 +%null_expr = OpExtInst %void %DbgExt DebugExpression %op %void +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo("", "", dbg_inst_header, + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "expected operand Operation must be a result id of DebugOperation")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplate) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name Class %dbg_src 1 1 %comp_unit %ty_name %dbg_none FlagIsPublic +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %opaque %param +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateUsedForVariableType) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name Class %dbg_src 1 1 %comp_unit %ty_name %dbg_none FlagIsPublic +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %opaque %param +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %temp %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%main_name = OpString "main" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %param %param +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %main_info %param +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateFailTarget) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%main_name = OpString "main" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %float_info %param +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Target must be DebugTypeComposite or " + "DebugFunction")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateFailParam) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%main_name = OpString "main" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %param %param +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %main_info %float_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "expected operand Parameters must be DebugTypeTemplateParameter or " + "DebugTypeTemplateTemplateParameter")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeTemplate) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %ty_name %dbg_none %u32_3 +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src %u32_0 %u32_0 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %opaque %param +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeTemplateUsedForVariableType) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %ty_name %dbg_none %u32_3 +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src %u32_0 %u32_0 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %opaque %param +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %temp %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %f32_input %u32_3 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeTemplateFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%main_name = OpString "main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src %u32_0 %u32_0 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %param %param +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_1 %u32_1 %comp_unit %main_name %u32_3 %u32_1 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %main_info %param +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeTemplateFailTarget) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%main_name = OpString "main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src %u32_0 %u32_0 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %float_info %param +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand Target must be DebugTypeComposite or " + "DebugFunction")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugTypeTemplateFailParam) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "OpaqueType foo; +main() {} +" +%float_name = OpString "float" +%ty_name = OpString "Texture" +%t_name = OpString "T" +%main_name = OpString "main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_none = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name %u32_1 %dbg_src %u32_1 %u32_1 %comp_unit %ty_name %dbg_none %u32_3 +%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src %u32_0 %u32_0 +%temp = OpExtInst %void %DbgExt DebugTypeTemplate %opaque %float_info +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "expected operand Parameters must be DebugTypeTemplateParameter or " + "DebugTypeTemplateTemplateParameter")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariable) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariableStaticMember) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%t = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Class %dbg_src 0 0 %comp_unit %foo_name %int_32 FlagIsPublic %a +%a = OpExtInst %void %DbgExt DebugTypeMember %foo_name %float_info %dbg_src 0 0 %t %u32_0 %int_32 FlagIsPublic +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate %a +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariableDebugInfoNone) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbgNone = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %dbgNone FlagIsProtected|FlagIsPrivate +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariableConst) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %int_32 FlagIsProtected|FlagIsPrivate +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugGlobalVariable, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo = OpExtInst %void %DbgExt DebugGlobalVariable )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugGlobalVariable, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%void %float_info %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", + "Name"), + std::make_pair( + R"(%foo_name %dbg_src %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", + "Type"), + std::make_pair( + R"(%foo_name %float_info %comp_unit 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", + "Source"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 0 0 %dbg_src %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", + "Scope"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 0 0 %comp_unit %void %f32_input FlagIsProtected|FlagIsPrivate)", + "Linkage Name"), + std::make_pair( + R"(%foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %void FlagIsProtected|FlagIsPrivate)", + "Variable"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugGlobalVariable) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %f32_input %u32_3 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugGlobalVariableStaticMember) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%a = OpExtInst %void %DbgExt DebugTypeMember %foo_name %float_info %dbg_src %u32_0 %u32_0 %u32_0 %u32_32 %u32_3 +%t = OpExtInst %void %DbgExt DebugTypeComposite %foo_name %u32_1 %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %u32_32 %u32_3 %a +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %t %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %f32_input %u32_3 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugGlobalVariableDebugInfoNone) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbgNone = OpExtInst %void %DbgExt DebugInfoNone +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %dbgNone %u32_3 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugGlobalVariableConst) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %u32_32 %u32_3 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugGlobalVariable, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float foo; void main() {}" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%foo = OpExtInst %void %DbgExt DebugGlobalVariable )" + << param.first; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, constants, ss.str(), + "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateVulkan100DebugInfoDebugGlobalVariable, + ::testing::ValuesIn(std::vector>{ + std::make_pair( + R"(%void %float_info %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %f32_input %u32_3)", + "Name"), + std::make_pair( + R"(%foo_name %dbg_src %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %f32_input %u32_3)", + "Type"), + std::make_pair( + R"(%foo_name %float_info %comp_unit %u32_0 %u32_0 %comp_unit %foo_name %f32_input %u32_3)", + "Source"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_0 %u32_0 %dbg_src %foo_name %f32_input %u32_3)", + "Scope"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_0 %u32_0 %comp_unit %void %f32_input %u32_3)", + "Linkage Name"), + std::make_pair( + R"(%foo_name %float_info %dbg_src %u32_0 %u32_0 %comp_unit %foo_name %void %u32_3)", + "Variable"), + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugInlinedAt) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main +%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info +%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info %inlined_at +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugInlinedAtFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main +%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info +%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt 0 %inlined_at +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Scope")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugInlinedAtFail2) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main +%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info +%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info %main_info +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Inlined")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugInlinedAt) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_1 %u32_1 %comp_unit %main_name %u32_3 %u32_1 +%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt %u32_0 %main_info +%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt %u32_0 %main_info %inlined_at +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugInlinedAtFail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_1 %u32_1 %comp_unit %main_name %u32_3 %u32_1 +%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt %u32_0 %main_info +%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt %u32_0 %inlined_at %inlined_at +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Scope")); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugInlinedAtFail2) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction %u32_3 %void +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src %u32_1 %u32_1 %comp_unit %main_name %u32_3 %u32_1 +%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt %u32_0 %main_info +%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt %u32_0 %main_info %main_info +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Inlined")); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugValue) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_3 = OpConstant %u32 3 +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %v4float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 +)"; + + const std::string body = R"( +%value = OpExtInst %void %DbgExt DebugValue %foo_info %int_32 %null_expr %int_3 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugValueWithVariableIndex) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%int_name = OpString "int" +%foo_name = OpString "foo" +%len_name = OpString "length" +)"; + + const std::string size_const = R"( +%int_3 = OpConstant %u32 3 +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %int_32 Signed +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %v4float_info %dbg_src 1 10 %comp_unit FlagIsLocal +%len_info = OpExtInst %void %DbgExt DebugLocalVariable %len_name %int_info %dbg_src 0 0 %comp_unit FlagIsLocal +)"; + + const std::string body = R"( +%value = OpExtInst %void %DbgExt DebugValue %foo_info %int_32 %null_expr %len_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateOpenCL100DebugInfoDebugValue, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%decl = OpExtInst %void %DbgExt DebugValue )" + << param.first; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, ss.str(), extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugValue, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%dbg_src %int_32 %null_expr)", "Local Variable"), + std::make_pair(R"(%foo_info %int_32 %dbg_src)", "Expression"), + std::make_pair(R"(%foo_info %int_32 %null_expr %dbg_src)", "Indexes"), + })); + +TEST_F(ValidateVulkan100DebugInfo, DebugValue) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_10 = OpConstant %u32 10 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_4 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %v4float_info %dbg_src %u32_1 %u32_10 %comp_unit %u32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string body = R"( +%value = OpExtInst %void %DbgExt DebugValue %foo_info %u32_32 %null_expr %u32_3 +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateVulkan100DebugInfo, DebugValueWithVariableIndex) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%int_name = OpString "int" +%foo_name = OpString "foo" +%len_name = OpString "length" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_10 = OpConstant %u32 10 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %u32_32 %u32_4 %u32_0 +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_4 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %v4float_info %dbg_src %u32_1 %u32_10 %comp_unit %u32_4 %u32_0 +%len_info = OpExtInst %void %DbgExt DebugLocalVariable %len_name %int_info %dbg_src %u32_0 %u32_0 %comp_unit %u32_4 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const std::string body = R"( +%value = OpExtInst %void %DbgExt DebugValue %foo_info %u32_32 %null_expr %len_info +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateVulkan100DebugInfoDebugValue, Fail) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() { float foo; }" +%float_name = OpString "float" +%foo_name = OpString "foo" +)"; + + const std::string constants = R"( +%u32_4 = OpConstant %u32 4 +%u32_5 = OpConstant %u32 5 +%u32_10 = OpConstant %u32 10 +%u32_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit %u32_2 %u32_4 %dbg_src %u32_5 +%null_expr = OpExtInst %void %DbgExt DebugExpression +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %u32_32 %u32_3 %u32_0 +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info %u32_4 +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %v4float_info %dbg_src %u32_1 %u32_10 %comp_unit %u32_4 %u32_0 +)"; + + const std::string extension = R"( +OpExtension "SPV_KHR_non_semantic_info" +%DbgExt = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +)"; + + const auto& param = GetParam(); + + std::ostringstream ss; + ss << R"( +%decl = OpExtInst %void %DbgExt DebugValue )" + << param.first; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, constants, dbg_inst_header, ss.str(), extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected operand " + param.second)); +} + +INSTANTIATE_TEST_SUITE_P( + AllOpenCL100DebugInfoFail, ValidateVulkan100DebugInfoDebugValue, + ::testing::ValuesIn(std::vector>{ + std::make_pair(R"(%dbg_src %u32_32 %null_expr %u32_3)", + "Local Variable"), + std::make_pair(R"(%foo_info %u32_32 %dbg_src %u32_3)", "Expression"), + std::make_pair(R"(%foo_info %u32_32 %null_expr %dbg_src)", "Indexes"), + })); + +TEST_F(ValidateVulkan100DebugInfo, VulkanDebugInfoSample) { + std::ostringstream ss; + ss << R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %id_1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %id_MainPs "MainPs" %id_in_var_TEXCOORD2 %id_out_var_SV_Target0 + OpExecutionMode %id_MainPs OriginUpperLeft + %id_7 = OpString "foo.frag" + %id_27 = OpString "float" + %id_32 = OpString "vColor" + %id_36 = OpString "PS_OUTPUT" + %id_42 = OpString "vTextureCoords" + %id_46 = OpString "PS_INPUT" + %id_49 = OpString "MainPs" + %id_50 = OpString "" + %id_55 = OpString "ps_output" + %id_59 = OpString "i" + %id_63 = OpString "@type.sampler" + %id_64 = OpString "type.sampler" + %id_66 = OpString "g_sAniso" + %id_69 = OpString "@type.2d.image" + %id_70 = OpString "type.2d.image" + %id_72 = OpString "TemplateParam" + %id_75 = OpString "g_tColor" + OpName %id_type_2d_image "type.2d.image" + OpName %id_g_tColor "g_tColor" + OpName %id_type_sampler "type.sampler" + OpName %id_g_sAniso "g_sAniso" + OpName %id_in_var_TEXCOORD2 "in.var.TEXCOORD2" + OpName %id_out_var_SV_Target0 "out.var.SV_Target0" + OpName %id_MainPs "MainPs" + OpName %id_PS_INPUT "PS_INPUT" + OpMemberName %id_PS_INPUT 0 "vTextureCoords" + OpName %id_param_var_i "param.var.i" + OpName %id_PS_OUTPUT "PS_OUTPUT" + OpMemberName %id_PS_OUTPUT 0 "vColor" + OpName %id_src_MainPs "src.MainPs" + OpName %id_i "i" + OpName %id_bb_entry "bb.entry" + OpName %id_ps_output "ps_output" + OpName %id_type_sampled_image "type.sampled.image" + OpDecorate %id_in_var_TEXCOORD2 Location 0 + OpDecorate %id_out_var_SV_Target0 Location 0 + OpDecorate %id_g_tColor DescriptorSet 0 + OpDecorate %id_g_tColor Binding 0 + OpDecorate %id_g_sAniso DescriptorSet 0 + OpDecorate %id_g_sAniso Binding 1 + %id_int = OpTypeInt 32 1 + %id_int_0 = OpConstant %id_int 0 + %id_uint = OpTypeInt 32 0 + %id_uint_32 = OpConstant %id_uint 32 + %id_float = OpTypeFloat 32 +%id_type_2d_image = OpTypeImage %id_float 2D 2 0 0 1 Unknown +%id__ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %id_type_2d_image +%id_type_sampler = OpTypeSampler +%id__ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %id_type_sampler + %id_v2float = OpTypeVector %id_float 2 +%id__ptr_Input_v2float = OpTypePointer Input %id_v2float + %id_v4float = OpTypeVector %id_float 4 +%id__ptr_Output_v4float = OpTypePointer Output %id_v4float + %id_void = OpTypeVoid + %id_uint_1 = OpConstant %id_uint 1 + %id_uint_4 = OpConstant %id_uint 4 + %id_uint_5 = OpConstant %id_uint 5 + %id_uint_3 = OpConstant %id_uint 3 + %id_uint_0 = OpConstant %id_uint 0 + %id_uint_128 = OpConstant %id_uint 128 + %id_uint_12 = OpConstant %id_uint 12 + %id_uint_10 = OpConstant %id_uint 10 + %id_uint_8 = OpConstant %id_uint 8 + %id_uint_2 = OpConstant %id_uint 2 + %id_uint_64 = OpConstant %id_uint 64 + %id_uint_7 = OpConstant %id_uint 7 + %id_uint_15 = OpConstant %id_uint 15 + %id_uint_16 = OpConstant %id_uint 16 + %id_uint_17 = OpConstant %id_uint 17 + %id_uint_29 = OpConstant %id_uint 29 + %id_uint_14 = OpConstant %id_uint 14 + %id_uint_11 = OpConstant %id_uint 11 + %id_78 = OpTypeFunction %id_void + %id_PS_INPUT = OpTypeStruct %id_v2float +%id__ptr_Function_PS_INPUT = OpTypePointer Function %id_PS_INPUT + %id_PS_OUTPUT = OpTypeStruct %id_v4float + %id_89 = OpTypeFunction %id_PS_OUTPUT %id__ptr_Function_PS_INPUT +%id__ptr_Function_PS_OUTPUT = OpTypePointer Function %id_PS_OUTPUT + %id_uint_20 = OpConstant %id_uint 20 + %id_uint_19 = OpConstant %id_uint 19 + %id_uint_26 = OpConstant %id_uint 26 + %id_uint_46 = OpConstant %id_uint 46 +%id__ptr_Function_v2float = OpTypePointer Function %id_v2float + %id_uint_57 = OpConstant %id_uint 57 + %id_uint_78 = OpConstant %id_uint 78 +%id_type_sampled_image = OpTypeSampledImage %id_type_2d_image + %id_uint_81 = OpConstant %id_uint 81 +%id__ptr_Function_v4float = OpTypePointer Function %id_v4float + %id_g_tColor = OpVariable %id__ptr_UniformConstant_type_2d_image UniformConstant + %id_g_sAniso = OpVariable %id__ptr_UniformConstant_type_sampler UniformConstant +%id_in_var_TEXCOORD2 = OpVariable %id__ptr_Input_v2float Input +%id_out_var_SV_Target0 = OpVariable %id__ptr_Output_v4float Output + %id_22 = OpExtInst %id_void %id_1 DebugSource %id_7 + %id_23 = OpExtInst %id_void %id_1 DebugCompilationUnit %id_uint_1 %id_uint_4 %id_22 %id_uint_5 + %id_28 = OpExtInst %id_void %id_1 DebugTypeBasic %id_27 %id_uint_32 %id_uint_3 %id_uint_0 + %id_31 = OpExtInst %id_void %id_1 DebugTypeVector %id_28 %id_uint_4 + %id_34 = OpExtInst %id_void %id_1 DebugTypeMember %id_32 %id_31 %id_22 %id_uint_12 %id_uint_12 %id_uint_0 %id_uint_128 %id_uint_3 + %id_37 = OpExtInst %id_void %id_1 DebugTypeComposite %id_36 %id_uint_1 %id_22 %id_uint_10 %id_uint_8 %id_23 %id_36 %id_uint_128 %id_uint_3 %id_34 + %id_40 = OpExtInst %id_void %id_1 DebugTypeVector %id_28 %id_uint_2 + %id_44 = OpExtInst %id_void %id_1 DebugTypeMember %id_42 %id_40 %id_22 %id_uint_7 %id_uint_12 %id_uint_0 %id_uint_64 %id_uint_3 + %id_47 = OpExtInst %id_void %id_1 DebugTypeComposite %id_46 %id_uint_1 %id_22 %id_uint_5 %id_uint_8 %id_23 %id_46 %id_uint_64 %id_uint_3 %id_44 + %id_48 = OpExtInst %id_void %id_1 DebugTypeFunction %id_uint_3 %id_37 %id_47 + %id_51 = OpExtInst %id_void %id_1 DebugFunction %id_49 %id_48 %id_22 %id_uint_15 %id_uint_1 %id_23 %id_50 %id_uint_3 %id_uint_16 + %id_54 = OpExtInst %id_void %id_1 DebugLexicalBlock %id_22 %id_uint_16 %id_uint_1 %id_51 + %id_56 = OpExtInst %id_void %id_1 DebugLocalVariable %id_55 %id_37 %id_22 %id_uint_17 %id_uint_15 %id_54 %id_uint_4 + %id_58 = OpExtInst %id_void %id_1 DebugExpression + %id_60 = OpExtInst %id_void %id_1 DebugLocalVariable %id_59 %id_47 %id_22 %id_uint_15 %id_uint_29 %id_51 %id_uint_4 %id_uint_1 + %id_62 = OpExtInst %id_void %id_1 DebugInfoNone + %id_65 = OpExtInst %id_void %id_1 DebugTypeComposite %id_63 %id_uint_1 %id_22 %id_uint_0 %id_uint_0 %id_23 %id_64 %id_62 %id_uint_3 + %id_67 = OpExtInst %id_void %id_1 DebugGlobalVariable %id_66 %id_65 %id_22 %id_uint_3 %id_uint_14 %id_23 %id_66 %id_g_sAniso %id_uint_8 + %id_71 = OpExtInst %id_void %id_1 DebugTypeComposite %id_69 %id_uint_0 %id_22 %id_uint_0 %id_uint_0 %id_23 %id_70 %id_62 %id_uint_3 + %id_73 = OpExtInst %id_void %id_1 DebugTypeTemplateParameter %id_72 %id_31 %id_62 %id_22 %id_uint_0 %id_uint_0 + %id_74 = OpExtInst %id_void %id_1 DebugTypeTemplate %id_71 %id_73 + %id_76 = OpExtInst %id_void %id_1 DebugGlobalVariable %id_75 %id_74 %id_22 %id_uint_1 %id_uint_11 %id_23 %id_75 %id_g_tColor %id_uint_8 + %id_MainPs = OpFunction %id_void None %id_78 + %id_79 = OpLabel +%id_param_var_i = OpVariable %id__ptr_Function_PS_INPUT Function + %id_83 = OpLoad %id_v2float %id_in_var_TEXCOORD2 + %id_84 = OpCompositeConstruct %id_PS_INPUT %id_83 + OpStore %id_param_var_i %id_84 + %id_86 = OpFunctionCall %id_PS_OUTPUT %id_src_MainPs %id_param_var_i + %id_88 = OpCompositeExtract %id_v4float %id_86 0 + OpStore %id_out_var_SV_Target0 %id_88 + OpReturn + OpFunctionEnd + %id_src_MainPs = OpFunction %id_PS_OUTPUT None %id_89 + %id_i = OpFunctionParameter %id__ptr_Function_PS_INPUT + %id_bb_entry = OpLabel + %id_ps_output = OpVariable %id__ptr_Function_PS_OUTPUT Function + %id_94 = OpExtInst %id_void %id_1 DebugScope %id_51 + %id_97 = OpExtInst %id_void %id_1 DebugDeclare %id_60 %id_i %id_58 + %id_99 = OpExtInst %id_void %id_1 DebugFunctionDefinition %id_51 %id_src_MainPs + %id_100 = OpExtInst %id_void %id_1 DebugScope %id_54 + %id_102 = OpExtInst %id_void %id_1 DebugDeclare %id_56 %id_ps_output %id_58 + %id_106 = OpLoad %id_type_2d_image %id_g_tColor + %id_109 = OpLoad %id_type_sampler %id_g_sAniso + %id_114 = OpAccessChain %id__ptr_Function_v2float %id_i %id_int_0 + %id_115 = OpLoad %id_v2float %id_114 + %id_119 = OpSampledImage %id_type_sampled_image %id_106 %id_109 + %id_120 = OpImageSampleImplicitLod %id_v4float %id_119 %id_115 None + %id_123 = OpAccessChain %id__ptr_Function_v4float %id_ps_output %id_int_0 + OpStore %id_123 %id_120 + %id_125 = OpLoad %id_PS_OUTPUT %id_ps_output + OpReturnValue %id_125 + OpFunctionEnd +)"; + + CompileSuccessfully(ss.str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_ext_inst_test.cpp b/third_party/spirv-tools/test/val/val_ext_inst_test.cpp index b73ec3415d..2b6df04ddd 100644 --- a/third_party/spirv-tools/test/val/val_ext_inst_test.cpp +++ b/third_party/spirv-tools/test/val/val_ext_inst_test.cpp @@ -33,33 +33,6 @@ using ::testing::HasSubstr; using ::testing::Not; using ValidateExtInst = spvtest::ValidateBase; -using ValidateOldDebugInfo = spvtest::ValidateBase; -using ValidateOpenCL100DebugInfo = spvtest::ValidateBase; -using ValidateLocalDebugInfoOutOfFunction = spvtest::ValidateBase; -using ValidateOpenCL100DebugInfoDebugTypedef = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugTypeEnum = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugTypeComposite = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugTypeMember = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugTypeInheritance = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugFunction = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugFunctionDeclaration = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugLexicalBlock = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugLocalVariable = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugGlobalVariable = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugDeclare = - spvtest::ValidateBase>; -using ValidateOpenCL100DebugInfoDebugValue = - spvtest::ValidateBase>; using ValidateGlslStd450SqrtLike = spvtest::ValidateBase; using ValidateGlslStd450FMinLike = spvtest::ValidateBase; using ValidateGlslStd450FClampLike = spvtest::ValidateBase; @@ -488,1685 +461,6 @@ OpFunctionEnd)"; return ss.str(); } -std::string GenerateShaderCodeForDebugInfo( - const std::string& op_string_instructions, - const std::string& op_const_instructions, - const std::string& debug_instructions_before_main, const std::string& body, - const std::string& capabilities_and_extensions = "", - const std::string& execution_model = "Fragment") { - std::ostringstream ss; - ss << R"( -OpCapability Shader -OpCapability Float16 -OpCapability Float64 -OpCapability Int16 -OpCapability Int64 -)"; - - ss << capabilities_and_extensions; - ss << "%extinst = OpExtInstImport \"GLSL.std.450\"\n"; - ss << "OpMemoryModel Logical GLSL450\n"; - ss << "OpEntryPoint " << execution_model << " %main \"main\"" - << " %f32_output" - << " %f32vec2_output" - << " %u32_output" - << " %u32vec2_output" - << " %u64_output" - << " %f32_input" - << " %f32vec2_input" - << " %u32_input" - << " %u32vec2_input" - << " %u64_input" - << "\n"; - if (execution_model == "Fragment") { - ss << "OpExecutionMode %main OriginUpperLeft\n"; - } - - ss << op_string_instructions; - - ss << R"( -%void = OpTypeVoid -%func = OpTypeFunction %void -%bool = OpTypeBool -%f16 = OpTypeFloat 16 -%f32 = OpTypeFloat 32 -%f64 = OpTypeFloat 64 -%u32 = OpTypeInt 32 0 -%s32 = OpTypeInt 32 1 -%u64 = OpTypeInt 64 0 -%s64 = OpTypeInt 64 1 -%u16 = OpTypeInt 16 0 -%s16 = OpTypeInt 16 1 -%f32vec2 = OpTypeVector %f32 2 -%f32vec3 = OpTypeVector %f32 3 -%f32vec4 = OpTypeVector %f32 4 -%f64vec2 = OpTypeVector %f64 2 -%f64vec3 = OpTypeVector %f64 3 -%f64vec4 = OpTypeVector %f64 4 -%u32vec2 = OpTypeVector %u32 2 -%u32vec3 = OpTypeVector %u32 3 -%s32vec2 = OpTypeVector %s32 2 -%u32vec4 = OpTypeVector %u32 4 -%s32vec4 = OpTypeVector %s32 4 -%u64vec2 = OpTypeVector %u64 2 -%s64vec2 = OpTypeVector %s64 2 -%f64mat22 = OpTypeMatrix %f64vec2 2 -%f32mat22 = OpTypeMatrix %f32vec2 2 -%f32mat23 = OpTypeMatrix %f32vec2 3 -%f32mat32 = OpTypeMatrix %f32vec3 2 -%f32mat33 = OpTypeMatrix %f32vec3 3 - -%f32_0 = OpConstant %f32 0 -%f32_1 = OpConstant %f32 1 -%f32_2 = OpConstant %f32 2 -%f32_3 = OpConstant %f32 3 -%f32_4 = OpConstant %f32 4 -%f32_h = OpConstant %f32 0.5 -%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 -%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 -%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 -%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 -%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 -%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 - -%f64_0 = OpConstant %f64 0 -%f64_1 = OpConstant %f64 1 -%f64_2 = OpConstant %f64 2 -%f64_3 = OpConstant %f64 3 -%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1 -%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2 -%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3 - -%f16_0 = OpConstant %f16 0 -%f16_1 = OpConstant %f16 1 -%f16_h = OpConstant %f16 0.5 - -%u32_0 = OpConstant %u32 0 -%u32_1 = OpConstant %u32 1 -%u32_2 = OpConstant %u32 2 -%u32_3 = OpConstant %u32 3 - -%s32_0 = OpConstant %s32 0 -%s32_1 = OpConstant %s32 1 -%s32_2 = OpConstant %s32 2 -%s32_3 = OpConstant %s32 3 - -%u64_0 = OpConstant %u64 0 -%u64_1 = OpConstant %u64 1 -%u64_2 = OpConstant %u64 2 -%u64_3 = OpConstant %u64 3 - -%s64_0 = OpConstant %s64 0 -%s64_1 = OpConstant %s64 1 -%s64_2 = OpConstant %s64 2 -%s64_3 = OpConstant %s64 3 -)"; - - ss << op_const_instructions; - - ss << R"( -%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1 -%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 - -%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2 -%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 - -%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3 -%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 - -%s64vec2_01 = OpConstantComposite %s64vec2 %s64_0 %s64_1 -%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1 - -%f32mat22_1212 = OpConstantComposite %f32mat22 %f32vec2_12 %f32vec2_12 -%f32mat23_121212 = OpConstantComposite %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12 - -%f32_ptr_output = OpTypePointer Output %f32 -%f32vec2_ptr_output = OpTypePointer Output %f32vec2 - -%u32_ptr_output = OpTypePointer Output %u32 -%u32vec2_ptr_output = OpTypePointer Output %u32vec2 - -%u64_ptr_output = OpTypePointer Output %u64 - -%f32_output = OpVariable %f32_ptr_output Output -%f32vec2_output = OpVariable %f32vec2_ptr_output Output - -%u32_output = OpVariable %u32_ptr_output Output -%u32vec2_output = OpVariable %u32vec2_ptr_output Output - -%u64_output = OpVariable %u64_ptr_output Output - -%f32_ptr_input = OpTypePointer Input %f32 -%f32vec2_ptr_input = OpTypePointer Input %f32vec2 - -%u32_ptr_input = OpTypePointer Input %u32 -%u32vec2_ptr_input = OpTypePointer Input %u32vec2 - -%u64_ptr_input = OpTypePointer Input %u64 - -%f32_ptr_function = OpTypePointer Function %f32 - -%f32_input = OpVariable %f32_ptr_input Input -%f32vec2_input = OpVariable %f32vec2_ptr_input Input - -%u32_input = OpVariable %u32_ptr_input Input -%u32vec2_input = OpVariable %u32vec2_ptr_input Input - -%u64_input = OpVariable %u64_ptr_input Input - -%u32_ptr_function = OpTypePointer Function %u32 - -%struct_f16_u16 = OpTypeStruct %f16 %u16 -%struct_f32_f32 = OpTypeStruct %f32 %f32 -%struct_f32_f32_f32 = OpTypeStruct %f32 %f32 %f32 -%struct_f32_u32 = OpTypeStruct %f32 %u32 -%struct_f32_u32_f32 = OpTypeStruct %f32 %u32 %f32 -%struct_u32_f32 = OpTypeStruct %u32 %f32 -%struct_u32_u32 = OpTypeStruct %u32 %u32 -%struct_f32_f64 = OpTypeStruct %f32 %f64 -%struct_f32vec2_f32vec2 = OpTypeStruct %f32vec2 %f32vec2 -%struct_f32vec2_u32vec2 = OpTypeStruct %f32vec2 %u32vec2 -)"; - - ss << debug_instructions_before_main; - - ss << R"( -%main = OpFunction %void None %func -%main_entry = OpLabel -)"; - - ss << body; - - ss << R"( -OpReturn -OpFunctionEnd)"; - - return ss.str(); -} - -TEST_F(ValidateOldDebugInfo, UseDebugInstructionOutOfFunction) { - const std::string src = R"( -%code = OpString "main() {}" -)"; - - const std::string dbg_inst = R"( -%cu = OpExtInst %void %DbgExt DebugCompilationUnit %code 1 1 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "DebugInfo" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, UseDebugInstructionOutOfFunction) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugSourceInFunction) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", "", dbg_inst, - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Debug info extension instructions other than DebugScope, " - "DebugNoScope, DebugDeclare, DebugValue must appear between " - "section 9 (types, constants, global variables) and section 10 " - "(function declarations)")); -} - -TEST_P(ValidateLocalDebugInfoOutOfFunction, OpenCLDebugInfo100DebugScope) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -%void_name = OpString "void" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -%int_name = OpString "int" -%foo_name = OpString "foo" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %u32_0 Signed -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %int_info %dbg_src 1 1 %main_info FlagIsLocal -%expr = OpExtInst %void %DbgExt DebugExpression -)"; - - const std::string body = R"( -%foo = OpVariable %u32_ptr_function Function -%foo_val = OpLoad %u32 %foo -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header + GetParam(), body, extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("DebugScope, DebugNoScope, DebugDeclare, DebugValue " - "of debug info extension must appear in a function " - "body")); -} - -INSTANTIATE_TEST_SUITE_P( - AllLocalDebugInfo, ValidateLocalDebugInfoOutOfFunction, - ::testing::ValuesIn(std::vector{ - "%main_scope = OpExtInst %void %DbgExt DebugScope %main_info", - "%no_scope = OpExtInst %void %DbgExt DebugNoScope", - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionForwardReference) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -%void_name = OpString "void" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %main_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionMissingOpFunction) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -%void_name = OpString "void" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -)"; - - const std::string dbg_inst_header = R"( -%dbgNone = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %dbgNone -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %main_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugScopeBeforeOpVariableInFunction) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float4 main(float arg) { - float foo; - return float4(0, 0, 0, 0); -} -" -%float_name = OpString "float" -%main_name = OpString "main" -%main_linkage_name = OpString "v4f_main_f" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %main_info -%foo = OpVariable %f32_ptr_function Function -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeSizeDebugInfoNone) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "OpaqueType foo; -main() {} -" -%ty_name = OpString "struct VS_OUTPUT" -)"; - - const std::string dbg_inst_header = R"( -%dbg_none = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name Class %dbg_src 1 1 %comp_unit %ty_name %dbg_none FlagIsPublic -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst_header, - "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeForwardReference) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float4 pos : SV_POSITION; - float4 color : COLOR; -}; -main() {} -" -%VS_OUTPUT_name = OpString "struct VS_OUTPUT" -%float_name = OpString "float" -%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" -%VS_OUTPUT_color_name = OpString "color : COLOR" -%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic -%VS_OUTPUT_color_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_color_name %v4float_info %dbg_src 3 3 %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeMissingReference) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float4 pos : SV_POSITION; - float4 color : COLOR; -}; -main() {} -" -%VS_OUTPUT_name = OpString "struct VS_OUTPUT" -%float_name = OpString "float" -%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" -%VS_OUTPUT_color_name = OpString "color : COLOR" -%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("forward referenced IDs have not been defined")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugInstructionWrongResultType) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %bool %DbgExt DebugSource %src %code -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected result type must be a result id of " - "OpTypeVoid")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugCompilationUnit) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugCompilationUnitFail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %src HLSL -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Source must be a result id of " - "DebugSource")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugSourceFailFile) { - const std::string src = R"( -%code = OpString "main() {}" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %DbgExt %code -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand File must be a result id of " - "OpString")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugSourceFailSource) { - const std::string src = R"( -%src = OpString "simple.hlsl" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %DbgExt -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Text must be a result id of " - "OpString")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugSourceNoText) { - const std::string src = R"( -%src = OpString "simple.hlsl" -)"; - - const std::string dbg_inst = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", - extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeBasicFailName) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float4 main(float arg) { - float foo; - return float4(0, 0, 0, 0); -} -" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %int_32 %int_32 Float -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Name must be a result id of " - "OpString")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeBasicFailSize) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float4 main(float arg) { - float foo; - return float4(0, 0, 0, 0); -} -" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %float_name Float -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Size must be a result id of " - "OpConstant")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypePointer) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float4 main(float arg) { - float foo; - return float4(0, 0, 0, 0); -} -" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%pfloat_info = OpExtInst %void %DbgExt DebugTypePointer %float_info Function FlagIsLocal -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypePointerFail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float4 main(float arg) { - float foo; - return float4(0, 0, 0, 0); -} -" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%pfloat_info = OpExtInst %void %DbgExt DebugTypePointer %dbg_src Function FlagIsLocal -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeQualifier) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float4 main(float arg) { - float foo; - return float4(0, 0, 0, 0); -} -" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%cfloat_info = OpExtInst %void %DbgExt DebugTypeQualifier %float_info ConstType -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeQualifierFail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float4 main(float arg) { - float foo; - return float4(0, 0, 0, 0); -} -" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%cfloat_info = OpExtInst %void %DbgExt DebugTypeQualifier %comp_unit ConstType -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArray) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %int_32 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayWithVariableSize) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -%int_name = OpString "int" -%main_name = OpString "main" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%uint_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %int_32 Unsigned -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %uint_info %dbg_src 1 1 %main_info FlagIsLocal -%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %foo_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailBaseType) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %comp_unit %int_32 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type is not a valid debug " - "type")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailComponentCount) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %float_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Component Count must be OpConstant with a 32- or " - "64-bits integer scalar type or DebugGlobalVariable or " - "DebugLocalVariable with a 32- or 64-bits unsigned " - "integer scalar type")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailComponentCountFloat) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %f32_4 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Component Count must be OpConstant with a 32- or " - "64-bits integer scalar type or DebugGlobalVariable or " - "DebugLocalVariable with a 32- or 64-bits unsigned " - "integer scalar type")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailComponentCountZero) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %u32_0 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Component Count must be OpConstant with a 32- or " - "64-bits integer scalar type or DebugGlobalVariable or " - "DebugLocalVariable with a 32- or 64-bits unsigned " - "integer scalar type")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArrayFailVariableSizeTypeFloat) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -%main_name = OpString "main" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 1 %main_info FlagIsLocal -%float_arr_info = OpExtInst %void %DbgExt DebugTypeArray %float_info %foo_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Component Count must be OpConstant with a 32- or " - "64-bits integer scalar type or DebugGlobalVariable or " - "DebugLocalVariable with a 32- or 64-bits unsigned " - "integer scalar type")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVector) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVectorFail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %dbg_src 4 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVectorFailComponentZero) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %dbg_src 0 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeVectorFailComponentFive) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%vfloat_info = OpExtInst %void %DbgExt DebugTypeVector %dbg_src 5 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypedef) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo_info = OpExtInst %void %DbgExt DebugTypedef %foo_name %float_info %dbg_src 1 1 %comp_unit -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugTypedef, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo_info = OpExtInst %void %DbgExt DebugTypedef )"; - ss << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), - "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second + - " must be a result id of ")); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypedef, - ::testing::ValuesIn(std::vector>{ - std::make_pair(R"(%dbg_src %float_info %dbg_src 1 1 %comp_unit)", - "Name"), - std::make_pair(R"(%foo_name %dbg_src %dbg_src 1 1 %comp_unit)", - "Base Type"), - std::make_pair(R"(%foo_name %float_info %comp_unit 1 1 %comp_unit)", - "Source"), - std::make_pair(R"(%foo_name %float_info %dbg_src 1 1 %dbg_src)", - "Parent"), - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeFunction) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%main_type_info1 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_type_info2 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %float_info -%main_type_info3 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %float_info %float_info -%main_type_info4 = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void %float_info %float_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeFunctionFailReturn) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %dbg_src %float_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("expected operand Return Type is not a valid debug type")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeFunctionFailParam) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -%float_name = OpString "float" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %float_info %void -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("expected operand Parameter Types is not a valid debug type")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeEnum) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%none = OpExtInst %void %DbgExt DebugInfoNone -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo_info1 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name %u32_1 %foo_name -%foo_info2 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %none %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name %u32_1 %foo_name -%foo_info3 = OpExtInst %void %DbgExt DebugTypeEnum %foo_name %none %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugTypeEnum, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo_info = OpExtInst %void %DbgExt DebugTypeEnum )"; - ss << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), - "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeEnum, - ::testing::ValuesIn(std::vector>{ - std::make_pair( - R"(%dbg_src %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name)", - "Name"), - std::make_pair( - R"(%foo_name %dbg_src %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name)", - "Underlying Types"), - std::make_pair( - R"(%foo_name %float_info %comp_unit 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %foo_name)", - "Source"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 1 1 %dbg_src %int_32 FlagIsPublic %u32_0 %foo_name)", - "Parent"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %void FlagIsPublic %u32_0 %foo_name)", - "Size"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %u32_0 FlagIsPublic %u32_0 %foo_name)", - "Size"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %foo_name %foo_name)", - "Value"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 1 1 %comp_unit %int_32 FlagIsPublic %u32_0 %u32_1)", - "Name"), - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeFunctionAndInheritance) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float4 pos : SV_POSITION; -}; -struct foo : VS_OUTPUT { -}; -main() {} -" -%VS_OUTPUT_name = OpString "struct VS_OUTPUT" -%float_name = OpString "float" -%foo_name = OpString "foo" -%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" -%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" -%main_name = OpString "main" -%main_linkage_name = OpString "v4f_main_f" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main -%foo_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Structure %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic -%child = OpExtInst %void %DbgExt DebugTypeInheritance %foo_info %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugTypeComposite, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float4 pos : SV_POSITION; -}; -struct foo : VS_OUTPUT { -}; -main() {} -" -%VS_OUTPUT_name = OpString "struct VS_OUTPUT" -%float_name = OpString "float" -%foo_name = OpString "foo" -%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" -%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" -%main_name = OpString "main" -%main_linkage_name = OpString "v4f_main_f" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite )"; - ss << param.first; - ss << R"( -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main -%foo_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Structure %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic -%child = OpExtInst %void %DbgExt DebugTypeInheritance %foo_info %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), - "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second + " must be ")); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeComposite, - ::testing::ValuesIn(std::vector>{ - std::make_pair( - R"(%dbg_src Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", - "Name"), - std::make_pair( - R"(%VS_OUTPUT_name Structure %comp_unit 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", - "Source"), - std::make_pair( - R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %dbg_src %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", - "Parent"), - std::make_pair( - R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %int_128 %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", - "Linkage Name"), - std::make_pair( - R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %dbg_src FlagIsPublic %VS_OUTPUT_pos_info %main_info %child)", - "Size"), - std::make_pair( - R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %dbg_src %main_info %child)", - "Members"), - std::make_pair( - R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %dbg_src %child)", - "Members"), - std::make_pair( - R"(%VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %main_info %dbg_src)", - "Members"), - })); - -TEST_P(ValidateOpenCL100DebugInfoDebugTypeMember, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float pos : SV_POSITION; -}; -main() {} -" -%VS_OUTPUT_name = OpString "struct VS_OUTPUT" -%float_name = OpString "float" -%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" -%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_32 FlagIsPublic %VS_OUTPUT_pos_info -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember )"; - ss << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), - "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - if (!param.second.empty()) { - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second + - " must be a result id of ")); - } -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeMember, - ::testing::ValuesIn(std::vector>{ - std::make_pair( - R"(%dbg_src %float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_32 FlagIsPublic)", - "Name"), - std::make_pair( - R"(%VS_OUTPUT_pos_name %dbg_src %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_32 FlagIsPublic)", - ""), - std::make_pair( - R"(%VS_OUTPUT_pos_name %float_info %float_info 2 3 %VS_OUTPUT_info %u32_0 %int_32 FlagIsPublic)", - "Source"), - std::make_pair( - R"(%VS_OUTPUT_pos_name %float_info %dbg_src 2 3 %float_info %u32_0 %int_32 FlagIsPublic)", - "Parent"), - std::make_pair( - R"(%VS_OUTPUT_pos_name %float_info %dbg_src 2 3 %VS_OUTPUT_info %void %int_32 FlagIsPublic)", - "Offset"), - std::make_pair( - R"(%VS_OUTPUT_pos_name %float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %void FlagIsPublic)", - "Size"), - })); - -TEST_P(ValidateOpenCL100DebugInfoDebugTypeInheritance, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT {}; -struct foo : VS_OUTPUT {}; -" -%VS_OUTPUT_name = OpString "struct VS_OUTPUT" -%foo_name = OpString "foo" -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_name %u32_0 FlagIsPublic %child -%foo_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Structure %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic -%bar_info = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Union %dbg_src 1 1 %comp_unit %foo_name %u32_0 FlagIsPublic -%child = OpExtInst %void %DbgExt DebugTypeInheritance )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugTypeInheritance, - ::testing::ValuesIn(std::vector>{ - std::make_pair(R"(%dbg_src %VS_OUTPUT_info %u32_0 %u32_0 FlagIsPublic)", - "Child must be a result id of"), - std::make_pair(R"(%foo_info %dbg_src %u32_0 %u32_0 FlagIsPublic)", - "Parent must be a result id of"), - std::make_pair( - R"(%bar_info %VS_OUTPUT_info %u32_0 %u32_0 FlagIsPublic)", - "Child must be class or struct debug type"), - std::make_pair(R"(%foo_info %bar_info %u32_0 %u32_0 FlagIsPublic)", - "Parent must be class or struct debug type"), - std::make_pair(R"(%foo_info %VS_OUTPUT_info %void %u32_0 FlagIsPublic)", - "Offset"), - std::make_pair(R"(%foo_info %VS_OUTPUT_info %u32_0 %void FlagIsPublic)", - "Size"), - })); TEST_P(ValidateGlslStd450SqrtLike, Success) { const std::string ext_inst_name = GetParam(); std::ostringstream ss; @@ -2178,1086 +472,6 @@ TEST_P(ValidateGlslStd450SqrtLike, Success) { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionDeclaration) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float4 pos : SV_POSITION; -}; -main() {} -" -%main_name = OpString "main" -%main_linkage_name = OpString "v4f_main_f" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst_header, - "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugFunction, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float4 pos : SV_POSITION; -}; -main() {} -" -%main_name = OpString "main" -%main_linkage_name = OpString "v4f_main_f" -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic -%main_info = OpExtInst %void %DbgExt DebugFunction )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugFunction, - ::testing::ValuesIn(std::vector>{ - std::make_pair( - R"(%u32_0 %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)", - "Name"), - std::make_pair( - R"(%main_name %dbg_src %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)", - "Type"), - std::make_pair( - R"(%main_name %main_type_info %comp_unit 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main)", - "Source"), - std::make_pair( - R"(%main_name %main_type_info %dbg_src 12 1 %dbg_src %main_linkage_name FlagIsPublic 13 %main)", - "Parent"), - std::make_pair( - R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %void FlagIsPublic 13 %main)", - "Linkage Name"), - std::make_pair( - R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %void)", - "Function"), - std::make_pair( - R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main %dbg_src)", - "Declaration"), - })); - -TEST_P(ValidateOpenCL100DebugInfoDebugFunctionDeclaration, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "struct VS_OUTPUT { - float4 pos : SV_POSITION; -}; -main() {} -" -%main_name = OpString "main" -%main_linkage_name = OpString "v4f_main_f" -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_decl = OpExtInst %void %DbgExt DebugFunctionDeclaration )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, - ValidateOpenCL100DebugInfoDebugFunctionDeclaration, - ::testing::ValuesIn(std::vector>{ - std::make_pair( - R"(%u32_0 %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic)", - "Name"), - std::make_pair( - R"(%main_name %dbg_src %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic)", - "Type"), - std::make_pair( - R"(%main_name %main_type_info %comp_unit 12 1 %comp_unit %main_linkage_name FlagIsPublic)", - "Source"), - std::make_pair( - R"(%main_name %main_type_info %dbg_src 12 1 %dbg_src %main_linkage_name FlagIsPublic)", - "Parent"), - std::make_pair( - R"(%main_name %main_type_info %dbg_src 12 1 %comp_unit %void FlagIsPublic)", - "Linkage Name"), - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugLexicalBlock) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%main_name = OpString "main" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_block = OpExtInst %void %DbgExt DebugLexicalBlock %dbg_src 1 1 %comp_unit %main_name)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst_header, - "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugLexicalBlock, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "main() {}" -%main_name = OpString "main" -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_block = OpExtInst %void %DbgExt DebugLexicalBlock )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", ss.str(), "", - extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugLexicalBlock, - ::testing::ValuesIn(std::vector>{ - std::make_pair(R"(%comp_unit 1 1 %comp_unit %main_name)", "Source"), - std::make_pair(R"(%dbg_src 1 1 %dbg_src %main_name)", "Parent"), - std::make_pair(R"(%dbg_src 1 1 %comp_unit %void)", "Name"), - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugScopeFailScope) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %dbg_src -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Scope")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugScopeFailInlinedAt) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %comp_unit %dbg_src -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Inlined At")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugLocalVariable) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() { float foo; }" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugLocalVariable, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() { float foo; }" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo = OpExtInst %void %DbgExt DebugLocalVariable )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), - "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugLocalVariable, - ::testing::ValuesIn(std::vector>{ - std::make_pair( - R"(%void %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0)", - "Name"), - std::make_pair( - R"(%foo_name %dbg_src %dbg_src 1 10 %comp_unit FlagIsLocal 0)", - "Type"), - std::make_pair( - R"(%foo_name %float_info %comp_unit 1 10 %comp_unit FlagIsLocal 0)", - "Source"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 1 10 %dbg_src FlagIsLocal 0)", - "Parent"), - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugDeclare) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() { float foo; }" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%null_expr = OpExtInst %void %DbgExt DebugExpression -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 -)"; - - const std::string body = R"( -%foo = OpVariable %f32_ptr_function Function -%decl = OpExtInst %void %DbgExt DebugDeclare %foo_info %foo %null_expr -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugDeclareParam) { - CompileSuccessfully(R"( - OpCapability Shader - %1 = OpExtInstImport "OpenCL.DebugInfo.100" - OpMemoryModel Logical GLSL450 - OpEntryPoint Vertex %main "main" %in_var_COLOR - %4 = OpString "test.hlsl" - OpSource HLSL 620 %4 "#line 1 \"test.hlsl\" -void main(float foo:COLOR) {} -" - %11 = OpString "#line 1 \"test.hlsl\" -void main(float foo:COLOR) {} -" - %14 = OpString "float" - %17 = OpString "src.main" - %20 = OpString "foo" - OpName %in_var_COLOR "in.var.COLOR" - OpName %main "main" - OpName %param_var_foo "param.var.foo" - OpName %src_main "src.main" - OpName %foo "foo" - OpName %bb_entry "bb.entry" - OpDecorate %in_var_COLOR Location 0 - %uint = OpTypeInt 32 0 - %uint_32 = OpConstant %uint 32 - %float = OpTypeFloat 32 -%_ptr_Input_float = OpTypePointer Input %float - %void = OpTypeVoid - %23 = OpTypeFunction %void -%_ptr_Function_float = OpTypePointer Function %float - %29 = OpTypeFunction %void %_ptr_Function_float - OpLine %4 1 21 -%in_var_COLOR = OpVariable %_ptr_Input_float Input - %10 = OpExtInst %void %1 DebugExpression - %12 = OpExtInst %void %1 DebugSource %4 %11 - %13 = OpExtInst %void %1 DebugCompilationUnit 1 4 %12 HLSL - %15 = OpExtInst %void %1 DebugTypeBasic %14 %uint_32 Float - %16 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %void %15 - %18 = OpExtInst %void %1 DebugFunction %17 %16 %12 1 1 %13 %17 FlagIsProtected|FlagIsPrivate 1 %src_main - %21 = OpExtInst %void %1 DebugLocalVariable %20 %15 %12 1 17 %18 FlagIsLocal 0 - %22 = OpExtInst %void %1 DebugLexicalBlock %12 1 28 %18 - OpLine %4 1 1 - %main = OpFunction %void None %23 - %24 = OpLabel - OpLine %4 1 17 -%param_var_foo = OpVariable %_ptr_Function_float Function - %27 = OpLoad %float %in_var_COLOR - OpLine %4 1 1 - %28 = OpFunctionCall %void %src_main %param_var_foo - OpReturn - OpFunctionEnd - %src_main = OpFunction %void None %29 - OpLine %4 1 17 - %foo = OpFunctionParameter %_ptr_Function_float - %31 = OpExtInst %void %1 DebugDeclare %21 %foo %10 - %bb_entry = OpLabel - OpLine %4 1 29 - OpReturn - OpFunctionEnd -)"); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugDeclare, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() { float foo; }" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%null_expr = OpExtInst %void %DbgExt DebugExpression -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%foo = OpVariable %f32_ptr_function Function -%decl = OpExtInst %void %DbgExt DebugDeclare )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, ss.str(), extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugDeclare, - ::testing::ValuesIn(std::vector>{ - std::make_pair(R"(%dbg_src %foo %null_expr)", "Local Variable"), - std::make_pair(R"(%foo_info %void %null_expr)", "Variable"), - std::make_pair(R"(%foo_info %foo %dbg_src)", "Expression"), - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugExpression) { - const std::string dbg_inst_header = R"( -%op0 = OpExtInst %void %DbgExt DebugOperation Deref -%op1 = OpExtInst %void %DbgExt DebugOperation Plus -%null_expr = OpExtInst %void %DbgExt DebugExpression %op0 %op1 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo("", "", dbg_inst_header, - "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugExpressionFail) { - const std::string dbg_inst_header = R"( -%op = OpExtInst %void %DbgExt DebugOperation Deref -%null_expr = OpExtInst %void %DbgExt DebugExpression %op %void -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo("", "", dbg_inst_header, - "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "expected operand Operation must be a result id of DebugOperation")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplate) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "OpaqueType foo; -main() {} -" -%float_name = OpString "float" -%ty_name = OpString "Texture" -%t_name = OpString "T" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_none = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name Class %dbg_src 1 1 %comp_unit %ty_name %dbg_none FlagIsPublic -%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 -%temp = OpExtInst %void %DbgExt DebugTypeTemplate %opaque %param -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateUsedForVariableType) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "OpaqueType foo; -main() {} -" -%float_name = OpString "float" -%ty_name = OpString "Texture" -%t_name = OpString "T" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_none = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%opaque = OpExtInst %void %DbgExt DebugTypeComposite %ty_name Class %dbg_src 1 1 %comp_unit %ty_name %dbg_none FlagIsPublic -%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 -%temp = OpExtInst %void %DbgExt DebugTypeTemplate %opaque %param -%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %temp %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateFunction) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "OpaqueType foo; -main() {} -" -%float_name = OpString "float" -%ty_name = OpString "Texture" -%t_name = OpString "T" -%main_name = OpString "main" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_none = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %param %param -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main -%temp = OpExtInst %void %DbgExt DebugTypeTemplate %main_info %param -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateFailTarget) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "OpaqueType foo; -main() {} -" -%float_name = OpString "float" -%ty_name = OpString "Texture" -%t_name = OpString "T" -%main_name = OpString "main" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_none = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 -%temp = OpExtInst %void %DbgExt DebugTypeTemplate %float_info %param -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Target must be DebugTypeComposite or " - "DebugFunction")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugTypeTemplateFailParam) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "OpaqueType foo; -main() {} -" -%float_name = OpString "float" -%ty_name = OpString "Texture" -%t_name = OpString "T" -%main_name = OpString "main" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -%int_128 = OpConstant %u32 128 -)"; - - const std::string dbg_inst_header = R"( -%dbg_none = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%param = OpExtInst %void %DbgExt DebugTypeTemplateParameter %t_name %float_info %dbg_none %dbg_src 0 0 -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %param %param -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_name FlagIsPublic 1 %main -%temp = OpExtInst %void %DbgExt DebugTypeTemplate %main_info %float_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "expected operand Parameters must be DebugTypeTemplateParameter or " - "DebugTypeTemplateTemplateParameter")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariable) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float foo; void main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariableStaticMember) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float foo; void main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%t = OpExtInst %void %DbgExt DebugTypeComposite %foo_name Class %dbg_src 0 0 %comp_unit %foo_name %int_32 FlagIsPublic %a -%a = OpExtInst %void %DbgExt DebugTypeMember %foo_name %float_info %dbg_src 0 0 %t %u32_0 %int_32 FlagIsPublic -%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate %a -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariableDebugInfoNone) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float foo; void main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbgNone = OpExtInst %void %DbgExt DebugInfoNone -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %dbgNone FlagIsProtected|FlagIsPrivate -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugGlobalVariableConst) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float foo; void main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo = OpExtInst %void %DbgExt DebugGlobalVariable %foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %int_32 FlagIsProtected|FlagIsPrivate -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, "", extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugGlobalVariable, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "float foo; void main() {}" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo = OpExtInst %void %DbgExt DebugGlobalVariable )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, size_const, ss.str(), - "", extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugGlobalVariable, - ::testing::ValuesIn(std::vector>{ - std::make_pair( - R"(%void %float_info %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", - "Name"), - std::make_pair( - R"(%foo_name %dbg_src %dbg_src 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", - "Type"), - std::make_pair( - R"(%foo_name %float_info %comp_unit 0 0 %comp_unit %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", - "Source"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 0 0 %dbg_src %foo_name %f32_input FlagIsProtected|FlagIsPrivate)", - "Scope"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 0 0 %comp_unit %void %f32_input FlagIsProtected|FlagIsPrivate)", - "Linkage Name"), - std::make_pair( - R"(%foo_name %float_info %dbg_src 0 0 %comp_unit %foo_name %void FlagIsProtected|FlagIsPrivate)", - "Variable"), - })); - -TEST_F(ValidateOpenCL100DebugInfo, DebugInlinedAt) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -%void_name = OpString "void" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main -%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info -%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info %inlined_at -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugInlinedAtFail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -%void_name = OpString "void" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main -%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info -%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt 0 %inlined_at -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Scope")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugInlinedAtFail2) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() {}" -%void_name = OpString "void" -%main_name = OpString "main" -%main_linkage_name = OpString "v_main" -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void -%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main -%inlined_at = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info -%inlined_at_recursive = OpExtInst %void %DbgExt DebugInlinedAt 0 %main_info %main_info -)"; - - const std::string body = R"( -%main_scope = OpExtInst %void %DbgExt DebugScope %main_info %inlined_at -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, "", dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("expected operand Inlined")); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugValue) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() { float foo; }" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_3 = OpConstant %u32 3 -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%null_expr = OpExtInst %void %DbgExt DebugExpression -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %v4float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 -)"; - - const std::string body = R"( -%value = OpExtInst %void %DbgExt DebugValue %foo_info %int_32 %null_expr %int_3 -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_F(ValidateOpenCL100DebugInfo, DebugValueWithVariableIndex) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() { float foo; }" -%float_name = OpString "float" -%int_name = OpString "int" -%foo_name = OpString "foo" -%len_name = OpString "length" -)"; - - const std::string size_const = R"( -%int_3 = OpConstant %u32 3 -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%null_expr = OpExtInst %void %DbgExt DebugExpression -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %int_32 Signed -%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %v4float_info %dbg_src 1 10 %comp_unit FlagIsLocal -%len_info = OpExtInst %void %DbgExt DebugLocalVariable %len_name %int_info %dbg_src 0 0 %comp_unit FlagIsLocal -)"; - - const std::string body = R"( -%value = OpExtInst %void %DbgExt DebugValue %foo_info %int_32 %null_expr %len_info -)"; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, body, extension, "Vertex")); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - -TEST_P(ValidateOpenCL100DebugInfoDebugValue, Fail) { - const std::string src = R"( -%src = OpString "simple.hlsl" -%code = OpString "void main() { float foo; }" -%float_name = OpString "float" -%foo_name = OpString "foo" -)"; - - const std::string size_const = R"( -%int_32 = OpConstant %u32 32 -)"; - - const std::string dbg_inst_header = R"( -%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code -%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL -%null_expr = OpExtInst %void %DbgExt DebugExpression -%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float -%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %float_info %dbg_src 1 10 %comp_unit FlagIsLocal 0 -)"; - - const auto& param = GetParam(); - - std::ostringstream ss; - ss << R"( -%decl = OpExtInst %void %DbgExt DebugValue )" - << param.first; - - const std::string extension = R"( -%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" -)"; - - CompileSuccessfully(GenerateShaderCodeForDebugInfo( - src, size_const, dbg_inst_header, ss.str(), extension, "Vertex")); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand " + param.second)); -} - -INSTANTIATE_TEST_SUITE_P( - AllOpenCL100DebugInfoFail, ValidateOpenCL100DebugInfoDebugValue, - ::testing::ValuesIn(std::vector>{ - std::make_pair(R"(%dbg_src %int_32 %null_expr)", "Local Variable"), - std::make_pair(R"(%foo_info %int_32 %dbg_src)", "Expression"), - std::make_pair(R"(%foo_info %int_32 %null_expr %dbg_src)", "Indexes"), - })); - TEST_P(ValidateGlslStd450SqrtLike, IntResultType) { const std::string ext_inst_name = GetParam(); const std::string body = @@ -3507,6 +721,19 @@ TEST_P(ValidateGlslStd450SAbsLike, WrongBitWidthOperand) { "Result Type")); } +TEST_P(ValidateGlslStd450SAbsLike, TypelessOperand) { + const std::string ext_inst_name = GetParam(); + const std::string body = + "%val1 = OpExtInst %s64 %extinst " + ext_inst_name + " %main_entry\n"; + + CompileSuccessfully(GenerateShaderCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("GLSL.std.450 " + ext_inst_name + + ": expected all operands to be int scalars or vectors")); +} + INSTANTIATE_TEST_SUITE_P(AllSAbsLike, ValidateGlslStd450SAbsLike, ::testing::ValuesIn(std::vector{ "SAbs", @@ -3656,6 +883,19 @@ TEST_P(ValidateGlslStd450UMinLike, WrongBitWidthOperand2) { "Result Type")); } +TEST_P(ValidateGlslStd450UMinLike, TypelessOperand) { + const std::string ext_inst_name = GetParam(); + const std::string body = "%val1 = OpExtInst %s64 %extinst " + ext_inst_name + + " %s64_0 %main_entry\n"; + + CompileSuccessfully(GenerateShaderCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("GLSL.std.450 " + ext_inst_name + + ": expected all operands to be int scalars or vectors")); +} + INSTANTIATE_TEST_SUITE_P(AllUMinLike, ValidateGlslStd450UMinLike, ::testing::ValuesIn(std::vector{ "UMin", @@ -3819,6 +1059,19 @@ TEST_P(ValidateGlslStd450UClampLike, WrongBitWidthOperand3) { "Result Type")); } +TEST_P(ValidateGlslStd450UClampLike, TypelessOperand) { + const std::string ext_inst_name = GetParam(); + const std::string body = "%val1 = OpExtInst %s64 %extinst " + ext_inst_name + + " %main_entry %s64_0 %s64_0\n"; + + CompileSuccessfully(GenerateShaderCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("GLSL.std.450 " + ext_inst_name + + ": expected all operands to be int scalars or vectors")); +} + INSTANTIATE_TEST_SUITE_P(AllUClampLike, ValidateGlslStd450UClampLike, ::testing::ValuesIn(std::vector{ "UClamp", @@ -4327,6 +1580,19 @@ TEST_F(ValidateExtInst, GlslStd450LdexpExpWrongSize) { "number as Result Type")); } +TEST_F(ValidateExtInst, GlslStd450LdexpExpNoType) { + const std::string body = R"( +%val1 = OpExtInst %f32 %extinst Ldexp %f32_1 %main_entry +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("GLSL.std.450 Ldexp: " + "expected operand Exp to be a 32-bit int scalar " + "or vector type")); +} + TEST_F(ValidateExtInst, GlslStd450FrexpStructSuccess) { const std::string body = R"( %val1 = OpExtInst %struct_f32_u32 %extinst FrexpStruct %f32_h @@ -5552,7 +2818,8 @@ TEST_F(ValidateExtInst, GlslStd450InterpolateAtOffsetInternalInvalidDataF32) { "expected Interpolant to be a pointer")); } -TEST_F(ValidateExtInst, GlslStd450InterpolateAtOffsetInternalInvalidDataF32Vec2) { +TEST_F(ValidateExtInst, + GlslStd450InterpolateAtOffsetInternalInvalidDataF32Vec2) { const std::string body = R"( %ld2 = OpLoad %f32vec2 %f32vec2_input %val2 = OpExtInst %f32vec2 %extinst InterpolateAtOffset %ld2 %f32vec2_01 diff --git a/third_party/spirv-tools/test/val/val_id_test.cpp b/third_party/spirv-tools/test/val/val_id_test.cpp index dd4c952cf9..ac05749333 100644 --- a/third_party/spirv-tools/test/val/val_id_test.cpp +++ b/third_party/spirv-tools/test/val/val_id_test.cpp @@ -5524,9 +5524,9 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpDecorate SpecId decoration target " - "'1[%uint_3]' is not a scalar specialization " - "constant.")); + HasSubstr("SpecId decoration on target " + "'1[%uint_3]' must be a scalar specialization " + "constant")); } TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantOpBad) { @@ -5546,8 +5546,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpDecorate SpecId decoration target '1[%1]' is " - "not a scalar specialization constant.")); + HasSubstr("SpecId decoration on target '1[%1]' " + "must be a scalar specialization constant")); } TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantCompositeBad) { @@ -5566,8 +5566,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpDecorate SpecId decoration target '1[%1]' is " - "not a scalar specialization constant.")); + HasSubstr("SpecId decoration on target '1[%1]' " + "must be a scalar specialization constant")); } TEST_F(ValidateIdWithMessage, SpecIdTargetGood) { diff --git a/third_party/spirv-tools/test/val/val_image_test.cpp b/third_party/spirv-tools/test/val/val_image_test.cpp index 701e35e132..11b14fb0ca 100644 --- a/third_party/spirv-tools/test/val/val_image_test.cpp +++ b/third_party/spirv-tools/test/val/val_image_test.cpp @@ -1815,9 +1815,10 @@ TEST_F(ValidateImage, SampleImplicitLodMoreThanOneOffset) { CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets " - "cannot be used together")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets, Offsets " + "cannot be used together")); } TEST_F(ValidateImage, SampleImplicitLodVulkanMoreThanOneOffset) { @@ -1833,9 +1834,10 @@ TEST_F(ValidateImage, SampleImplicitLodVulkanMoreThanOneOffset) { ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-StandaloneSpirv-Offset-04662")); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets " - "cannot be used together")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets, Offsets " + "cannot be used together")); } TEST_F(ValidateImage, SampleImplicitLodMinLodWrongType) { @@ -6061,6 +6063,42 @@ TEST_F(ValidateImage, ImageTexelPointerRgba16fVulkan) { "R32f, R32i, or R32ui for Vulkan environment")); } +TEST_F(ValidateImage, ImageExecutionModeLimitationNoMode) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %2 " " %4 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%12 = OpTypeImage %float 2D 0 0 0 1 Rgba8ui +%13 = OpTypeSampledImage %12 +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%5 = OpVariable %_ptr_UniformConstant_13 UniformConstant +%_ptr_Input_v4float = OpTypePointer Input %v4float +%4 = OpVariable %_ptr_Input_v4float Input +%v2float = OpTypeVector %float 2 +%float_1_35631564en19 = OpConstant %float 1.35631564e-19 +%2 = OpFunction %void None %8 +%8224 = OpLabel +%6 = OpLoad %13 %5 +%19 = OpLoad %v4float %4 +%20 = OpVectorShuffle %v2float %19 %19 0 1 +%21 = OpVectorTimesScalar %v2float %20 %float_1_35631564en19 +%65312 = OpImageSampleImplicitLod %v4float %6 %21 +OpUnreachable +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ImplicitLod instructions require " + "DerivativeGroupQuadsNV or DerivativeGroupLinearNV " + "execution mode for GLCompute execution model")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_interfaces_test.cpp b/third_party/spirv-tools/test/val/val_interfaces_test.cpp index 6869e79445..a01fc19b69 100644 --- a/third_party/spirv-tools/test/val/val_interfaces_test.cpp +++ b/third_party/spirv-tools/test/val/val_interfaces_test.cpp @@ -1267,10 +1267,9 @@ OpFunctionEnd )"; CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Index can only be applied to Fragment output variables")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be in the Output storage class")); } TEST_F(ValidateInterfacesTest, VulkanLocationsArrayWithComponent) { @@ -1410,6 +1409,93 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); } +TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent1) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %in +OpExecutionMode %main OriginUpperLeft +OpDecorate %struct Block +OpMemberDecorate %struct 0 Location 0 +OpMemberDecorate %struct 0 Component 0 +OpMemberDecorate %struct 1 Location 0 +OpMemberDecorate %struct 1 Component 1 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%float_arr = OpTypeArray %float %int_2 +%struct = OpTypeStruct %float_arr %float_arr +%ptr = OpTypePointer Input %struct +%in = OpVariable %ptr Input +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent2) { + const std::string text = R"( +OpCapability Shader +OpCapability Float64 +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %in +OpExecutionMode %main OriginUpperLeft +OpDecorate %struct Block +OpMemberDecorate %struct 0 Location 0 +OpMemberDecorate %struct 0 Component 0 +OpMemberDecorate %struct 1 Location 0 +OpMemberDecorate %struct 1 Component 1 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%float = OpTypeFloat 32 +%double = OpTypeFloat 64 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%double_arr = OpTypeArray %double %int_2 +%struct = OpTypeStruct %float %double_arr +%ptr = OpTypePointer Input %struct +%in = OpVariable %ptr Input +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateInterfacesTest, DuplicateInterfaceVariableSuccess) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %in %out %in +OpExecutionMode %main OriginUpperLeft +OpDecorate %in Location 0 +OpDecorate %out Location 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%in_ptr = OpTypePointer Input %float +%out_ptr = OpTypePointer Output %float +%in = OpVariable %in_ptr Input +%out = OpVariable %out_ptr Output +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_layout_test.cpp b/third_party/spirv-tools/test/val/val_layout_test.cpp index d34c97f9cf..7ebd7c0084 100644 --- a/third_party/spirv-tools/test/val/val_layout_test.cpp +++ b/third_party/spirv-tools/test/val/val_layout_test.cpp @@ -538,7 +538,6 @@ TEST_F(ValidateLayout, ModuleProcessedInvalidIn10) { OpMemoryModel Logical GLSL450 OpName %void "void" OpModuleProcessed "this is ok in 1.1 and later" - OpDecorate %void Volatile ; bogus, but makes the example short %void = OpTypeVoid )"; @@ -558,7 +557,6 @@ TEST_F(ValidateLayout, ModuleProcessedValidIn11) { OpMemoryModel Logical GLSL450 OpName %void "void" OpModuleProcessed "this is ok in 1.1 and later" - OpDecorate %void Volatile ; bogus, but makes the example short %void = OpTypeVoid )"; diff --git a/third_party/spirv-tools/test/val/val_memory_test.cpp b/third_party/spirv-tools/test/val/val_memory_test.cpp index 9799b404b0..2a884c4da5 100644 --- a/third_party/spirv-tools/test/val/val_memory_test.cpp +++ b/third_party/spirv-tools/test/val/val_memory_test.cpp @@ -746,7 +746,7 @@ TEST_F(ValidateMemory, ArrayLenIndexNotPointerToStruct) { %float = OpTypeFloat 32 %uint = OpTypeInt 32 0 %_runtimearr_float = OpTypeRuntimeArray %float - %_struct_7 = OpTypeStruct %float %_runtimearr_float + %_struct_7 = OpTypeStruct %float %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 %1 = OpFunction %void None %3 %9 = OpLabel @@ -2344,11 +2344,12 @@ OpExtension "SPV_EXT_descriptor_indexing" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" OpExecutionMode %func OriginUpperLeft -OpDecorate %array_t Block +OpDecorate %struct Block %uint_t = OpTypeInt 32 0 %inner_array_t = OpTypeRuntimeArray %uint_t %array_t = OpTypeRuntimeArray %inner_array_t -%array_ptr = OpTypePointer StorageBuffer %array_t +%struct = OpTypeStruct %array_t +%array_ptr = OpTypePointer StorageBuffer %struct %2 = OpVariable %array_ptr StorageBuffer %void = OpTypeVoid %func_t = OpTypeFunction %void @@ -2504,13 +2505,14 @@ OpExtension "SPV_EXT_descriptor_indexing" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" OpExecutionMode %func OriginUpperLeft -OpDecorate %array_t Block +OpDecorate %struct Block %uint_t = OpTypeInt 32 0 %dim = OpConstant %uint_t 1 %sampler_t = OpTypeSampler %inner_array_t = OpTypeRuntimeArray %uint_t %array_t = OpTypeRuntimeArray %inner_array_t -%array_ptr = OpTypePointer StorageBuffer %array_t +%struct = OpTypeStruct %array_t +%array_ptr = OpTypePointer StorageBuffer %struct %2 = OpVariable %array_ptr StorageBuffer %void = OpTypeVoid %func_t = OpTypeFunction %void @@ -4284,6 +4286,117 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } +TEST_F(ValidateMemory, LoadRuntimeArray) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%rta = OpTypeRuntimeArray %int +%block = OpTypeStruct %rta +%ptr_rta = OpTypePointer StorageBuffer %rta +%ptr_block = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_block StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_rta %var %int_0 +%ld = OpLoad %rta %gep +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot load a runtime-sized array")); +} + +TEST_F(ValidateMemory, LoadRuntimeArrayInStruct) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%rta = OpTypeRuntimeArray %int +%block = OpTypeStruct %rta +%ptr_rta = OpTypePointer StorageBuffer %rta +%ptr_block = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_block StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpLoad %block %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot load a runtime-sized array")); +} + +TEST_F(ValidateMemory, LoadRuntimeArrayInArray) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_4 = OpConstant %int 4 +%rta = OpTypeRuntimeArray %int +%block = OpTypeStruct %rta +%array = OpTypeArray %block %int_4 +%ptr_rta = OpTypePointer StorageBuffer %rta +%ptr_block = OpTypePointer StorageBuffer %block +%ptr_array = OpTypePointer StorageBuffer %array +%var = OpVariable %ptr_array StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpLoad %array %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot load a runtime-sized array")); +} + +TEST_F(ValidateMemory, Pre1p4WorkgroupMemoryBadLayoutOk) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%bool = OpTypeBool +%struct = OpTypeStruct %bool +%ptr = OpTypePointer Workgroup %struct +%var = OpVariable %ptr Workgroup +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_modes_test.cpp b/third_party/spirv-tools/test/val/val_modes_test.cpp index 99f5c9cfae..02a61327e9 100644 --- a/third_party/spirv-tools/test/val/val_modes_test.cpp +++ b/third_party/spirv-tools/test/val/val_modes_test.cpp @@ -63,12 +63,13 @@ OpEntryPoint GLCompute %main "main" CompileSuccessfully(spirv, env); EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-LocalSize-04683")); + AnyVUID("VUID-StandaloneSpirv-LocalSize-06426")); EXPECT_THAT( getDiagnosticString(), - HasSubstr("In the Vulkan environment, GLCompute execution model entry " - "points require either the LocalSize execution mode or an " - "object decorated with WorkgroupSize must be specified.")); + HasSubstr( + "In the Vulkan environment, GLCompute execution model entry " + "points require either the LocalSize or LocalSizeId execution mode " + "or an object decorated with WorkgroupSize must be specified.")); } TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) { @@ -101,6 +102,40 @@ OpExecutionMode %main LocalSize 1 1 1 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); } +TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdBad) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_VULKAN_1_1; // need SPIR-V 1.2 + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("LocalSizeId mode is not allowed by the current environment.")); +} + +TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdGood) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_VULKAN_1_1; // need SPIR-V 1.2 + CompileSuccessfully(spirv, env); + spvValidatorOptionsSetAllowLocalSizeId(getValidatorOptions(), true); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) { const std::string spirv = R"( OpCapability Shader @@ -672,7 +707,7 @@ INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution, Values("Kernel"), Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff", - "LocalSizeHintId %int1"), + "LocalSizeHintId %int1 %int1 %int1"), Values(SPV_ENV_UNIVERSAL_1_3))); INSTANTIATE_TEST_SUITE_P( @@ -684,7 +719,7 @@ INSTANTIATE_TEST_SUITE_P( Values("Geometry", "TessellationControl", "TessellationEvaluation", "GLCompute", "Vertex", "Fragment"), Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff", - "LocalSizeHintId %int1"), + "LocalSizeHintId %int1 %int1 %int1"), Values(SPV_ENV_UNIVERSAL_1_3))); INSTANTIATE_TEST_SUITE_P( @@ -863,7 +898,7 @@ OpCapability Kernel OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Kernel %main "main" -OpExecutionMode %main LocalSizeHintId %int_1 +OpExecutionMode %main LocalSizeHintId %int_1 %int_1 %int_1 %int = OpTypeInt 32 0 %int_1 = OpConstant %int 1 )" + kVoidFunction; @@ -882,7 +917,7 @@ OpCapability Kernel OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Kernel %main "main" -OpExecutionModeId %main LocalSizeHintId %int_1 +OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1 %int = OpTypeInt 32 0 %int_1 = OpConstant %int 1 )" + kVoidFunction; @@ -898,7 +933,7 @@ OpCapability Kernel OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %main "main" -OpExecutionModeId %main LocalSizeHintId %int_1 +OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1 %int = OpTypeInt 32 0 %int_ptr = OpTypePointer Private %int %int_1 = OpVariable %int_ptr Private diff --git a/third_party/spirv-tools/test/wasm/test.js b/third_party/spirv-tools/test/wasm/test.js new file mode 100644 index 0000000000..7f0d8f3cf8 --- /dev/null +++ b/third_party/spirv-tools/test/wasm/test.js @@ -0,0 +1,64 @@ +// Copyright (c) 2020 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. + +const spirvTools = require("../../out/web/spirv-tools"); +const fs = require("fs"); +const util = require("util"); +const readFile = util.promisify(fs.readFile); + +const SPV_PATH = "./test/fuzzers/corpora/spv/simple.spv"; + +const test = async () => { + const spv = await spirvTools(); + + // disassemble from file + const buffer = await readFile(SPV_PATH); + const disFileResult = spv.dis( + buffer, + spv.SPV_ENV_UNIVERSAL_1_3, + spv.SPV_BINARY_TO_TEXT_OPTION_INDENT | + spv.SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | + spv.SPV_BINARY_TO_TEXT_OPTION_COLOR + ); + console.log("dis from file:\n", disFileResult); + + // assemble + const source = ` + OpCapability Linkage + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpSource GLSL 450 + OpDecorate %spec SpecId 1 + %int = OpTypeInt 32 1 + %spec = OpSpecConstant %int 0 + %const = OpConstant %int 42`; + const asResult = spv.as( + source, + spv.SPV_ENV_UNIVERSAL_1_3, + spv.SPV_TEXT_TO_BINARY_OPTION_NONE + ); + console.log(`as returned ${asResult.byteLength} bytes`); + + // re-disassemble + const disResult = spv.dis( + asResult, + spv.SPV_ENV_UNIVERSAL_1_3, + spv.SPV_BINARY_TO_TEXT_OPTION_INDENT | + spv.SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | + spv.SPV_BINARY_TO_TEXT_OPTION_COLOR + ); + console.log("dis:\n", disResult); +}; + +test(); diff --git a/third_party/spirv-tools/tools/CMakeLists.txt b/third_party/spirv-tools/tools/CMakeLists.txt index 124a33281a..6039089a07 100644 --- a/third_party/spirv-tools/tools/CMakeLists.txt +++ b/third_party/spirv-tools/tools/CMakeLists.txt @@ -48,6 +48,7 @@ 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_FULL_VISIBILITY}) endif() add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-lint SRCS lint/lint.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-lint SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) add_spvtools_tool(TARGET spirv-cfg SRCS cfg/cfg.cpp cfg/bin_to_dot.h @@ -56,7 +57,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) target_include_directories(spirv-cfg PRIVATE ${spirv-tools_SOURCE_DIR} ${SPIRV_HEADER_INCLUDE_DIR}) set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt - spirv-cfg spirv-link) + spirv-cfg spirv-link spirv-lint) if(NOT DEFINED IOS_PLATFORM) set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-reduce) endif() diff --git a/third_party/spirv-tools/tools/cfg/cfg.cpp b/third_party/spirv-tools/tools/cfg/cfg.cpp index a93488d545..6a5faa18c9 100644 --- a/third_party/spirv-tools/tools/cfg/cfg.cpp +++ b/third_party/spirv-tools/tools/cfg/cfg.cpp @@ -69,16 +69,16 @@ int main(int argc, char** argv) { if (0 == strcmp(argv[argi], "--help")) { print_usage(argv[0]); return 0; - } else if (0 == strcmp(argv[argi], "--version")) { + } + if (0 == strcmp(argv[argi], "--version")) { printf("%s EXPERIMENTAL\n", spvSoftwareVersionDetailsString()); printf("Target: %s\n", spvTargetEnvDescription(kDefaultEnvironment)); return 0; - } else { - print_usage(argv[0]); - return 1; } - } break; + print_usage(argv[0]); + return 1; + } case 0: { // Setting a filename of "-" to indicate stdin. if (!inFile) { diff --git a/third_party/spirv-tools/tools/fuzz/fuzz.cpp b/third_party/spirv-tools/tools/fuzz/fuzz.cpp index 422bea53b1..306f9255b4 100644 --- a/third_party/spirv-tools/tools/fuzz/fuzz.cpp +++ b/third_party/spirv-tools/tools/fuzz/fuzz.cpp @@ -630,7 +630,7 @@ bool Fuzz(const spv_target_env& target_env, std::move(ir_context), std::move(transformation_context), std::move(fuzzer_context), message_consumer, donor_suppliers, fuzzer_options->all_passes_enabled, repeated_pass_strategy, - fuzzer_options->fuzzer_pass_validation_enabled, validator_options); + fuzzer_options->fuzzer_pass_validation_enabled, validator_options, false); auto fuzz_result = fuzzer.Run(0); if (fuzz_result.status == spvtools::fuzz::Fuzzer::Status::kFuzzerPassLedToInvalidModule) { @@ -673,6 +673,19 @@ void DumpTransformationsBinary( transformations_file.close(); } +// The Chromium project applies the following patch to the protobuf library: +// +// source.chromium.org/chromium/chromium/src/+/main:third_party/protobuf/patches/0003-remove-static-initializers.patch +// +// This affects how Status objects must be constructed. This method provides a +// convenient way to get the OK status that works both with and without the +// patch. With the patch OK is a StatusPod, from which a Status can be +// constructed. Without the patch, OK is already a Status, and we harmlessly +// copy-construct the result from it. +google::protobuf::util::Status GetProtobufOkStatus() { + return google::protobuf::util::Status(google::protobuf::util::Status::OK); +} + // Dumps |transformations| to file |filename| in JSON format. Useful for // interactive debugging. void DumpTransformationsJson( @@ -683,7 +696,7 @@ void DumpTransformationsJson( json_options.add_whitespace = true; auto json_generation_status = google::protobuf::util::MessageToJsonString( transformations, &json_string, json_options); - if (json_generation_status == google::protobuf::util::Status::OK) { + if (json_generation_status == GetProtobufOkStatus()) { std::ofstream transformations_json_file(filename); transformations_json_file << json_string; transformations_json_file.close(); @@ -734,9 +747,8 @@ int main(int argc, const char** argv) { 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)) { + if (GetProtobufOkStatus() != google::protobuf::util::JsonStringToMessage( + facts_json_string, &initial_facts)) { spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error reading facts data"); return 1; } @@ -816,7 +828,7 @@ int main(int argc, const char** argv) { 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) { + if (json_generation_status != GetProtobufOkStatus()) { spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error writing out transformations in JSON format"); return 1; diff --git a/third_party/spirv-tools/tools/io.h b/third_party/spirv-tools/tools/io.h index aff9eabd97..83a85c1d1c 100644 --- a/third_party/spirv-tools/tools/io.h +++ b/third_party/spirv-tools/tools/io.h @@ -89,7 +89,7 @@ bool ReadBinaryFile(const char* filename, std::vector* data) { ReadFile(fp, data); bool succeeded = WasFileCorrectlyRead(fp, filename); - if (use_file) fclose(fp); + if (use_file && fp) fclose(fp); return succeeded; } @@ -111,7 +111,7 @@ bool ReadTextFile(const char* filename, std::vector* data) { ReadFile(fp, data); bool succeeded = WasFileCorrectlyRead(fp, filename); - if (use_file) fclose(fp); + if (use_file && fp) fclose(fp); return succeeded; } diff --git a/third_party/spirv-tools/tools/lint/lint.cpp b/third_party/spirv-tools/tools/lint/lint.cpp new file mode 100644 index 0000000000..5c2a82ac1d --- /dev/null +++ b/third_party/spirv-tools/tools/lint/lint.cpp @@ -0,0 +1,75 @@ +// Copyright (c) 2021 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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/opt/log.h" +#include "spirv-tools/linter.hpp" +#include "tools/io.h" +#include "tools/util/cli_consumer.h" + +const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; + +namespace { +// Status and actions to perform after parsing command-line arguments. +enum LintActions { LINT_CONTINUE, LINT_STOP }; + +struct LintStatus { + LintActions action; + int code; +}; + +// Parses command-line flags. |argc| contains the number of command-line flags. +// |argv| points to an array of strings holding the flags. +// +// On return, this function stores the name of the input program in |in_file|. +// The return value indicates whether optimization should continue and a status +// code indicating an error or success. +LintStatus ParseFlags(int argc, const char** argv, const char** in_file) { + // TODO (dongja): actually parse flags, etc. + if (argc != 2) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, nullptr, {}, + "expected exactly one argument: in_file"); + return {LINT_STOP, 1}; + } + + *in_file = argv[1]; + + return {LINT_CONTINUE, 0}; +} +} // namespace + +int main(int argc, const char** argv) { + const char* in_file = nullptr; + + spv_target_env target_env = kDefaultEnvironment; + + spvtools::Linter linter(target_env); + linter.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + + LintStatus status = ParseFlags(argc, argv, &in_file); + + if (status.action == LINT_STOP) { + return status.code; + } + + std::vector binary; + if (!ReadBinaryFile(in_file, &binary)) { + return 1; + } + + bool ok = linter.Run(binary.data(), binary.size()); + + return ok ? 0 : 1; +} diff --git a/third_party/spirv-tools/tools/opt/opt.cpp b/third_party/spirv-tools/tools/opt/opt.cpp index 53bf31d6d9..04f81b8c1a 100644 --- a/third_party/spirv-tools/tools/opt/opt.cpp +++ b/third_party/spirv-tools/tools/opt/opt.cpp @@ -143,6 +143,15 @@ Options (in lexicographical order):)", does not support RelaxedPrecision or ignores it. This pass also removes all RelaxedPrecision decorations.)"); printf(R"( + --convert-to-sampled-image ": ..." + convert images and/or samplers with the given pairs of descriptor + set and binding to sampled images. If a pair of an image and a + sampler have the same pair of descriptor set and binding that is + one of the given pairs, they will be converted to a sampled + image. In addition, if only an image or a sampler has the + descriptor set and binding that is one of the given pairs, it + will be converted to a sampled image.)"); + printf(R"( --copy-propagate-arrays Does propagation of memory references when an array is a copy of another. It will only propagate an array if the source is never @@ -154,6 +163,11 @@ Options (in lexicographical order):)", around known issues with some Vulkan drivers for initialize variables.)"); printf(R"( + --replace-desc-array-access-using-var-index + Replaces accesses to descriptor arrays based on a variable index + with a switch that has a case for every possible value of the + index.)"); + printf(R"( --descriptor-scalar-replacement Replaces every array variable |desc| that has a DescriptorSet and Binding decorations with a new variable for each element of @@ -378,9 +392,12 @@ Options (in lexicographical order):)", Change the scope of private variables that are used in a single function to that function.)"); printf(R"( - --reduce-load-size + --reduce-load-size[=] Replaces loads of composite objects where not every component is - used by loads of just the elements that are used.)"); + used by loads of just the elements that are used. If the ratio + of the used components of the load is less than the , + we replace the load. is a double type number. If + it is bigger than 1.0, we always replaces the load.)"); printf(R"( --redundancy-elimination Looks for instructions in the same function that compute the diff --git a/third_party/spirv-tools/tools/val/val.cpp b/third_party/spirv-tools/tools/val/val.cpp index 21a7d8f435..55321dab28 100644 --- a/third_party/spirv-tools/tools/val/val.cpp +++ b/third_party/spirv-tools/tools/val/val.cpp @@ -64,6 +64,8 @@ Options: --relax-struct-store Allow store from one struct type to a different type with compatible layout and members. + --allow-localsizeid Allow use of the LocalSizeId decoration where it would otherwise not + be allowed by the target environment. --before-hlsl-legalization Allows code patterns that are intended to be fixed by spirv-opt's legalization passes. --version Display validator version information. @@ -153,6 +155,8 @@ int main(int argc, char** argv) { options.SetWorkgroupScalarBlockLayout(true); } else if (0 == strcmp(cur_arg, "--skip-block-layout")) { options.SetSkipBlockLayout(true); + } else if (0 == strcmp(cur_arg, "--allow-localsizeid")) { + options.SetAllowLocalSizeId(true); } else if (0 == strcmp(cur_arg, "--relax-struct-store")) { options.SetRelaxStructStore(true); } else if (0 == cur_arg[1]) { diff --git a/third_party/spirv-tools/utils/roll_deps.sh b/third_party/spirv-tools/utils/roll_deps.sh index 7ecfdd3b35..f61f2a31c8 100755 --- a/third_party/spirv-tools/utils/roll_deps.sh +++ b/third_party/spirv-tools/utils/roll_deps.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright (c) 2019 Google Inc. +# Copyright (c) 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,7 +15,10 @@ # Attempts to roll all entries in DEPS to tip-of-tree and create a commit. # -# Depends on roll-dep from depot_path being in PATH. +# Depends on roll-dep from depot_tools +# (https://chromium.googlesource.com/chromium/tools/depot_tools) being in PATH. + +set -eo pipefail effcee_dir="external/effcee/" effcee_trunk="origin/main" @@ -44,3 +47,4 @@ roll-dep --ignore-dirty-tree --roll-to="${re2_trunk}" "${re2_dir}" roll-dep --ignore-dirty-tree --roll-to="${spirv_headers_trunk}" "${spirv_headers_dir}" git rebase --interactive "${old_head}" +