diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index d03dbba53..594ae7810 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2020.5", "SPIRV-Tools v2020.5 e272a31e19b278158551bc64142947df09ede4ac" +"v2020.5", "SPIRV-Tools v2020.5 86402fec24134b6d4103b6ad1e689fb5840f720f" diff --git a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt deleted file mode 100644 index 905d53572..000000000 --- a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt +++ /dev/null @@ -1,392 +0,0 @@ -# Copyright (c) 2019 Google LLC - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -if(SPIRV_BUILD_FUZZER) - - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protobufs) - - set(PROTOBUF_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/protobufs/spvtoolsfuzz.proto) - - add_custom_command( - OUTPUT protobufs/spvtoolsfuzz.pb.cc protobufs/spvtoolsfuzz.pb.h - COMMAND protobuf::protoc - -I=${CMAKE_CURRENT_SOURCE_DIR}/protobufs - --cpp_out=protobufs - ${PROTOBUF_SOURCE} - DEPENDS ${PROTOBUF_SOURCE} - COMMENT "Generate protobuf sources from proto definition file." - ) - - set(SPIRV_TOOLS_FUZZ_SOURCES - call_graph.h - counter_overflow_id_source.h - data_descriptor.h - equivalence_relation.h - fact_manager/constant_uniform_facts.h - fact_manager/data_synonym_and_id_equation_facts.h - fact_manager/dead_block_facts.h - fact_manager/fact_manager.h - fact_manager/irrelevant_value_facts.h - fact_manager/livesafe_function_facts.h - force_render_red.h - fuzzer.h - fuzzer_context.h - fuzzer_pass.h - fuzzer_pass_add_access_chains.h - fuzzer_pass_add_composite_inserts.h - fuzzer_pass_add_composite_types.h - fuzzer_pass_add_copy_memory.h - fuzzer_pass_add_dead_blocks.h - fuzzer_pass_add_dead_breaks.h - fuzzer_pass_add_dead_continues.h - fuzzer_pass_add_equation_instructions.h - fuzzer_pass_add_function_calls.h - fuzzer_pass_add_global_variables.h - fuzzer_pass_add_image_sample_unused_components.h - fuzzer_pass_add_synonyms.h - fuzzer_pass_add_loads.h - fuzzer_pass_add_local_variables.h - fuzzer_pass_add_loop_preheaders.h - fuzzer_pass_add_no_contraction_decorations.h - fuzzer_pass_add_opphi_synonyms.h - fuzzer_pass_add_parameters.h - fuzzer_pass_add_relaxed_decorations.h - fuzzer_pass_add_stores.h - fuzzer_pass_add_vector_shuffle_instructions.h - fuzzer_pass_adjust_branch_weights.h - fuzzer_pass_adjust_function_controls.h - fuzzer_pass_adjust_loop_controls.h - fuzzer_pass_adjust_memory_operands_masks.h - fuzzer_pass_adjust_selection_controls.h - fuzzer_pass_apply_id_synonyms.h - fuzzer_pass_construct_composites.h - fuzzer_pass_copy_objects.h - fuzzer_pass_donate_modules.h - fuzzer_pass_inline_functions.h - fuzzer_pass_invert_comparison_operators.h - fuzzer_pass_interchange_signedness_of_integer_operands.h - fuzzer_pass_interchange_zero_like_constants.h - fuzzer_pass_make_vector_operations_dynamic.h - fuzzer_pass_merge_blocks.h - fuzzer_pass_obfuscate_constants.h - fuzzer_pass_outline_functions.h - fuzzer_pass_permute_blocks.h - fuzzer_pass_permute_function_parameters.h - fuzzer_pass_permute_instructions.h - fuzzer_pass_permute_phi_operands.h - fuzzer_pass_propagate_instructions_up.h - fuzzer_pass_push_ids_through_variables.h - fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h - fuzzer_pass_replace_copy_memories_with_loads_stores.h - fuzzer_pass_replace_copy_objects_with_stores_loads.h - fuzzer_pass_replace_linear_algebra_instructions.h - fuzzer_pass_replace_loads_stores_with_copy_memories.h - fuzzer_pass_replace_parameter_with_global.h - fuzzer_pass_replace_params_with_struct.h - fuzzer_pass_split_blocks.h - fuzzer_pass_swap_commutable_operands.h - fuzzer_pass_swap_conditional_branch_operands.h - fuzzer_pass_toggle_access_chain_instruction.h - fuzzer_util.h - id_use_descriptor.h - instruction_descriptor.h - instruction_message.h - overflow_id_source.h - protobufs/spirvfuzz_protobufs.h - pseudo_random_generator.h - random_generator.h - replayer.h - shrinker.h - transformation.h - transformation_access_chain.h - transformation_add_constant_boolean.h - transformation_add_constant_composite.h - transformation_add_constant_null.h - transformation_add_constant_scalar.h - transformation_add_copy_memory.h - transformation_add_dead_block.h - transformation_add_dead_break.h - transformation_add_dead_continue.h - transformation_add_function.h - transformation_add_global_undef.h - transformation_add_global_variable.h - transformation_add_image_sample_unused_components.h - transformation_add_local_variable.h - transformation_add_loop_preheader.h - transformation_add_no_contraction_decoration.h - transformation_add_opphi_synonym.h - transformation_add_parameter.h - transformation_add_relaxed_decoration.h - transformation_add_spec_constant_op.h - transformation_add_synonym.h - transformation_add_type_array.h - transformation_add_type_boolean.h - transformation_add_type_float.h - transformation_add_type_function.h - transformation_add_type_int.h - transformation_add_type_matrix.h - transformation_add_type_pointer.h - transformation_add_type_struct.h - transformation_add_type_vector.h - transformation_adjust_branch_weights.h - transformation_composite_construct.h - transformation_composite_extract.h - transformation_composite_insert.h - transformation_compute_data_synonym_fact_closure.h - transformation_context.h - transformation_equation_instruction.h - transformation_function_call.h - transformation_inline_function.h - transformation_invert_comparison_operator.h - transformation_load.h - transformation_make_vector_operation_dynamic.h - transformation_merge_blocks.h - transformation_move_block_down.h - transformation_move_instruction_down.h - transformation_outline_function.h - transformation_permute_function_parameters.h - transformation_permute_phi_operands.h - transformation_propagate_instruction_up.h - transformation_push_id_through_variable.h - transformation_record_synonymous_constants.h - transformation_replace_add_sub_mul_with_carrying_extended.h - transformation_replace_boolean_constant_with_constant_binary.h - transformation_replace_constant_with_uniform.h - transformation_replace_copy_memory_with_load_store.h - transformation_replace_copy_object_with_store_load.h - transformation_replace_id_with_synonym.h - transformation_replace_linear_algebra_instruction.h - transformation_replace_load_store_with_copy_memory.h - transformation_replace_parameter_with_global.h - transformation_replace_params_with_struct.h - transformation_set_function_control.h - transformation_set_loop_control.h - transformation_set_memory_operands_mask.h - transformation_set_selection_control.h - transformation_split_block.h - transformation_store.h - transformation_swap_commutable_operands.h - transformation_swap_conditional_branch_operands.h - transformation_toggle_access_chain_instruction.h - transformation_vector_shuffle.h - uniform_buffer_element_descriptor.h - ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h - - call_graph.cpp - counter_overflow_id_source.cpp - data_descriptor.cpp - fact_manager/constant_uniform_facts.cpp - fact_manager/data_synonym_and_id_equation_facts.cpp - fact_manager/dead_block_facts.cpp - fact_manager/fact_manager.cpp - fact_manager/irrelevant_value_facts.cpp - fact_manager/livesafe_function_facts.cpp - force_render_red.cpp - fuzzer.cpp - fuzzer_context.cpp - fuzzer_pass.cpp - fuzzer_pass_add_access_chains.cpp - fuzzer_pass_add_composite_inserts.cpp - fuzzer_pass_add_composite_types.cpp - fuzzer_pass_add_copy_memory.cpp - fuzzer_pass_add_dead_blocks.cpp - fuzzer_pass_add_dead_breaks.cpp - fuzzer_pass_add_dead_continues.cpp - fuzzer_pass_add_equation_instructions.cpp - fuzzer_pass_add_function_calls.cpp - fuzzer_pass_add_global_variables.cpp - fuzzer_pass_add_image_sample_unused_components.cpp - fuzzer_pass_add_synonyms.cpp - fuzzer_pass_add_loads.cpp - fuzzer_pass_add_local_variables.cpp - fuzzer_pass_add_loop_preheaders.cpp - fuzzer_pass_add_no_contraction_decorations.cpp - fuzzer_pass_add_opphi_synonyms.cpp - fuzzer_pass_add_parameters.cpp - fuzzer_pass_add_relaxed_decorations.cpp - fuzzer_pass_add_stores.cpp - fuzzer_pass_add_vector_shuffle_instructions.cpp - fuzzer_pass_adjust_branch_weights.cpp - fuzzer_pass_adjust_function_controls.cpp - fuzzer_pass_adjust_loop_controls.cpp - fuzzer_pass_adjust_memory_operands_masks.cpp - fuzzer_pass_adjust_selection_controls.cpp - fuzzer_pass_apply_id_synonyms.cpp - fuzzer_pass_construct_composites.cpp - fuzzer_pass_copy_objects.cpp - fuzzer_pass_donate_modules.cpp - fuzzer_pass_inline_functions.cpp - fuzzer_pass_invert_comparison_operators.cpp - fuzzer_pass_interchange_signedness_of_integer_operands.cpp - fuzzer_pass_interchange_zero_like_constants.cpp - fuzzer_pass_make_vector_operations_dynamic.cpp - fuzzer_pass_merge_blocks.cpp - fuzzer_pass_obfuscate_constants.cpp - fuzzer_pass_outline_functions.cpp - fuzzer_pass_permute_blocks.cpp - fuzzer_pass_permute_function_parameters.cpp - fuzzer_pass_permute_instructions.cpp - fuzzer_pass_permute_phi_operands.cpp - fuzzer_pass_propagate_instructions_up.cpp - fuzzer_pass_push_ids_through_variables.cpp - fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp - fuzzer_pass_replace_copy_memories_with_loads_stores.cpp - fuzzer_pass_replace_copy_objects_with_stores_loads.cpp - fuzzer_pass_replace_linear_algebra_instructions.cpp - fuzzer_pass_replace_loads_stores_with_copy_memories.cpp - fuzzer_pass_replace_parameter_with_global.cpp - fuzzer_pass_replace_params_with_struct.cpp - fuzzer_pass_split_blocks.cpp - fuzzer_pass_swap_commutable_operands.cpp - fuzzer_pass_swap_conditional_branch_operands.cpp - fuzzer_pass_toggle_access_chain_instruction.cpp - fuzzer_util.cpp - id_use_descriptor.cpp - instruction_descriptor.cpp - instruction_message.cpp - overflow_id_source.cpp - pseudo_random_generator.cpp - random_generator.cpp - replayer.cpp - shrinker.cpp - transformation.cpp - transformation_access_chain.cpp - transformation_add_constant_boolean.cpp - transformation_add_constant_composite.cpp - transformation_add_constant_null.cpp - transformation_add_constant_scalar.cpp - transformation_add_copy_memory.cpp - transformation_add_dead_block.cpp - transformation_add_dead_break.cpp - transformation_add_dead_continue.cpp - transformation_add_function.cpp - transformation_add_global_undef.cpp - transformation_add_global_variable.cpp - transformation_add_image_sample_unused_components.cpp - transformation_add_local_variable.cpp - transformation_add_loop_preheader.cpp - transformation_add_no_contraction_decoration.cpp - transformation_add_opphi_synonym.cpp - transformation_add_parameter.cpp - transformation_add_relaxed_decoration.cpp - transformation_add_spec_constant_op.cpp - transformation_add_synonym.cpp - transformation_add_type_array.cpp - transformation_add_type_boolean.cpp - transformation_add_type_float.cpp - transformation_add_type_function.cpp - transformation_add_type_int.cpp - transformation_add_type_matrix.cpp - transformation_add_type_pointer.cpp - transformation_add_type_struct.cpp - transformation_add_type_vector.cpp - transformation_adjust_branch_weights.cpp - transformation_composite_construct.cpp - transformation_composite_extract.cpp - transformation_composite_insert.cpp - transformation_compute_data_synonym_fact_closure.cpp - transformation_context.cpp - transformation_equation_instruction.cpp - transformation_function_call.cpp - transformation_inline_function.cpp - transformation_invert_comparison_operator.cpp - transformation_load.cpp - transformation_make_vector_operation_dynamic.cpp - transformation_merge_blocks.cpp - transformation_move_block_down.cpp - transformation_move_instruction_down.cpp - transformation_outline_function.cpp - transformation_permute_function_parameters.cpp - transformation_permute_phi_operands.cpp - transformation_propagate_instruction_up.cpp - transformation_push_id_through_variable.cpp - transformation_record_synonymous_constants.cpp - transformation_replace_add_sub_mul_with_carrying_extended.cpp - transformation_replace_boolean_constant_with_constant_binary.cpp - transformation_replace_constant_with_uniform.cpp - transformation_replace_copy_memory_with_load_store.cpp - transformation_replace_copy_object_with_store_load.cpp - transformation_replace_id_with_synonym.cpp - transformation_replace_linear_algebra_instruction.cpp - transformation_replace_load_store_with_copy_memory.cpp - transformation_replace_parameter_with_global.cpp - transformation_replace_params_with_struct.cpp - transformation_set_function_control.cpp - transformation_set_loop_control.cpp - transformation_set_memory_operands_mask.cpp - transformation_set_selection_control.cpp - transformation_split_block.cpp - transformation_store.cpp - transformation_swap_commutable_operands.cpp - transformation_swap_conditional_branch_operands.cpp - transformation_toggle_access_chain_instruction.cpp - transformation_vector_shuffle.cpp - uniform_buffer_element_descriptor.cpp - ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc - ) - - if(MSVC AND (NOT ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))) - # Enable parallel builds across four cores for this lib - add_definitions(/MP4) - endif() - - spvtools_pch(SPIRV_TOOLS_FUZZ_SOURCES pch_source_fuzz) - - add_library(SPIRV-Tools-fuzz ${SPIRV_TOOLS_FUZZ_SOURCES}) - - spvtools_default_compile_options(SPIRV-Tools-fuzz) - target_compile_definitions(SPIRV-Tools-fuzz PUBLIC -DGOOGLE_PROTOBUF_NO_RTTI -DGOOGLE_PROTOBUF_USE_UNALIGNED=0) - - # Compilation of the auto-generated protobuf source file will yield warnings, - # which we have no control over and thus wish to ignore. - if(${COMPILER_IS_LIKE_GNU}) - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS -w) - endif() - if(MSVC) - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS /w) - endif() - - target_include_directories(SPIRV-Tools-fuzz - PUBLIC - $ - $ - $ - PRIVATE ${spirv-tools_BINARY_DIR} - PRIVATE ${CMAKE_BINARY_DIR}) - - # The fuzzer reuses a lot of functionality from the SPIRV-Tools library. - target_link_libraries(SPIRV-Tools-fuzz - PUBLIC ${SPIRV_TOOLS}-static - PUBLIC SPIRV-Tools-opt - PUBLIC protobuf::libprotobuf) - - set_property(TARGET SPIRV-Tools-fuzz PROPERTY FOLDER "SPIRV-Tools libraries") - spvtools_check_symbol_exports(SPIRV-Tools-fuzz) - - if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-fuzz EXPORT SPIRV-Tools-fuzzTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - export(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake) - - spvtools_config_package_dir(SPIRV-Tools-fuzz PACKAGE_DIR) - install(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake - DESTINATION ${PACKAGE_DIR}) - - spvtools_generate_config_file(SPIRV-Tools-fuzz) - install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-fuzzConfig.cmake DESTINATION ${PACKAGE_DIR}) - endif(ENABLE_SPIRV_TOOLS_INSTALL) - -endif(SPIRV_BUILD_FUZZER) diff --git a/3rdparty/spirv-tools/source/fuzz/call_graph.cpp b/3rdparty/spirv-tools/source/fuzz/call_graph.cpp deleted file mode 100644 index 15416fe3e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/call_graph.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/call_graph.h" - -#include - -namespace spvtools { -namespace fuzz { - -CallGraph::CallGraph(opt::IRContext* context) { - // Initialize function in-degree and call graph edges to 0 and empty. - for (auto& function : *context->module()) { - function_in_degree_[function.result_id()] = 0; - call_graph_edges_[function.result_id()] = std::set(); - } - - // Consider every function. - for (auto& function : *context->module()) { - // Avoid considering the same callee of this function multiple times by - // recording known callees. - std::set known_callees; - // Consider every function call instruction in every block. - for (auto& block : function) { - for (auto& instruction : block) { - if (instruction.opcode() != SpvOpFunctionCall) { - continue; - } - // Get the id of the function being called. - uint32_t callee = instruction.GetSingleWordInOperand(0); - if (known_callees.count(callee)) { - // We have already considered a call to this function - ignore it. - continue; - } - // Increase the callee's in-degree and add an edge to the call graph. - function_in_degree_[callee]++; - call_graph_edges_[function.result_id()].insert(callee); - // Mark the callee as 'known'. - known_callees.insert(callee); - } - } - } -} - -void CallGraph::PushDirectCallees(uint32_t function_id, - std::queue* queue) const { - for (auto callee : GetDirectCallees(function_id)) { - queue->push(callee); - } -} - -std::set CallGraph::GetIndirectCallees(uint32_t function_id) const { - std::set result; - std::queue queue; - PushDirectCallees(function_id, &queue); - - while (!queue.empty()) { - auto next = queue.front(); - queue.pop(); - if (result.count(next)) { - continue; - } - result.insert(next); - PushDirectCallees(next, &queue); - } - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/call_graph.h b/3rdparty/spirv-tools/source/fuzz/call_graph.h deleted file mode 100644 index 14cd23b4c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/call_graph.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_CALL_GRAPH_H_ -#define SOURCE_FUZZ_CALL_GRAPH_H_ - -#include -#include - -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// Represents the acyclic call graph of a SPIR-V module. -class CallGraph { - public: - // Creates a call graph corresponding to the given SPIR-V module. - explicit CallGraph(opt::IRContext* context); - - // Returns a mapping from each function to its number of distinct callers. - const std::map& GetFunctionInDegree() const { - return function_in_degree_; - } - - // Returns the ids of the functions that |function_id| directly invokes. - const std::set& GetDirectCallees(uint32_t function_id) const { - return call_graph_edges_.at(function_id); - } - - // Returns the ids of the functions that |function_id| directly or indirectly - // invokes. - std::set GetIndirectCallees(uint32_t function_id) const; - - private: - // Pushes the direct callees of |function_id| on to |queue|. - void PushDirectCallees(uint32_t function_id, - std::queue* queue) const; - - // Maps each function id to the ids of its immediate callees. - std::map> call_graph_edges_; - - // For each function id, stores the number of distinct functions that call - // the function. - std::map function_in_degree_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_CALL_GRAPH_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/counter_overflow_id_source.cpp b/3rdparty/spirv-tools/source/fuzz/counter_overflow_id_source.cpp deleted file mode 100644 index 1ed5603f7..000000000 --- a/3rdparty/spirv-tools/source/fuzz/counter_overflow_id_source.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/counter_overflow_id_source.h" - -namespace spvtools { -namespace fuzz { - -CounterOverflowIdSource::CounterOverflowIdSource(uint32_t first_available_id) - : next_available_id_(first_available_id) {} - -bool CounterOverflowIdSource::HasOverflowIds() const { return true; } - -uint32_t CounterOverflowIdSource::GetNextOverflowId() { - return next_available_id_++; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/counter_overflow_id_source.h b/3rdparty/spirv-tools/source/fuzz/counter_overflow_id_source.h deleted file mode 100644 index aa8bc7abd..000000000 --- a/3rdparty/spirv-tools/source/fuzz/counter_overflow_id_source.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_COUNTER_OVERFLOW_ID_SOURCE_H_ -#define SOURCE_FUZZ_COUNTER_OVERFLOW_ID_SOURCE_H_ - -#include "source/fuzz/overflow_id_source.h" - -namespace spvtools { -namespace fuzz { - -// A source of overflow ids that uses a counter to provide successive ids from -// a given starting value. -class CounterOverflowIdSource : public OverflowIdSource { - public: - // |first_available_id| is the starting value for the counter. - explicit CounterOverflowIdSource(uint32_t first_available_id); - - // Always returns true. - bool HasOverflowIds() const override; - - // Returns the current counter value and increments the counter. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) We should - // account for the case where the maximum allowed id is reached. - uint32_t GetNextOverflowId() override; - - private: - uint32_t next_available_id_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_OVERFLOW_ID_SOURCE_COUNTER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/data_descriptor.cpp b/3rdparty/spirv-tools/source/fuzz/data_descriptor.cpp deleted file mode 100644 index 86e5325f1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/data_descriptor.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/data_descriptor.h" - -#include - -namespace spvtools { -namespace fuzz { - -protobufs::DataDescriptor MakeDataDescriptor(uint32_t object, - std::vector&& indices) { - protobufs::DataDescriptor result; - result.set_object(object); - for (auto index : indices) { - result.add_index(index); - } - return result; -} - -size_t DataDescriptorHash::operator()( - const protobufs::DataDescriptor* data_descriptor) const { - std::u32string hash; - hash.push_back(data_descriptor->object()); - for (auto an_index : data_descriptor->index()) { - hash.push_back(an_index); - } - return std::hash()(hash); -} - -bool DataDescriptorEquals::operator()( - const protobufs::DataDescriptor* first, - const protobufs::DataDescriptor* second) const { - return first->object() == second->object() && - first->index().size() == second->index().size() && - std::equal(first->index().begin(), first->index().end(), - second->index().begin()); -} - -std::ostream& operator<<(std::ostream& out, - const protobufs::DataDescriptor& data_descriptor) { - out << data_descriptor.object(); - out << "["; - bool first = true; - for (auto index : data_descriptor.index()) { - if (first) { - first = false; - } else { - out << ", "; - } - out << index; - } - out << "]"; - return out; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/data_descriptor.h b/3rdparty/spirv-tools/source/fuzz/data_descriptor.h deleted file mode 100644 index c569ac80a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/data_descriptor.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_DATA_DESCRIPTOR_H_ -#define SOURCE_FUZZ_DATA_DESCRIPTOR_H_ - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" - -#include -#include - -namespace spvtools { -namespace fuzz { - -// Factory method to create a data descriptor message from an object id and a -// list of indices. -protobufs::DataDescriptor MakeDataDescriptor(uint32_t object, - std::vector&& indices); - -// Hash function for data descriptors. -struct DataDescriptorHash { - size_t operator()(const protobufs::DataDescriptor* data_descriptor) const; -}; - -// Equality function for data descriptors. -struct DataDescriptorEquals { - bool operator()(const protobufs::DataDescriptor* first, - const protobufs::DataDescriptor* second) const; -}; - -std::ostream& operator<<(std::ostream& out, - const protobufs::DataDescriptor& data_descriptor); - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_DATA_DESCRIPTOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/equivalence_relation.h b/3rdparty/spirv-tools/source/fuzz/equivalence_relation.h deleted file mode 100644 index 6d0b63eda..000000000 --- a/3rdparty/spirv-tools/source/fuzz/equivalence_relation.h +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_EQUIVALENCE_RELATION_H_ -#define SOURCE_FUZZ_EQUIVALENCE_RELATION_H_ - -#include -#include -#include -#include - -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { - -// A class for representing an equivalence relation on objects of type |T|, -// which should be a value type. The type |T| is required to have a copy -// constructor, and |PointerHashT| and |PointerEqualsT| must be functors -// providing hashing and equality testing functionality for pointers to objects -// of type |T|. -// -// A disjoint-set (a.k.a. union-find or merge-find) data structure is used to -// represent the equivalence relation. Path compression is used. Union by -// rank/size is not used. -// -// Each disjoint set is represented as a tree, rooted at the representative -// of the set. -// -// Getting the representative of a value simply requires chasing parent pointers -// from the value until you reach the root. -// -// Checking equivalence of two elements requires checking that the -// representatives are equal. -// -// Traversing the tree rooted at a value's representative visits the value's -// equivalence class. -// -// |PointerHashT| and |PointerEqualsT| are used to define *equality* between -// values, and otherwise are *not* used to define the equivalence relation -// (except that equal values are equivalent). The equivalence relation is -// constructed by repeatedly adding pairs of (typically non-equal) values that -// are deemed to be equivalent. -// -// For example in an equivalence relation on integers, 1 and 5 might be added -// as equivalent, so that IsEquivalent(1, 5) holds, because they represent -// IDs in a SPIR-V binary that are known to contain the same value at run time, -// but clearly 1 != 5. Since 1 and 1 are equal, IsEquivalent(1, 1) will also -// hold. -// -// Each unique (up to equality) value added to the relation is copied into -// |owned_values_|, so there is one canonical memory address per unique value. -// Uniqueness is ensured by storing (and checking) a set of pointers to these -// values in |value_set_|, which uses |PointerHashT| and |PointerEqualsT|. -// -// |parent_| and |children_| encode the equivalence relation, i.e., the trees. -template -class EquivalenceRelation { - public: - // Requires that |value1| and |value2| are already registered in the - // equivalence relation. Merges the equivalence classes associated with - // |value1| and |value2|. - void MakeEquivalent(const T& value1, const T& value2) { - assert(Exists(value1) && - "Precondition: value1 must already be registered."); - assert(Exists(value2) && - "Precondition: value2 must already be registered."); - - // Look up canonical pointers to each of the values in the value pool. - const T* value1_ptr = *value_set_.find(&value1); - const T* value2_ptr = *value_set_.find(&value2); - - // If the values turn out to be identical, they are already in the same - // equivalence class so there is nothing to do. - if (value1_ptr == value2_ptr) { - return; - } - - // Find the representative for each value's equivalence class, and if they - // are not already in the same class, make one the parent of the other. - const T* representative1 = Find(value1_ptr); - const T* representative2 = Find(value2_ptr); - assert(representative1 && "Representatives should never be null."); - assert(representative2 && "Representatives should never be null."); - if (representative1 != representative2) { - parent_[representative1] = representative2; - children_[representative2].push_back(representative1); - } - } - - // Requires that |value| is not known to the equivalence relation. Registers - // it in its own equivalence class and returns a pointer to the equivalence - // class representative. - const T* Register(const T& value) { - assert(!Exists(value)); - - // This relies on T having a copy constructor. - auto unique_pointer_to_value = MakeUnique(value); - auto pointer_to_value = unique_pointer_to_value.get(); - owned_values_.push_back(std::move(unique_pointer_to_value)); - value_set_.insert(pointer_to_value); - - // Initially say that the value is its own parent and that it has no - // children. - assert(pointer_to_value && "Representatives should never be null."); - parent_[pointer_to_value] = pointer_to_value; - children_[pointer_to_value] = std::vector(); - - return pointer_to_value; - } - - // Returns exactly one representative per equivalence class. - std::vector GetEquivalenceClassRepresentatives() const { - std::vector result; - for (auto& value : owned_values_) { - if (parent_[value.get()] == value.get()) { - result.push_back(value.get()); - } - } - return result; - } - - // Returns pointers to all values in the equivalence class of |value|, which - // must already be part of the equivalence relation. - std::vector GetEquivalenceClass(const T& value) const { - assert(Exists(value)); - - std::vector result; - - // Traverse the tree of values rooted at the representative of the - // equivalence class to which |value| belongs, and collect up all the values - // that are encountered. This constitutes the whole equivalence class. - std::vector stack; - stack.push_back(Find(*value_set_.find(&value))); - while (!stack.empty()) { - const T* item = stack.back(); - result.push_back(item); - stack.pop_back(); - for (auto child : children_[item]) { - stack.push_back(child); - } - } - return result; - } - - // Returns true if and only if |value1| and |value2| are in the same - // equivalence class. Both values must already be known to the equivalence - // relation. - bool IsEquivalent(const T& value1, const T& value2) const { - return Find(&value1) == Find(&value2); - } - - // Returns all values known to be part of the equivalence relation. - std::vector GetAllKnownValues() const { - std::vector result; - for (auto& value : owned_values_) { - result.push_back(value.get()); - } - return result; - } - - // Returns true if and only if |value| is known to be part of the equivalence - // relation. - bool Exists(const T& value) const { - return value_set_.find(&value) != value_set_.end(); - } - - // Returns the representative of the equivalence class of |value|, which must - // already be known to the equivalence relation. This is the 'Find' operation - // in a classic union-find data structure. - const T* Find(const T* value) const { - assert(Exists(*value)); - - // Get the canonical pointer to the value from the value pool. - const T* known_value = *value_set_.find(value); - assert(parent_[known_value] && "Every known value should have a parent."); - - // Compute the result by chasing parents until we find a value that is its - // own parent. - const T* result = known_value; - while (parent_[result] != result) { - result = parent_[result]; - } - assert(result && "Representatives should never be null."); - - // At this point, |result| is the representative of the equivalence class. - // Now perform the 'path compression' optimization by doing another pass up - // the parent chain, setting the parent of each node to be the - // representative, and rewriting children correspondingly. - const T* current = known_value; - while (parent_[current] != result) { - const T* next = parent_[current]; - parent_[current] = result; - children_[result].push_back(current); - auto child_iterator = - std::find(children_[next].begin(), children_[next].end(), current); - assert(child_iterator != children_[next].end() && - "'next' is the parent of 'current', so 'current' should be a " - "child of 'next'"); - children_[next].erase(child_iterator); - current = next; - } - return result; - } - - private: - // Maps every value to a parent. The representative of an equivalence class - // is its own parent. A value's representative can be found by walking its - // chain of ancestors. - // - // Mutable because the intuitively const method, 'Find', performs path - // compression. - mutable std::unordered_map parent_; - - // Stores the children of each value. This allows the equivalence class of - // a value to be calculated by traversing all descendents of the class's - // representative. - // - // Mutable because the intuitively const method, 'Find', performs path - // compression. - mutable std::unordered_map> children_; - - // The values known to the equivalence relation are allocated in - // |owned_values_|, and |value_pool_| provides (via |PointerHashT| and - // |PointerEqualsT|) a means for mapping a value of interest to a pointer - // into an equivalent value in |owned_values_|. - std::unordered_set value_set_; - std::vector> owned_values_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_EQUIVALENCE_RELATION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/constant_uniform_facts.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager/constant_uniform_facts.cpp deleted file mode 100644 index 672ed5280..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/constant_uniform_facts.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fact_manager/constant_uniform_facts.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/uniform_buffer_element_descriptor.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -uint32_t ConstantUniformFacts::GetConstantId( - opt::IRContext* context, - const protobufs::FactConstantUniform& constant_uniform_fact, - uint32_t type_id) { - auto type = context->get_type_mgr()->GetType(type_id); - assert(type != nullptr && "Unknown type id."); - const opt::analysis::Constant* known_constant; - if (type->AsInteger()) { - opt::analysis::IntConstant candidate_constant( - type->AsInteger(), GetConstantWords(constant_uniform_fact)); - known_constant = - context->get_constant_mgr()->FindConstant(&candidate_constant); - } else { - assert( - type->AsFloat() && - "Uniform constant facts are only supported for int and float types."); - opt::analysis::FloatConstant candidate_constant( - type->AsFloat(), GetConstantWords(constant_uniform_fact)); - known_constant = - context->get_constant_mgr()->FindConstant(&candidate_constant); - } - if (!known_constant) { - return 0; - } - return context->get_constant_mgr()->FindDeclaredConstant(known_constant, - type_id); -} - -std::vector ConstantUniformFacts::GetConstantWords( - const protobufs::FactConstantUniform& constant_uniform_fact) { - std::vector result; - for (auto constant_word : constant_uniform_fact.constant_word()) { - result.push_back(constant_word); - } - return result; -} - -bool ConstantUniformFacts::DataMatches( - const opt::Instruction& constant_instruction, - const protobufs::FactConstantUniform& constant_uniform_fact) { - assert(constant_instruction.opcode() == SpvOpConstant); - std::vector data_in_constant; - for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) { - data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i)); - } - return data_in_constant == GetConstantWords(constant_uniform_fact); -} - -std::vector -ConstantUniformFacts::GetConstantsAvailableFromUniformsForType( - opt::IRContext* ir_context, uint32_t type_id) const { - std::vector result; - std::set already_seen; - for (auto& fact_and_type_id : facts_and_type_ids_) { - if (fact_and_type_id.second != type_id) { - continue; - } - if (auto constant_id = - GetConstantId(ir_context, fact_and_type_id.first, type_id)) { - if (already_seen.find(constant_id) == already_seen.end()) { - result.push_back(constant_id); - already_seen.insert(constant_id); - } - } - } - return result; -} - -std::vector -ConstantUniformFacts::GetUniformDescriptorsForConstant( - opt::IRContext* ir_context, uint32_t constant_id) const { - std::vector result; - auto constant_inst = ir_context->get_def_use_mgr()->GetDef(constant_id); - assert(constant_inst->opcode() == SpvOpConstant && - "The given id must be that of a constant"); - auto type_id = constant_inst->type_id(); - for (auto& fact_and_type_id : facts_and_type_ids_) { - if (fact_and_type_id.second != type_id) { - continue; - } - if (DataMatches(*constant_inst, fact_and_type_id.first)) { - result.emplace_back( - fact_and_type_id.first.uniform_buffer_element_descriptor()); - } - } - return result; -} - -uint32_t ConstantUniformFacts::GetConstantFromUniformDescriptor( - opt::IRContext* context, - const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const { - // Consider each fact. - for (auto& fact_and_type : facts_and_type_ids_) { - // Check whether the uniform descriptor associated with the fact matches - // |uniform_descriptor|. - if (UniformBufferElementDescriptorEquals()( - &uniform_descriptor, - &fact_and_type.first.uniform_buffer_element_descriptor())) { - return GetConstantId(context, fact_and_type.first, fact_and_type.second); - } - } - // No fact associated with the given uniform descriptor was found. - return 0; -} - -std::vector -ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown() const { - std::vector result; - for (auto& fact_and_type : facts_and_type_ids_) { - if (std::find(result.begin(), result.end(), fact_and_type.second) == - result.end()) { - result.push_back(fact_and_type.second); - } - } - return result; -} - -bool ConstantUniformFacts::FloatingPointValueIsSuitable( - const protobufs::FactConstantUniform& fact, uint32_t width) { - const uint32_t kFloatWidth = 32; - const uint32_t kDoubleWidth = 64; - if (width != kFloatWidth && width != kDoubleWidth) { - // Only 32- and 64-bit floating-point types are handled. - return false; - } - std::vector words = GetConstantWords(fact); - if (width == 32) { - float value; - memcpy(&value, words.data(), sizeof(float)); - if (!std::isfinite(value)) { - return false; - } - } else { - double value; - memcpy(&value, words.data(), sizeof(double)); - if (!std::isfinite(value)) { - return false; - } - } - return true; -} - -bool ConstantUniformFacts::AddFact(const protobufs::FactConstantUniform& fact, - opt::IRContext* context) { - // Try to find a unique instruction that declares a variable such that the - // variable is decorated with the descriptor set and binding associated with - // the constant uniform fact. - opt::Instruction* uniform_variable = FindUniformVariable( - fact.uniform_buffer_element_descriptor(), context, true); - - if (!uniform_variable) { - return false; - } - - assert(SpvOpVariable == uniform_variable->opcode()); - assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0)); - - auto should_be_uniform_pointer_type = - context->get_type_mgr()->GetType(uniform_variable->type_id()); - if (!should_be_uniform_pointer_type->AsPointer()) { - return false; - } - if (should_be_uniform_pointer_type->AsPointer()->storage_class() != - SpvStorageClassUniform) { - return false; - } - auto should_be_uniform_pointer_instruction = - context->get_def_use_mgr()->GetDef(uniform_variable->type_id()); - auto composite_type = - should_be_uniform_pointer_instruction->GetSingleWordInOperand(1); - - auto final_element_type_id = fuzzerutil::WalkCompositeTypeIndices( - context, composite_type, - fact.uniform_buffer_element_descriptor().index()); - if (!final_element_type_id) { - return false; - } - auto final_element_type = - context->get_type_mgr()->GetType(final_element_type_id); - assert(final_element_type && - "There should be a type corresponding to this id."); - - if (!(final_element_type->AsFloat() || final_element_type->AsInteger())) { - return false; - } - auto width = final_element_type->AsFloat() - ? final_element_type->AsFloat()->width() - : final_element_type->AsInteger()->width(); - - if (final_element_type->AsFloat() && - !FloatingPointValueIsSuitable(fact, width)) { - return false; - } - - auto required_words = (width + 32 - 1) / 32; - if (static_cast(fact.constant_word().size()) != required_words) { - return false; - } - facts_and_type_ids_.emplace_back( - std::pair( - fact, final_element_type_id)); - return true; -} - -const std::vector>& -ConstantUniformFacts::GetConstantUniformFactsAndTypes() const { - return facts_and_type_ids_; -} - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/constant_uniform_facts.h b/3rdparty/spirv-tools/source/fuzz/fact_manager/constant_uniform_facts.h deleted file mode 100644 index 6d052e504..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/constant_uniform_facts.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FACT_MANAGER_CONSTANT_UNIFORM_FACTS_H_ -#define SOURCE_FUZZ_FACT_MANAGER_CONSTANT_UNIFORM_FACTS_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -// The purpose of this class is to group the fields and data used to represent -// facts about uniform constants. -class ConstantUniformFacts { - public: - // See method in FactManager which delegates to this method. - bool AddFact(const protobufs::FactConstantUniform& fact, - opt::IRContext* context); - - // See method in FactManager which delegates to this method. - std::vector GetConstantsAvailableFromUniformsForType( - opt::IRContext* ir_context, uint32_t type_id) const; - - // See method in FactManager which delegates to this method. - std::vector - GetUniformDescriptorsForConstant(opt::IRContext* ir_context, - uint32_t constant_id) const; - - // See method in FactManager which delegates to this method. - uint32_t GetConstantFromUniformDescriptor( - opt::IRContext* context, - const protobufs::UniformBufferElementDescriptor& uniform_descriptor) - const; - - // See method in FactManager which delegates to this method. - std::vector GetTypesForWhichUniformValuesAreKnown() const; - - // See method in FactManager which delegates to this method. - const std::vector>& - GetConstantUniformFactsAndTypes() const; - - private: - // Returns true if and only if the words associated with - // |constant_instruction| exactly match the words for the constant associated - // with |constant_uniform_fact|. - static bool DataMatches( - const opt::Instruction& constant_instruction, - const protobufs::FactConstantUniform& constant_uniform_fact); - - // Yields the constant words associated with |constant_uniform_fact|. - static std::vector GetConstantWords( - const protobufs::FactConstantUniform& constant_uniform_fact); - - // Yields the id of a constant of type |type_id| whose data matches the - // constant data in |constant_uniform_fact|, or 0 if no such constant is - // declared. - static uint32_t GetConstantId( - opt::IRContext* context, - const protobufs::FactConstantUniform& constant_uniform_fact, - uint32_t type_id); - - // Checks that the width of a floating-point constant is supported, and that - // the constant is finite. - static bool FloatingPointValueIsSuitable( - const protobufs::FactConstantUniform& fact, uint32_t width); - - std::vector> - facts_and_type_ids_; -}; - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FACT_MANAGER_CONSTANT_UNIFORM_FACTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp deleted file mode 100644 index 877a38c67..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp +++ /dev/null @@ -1,861 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -size_t DataSynonymAndIdEquationFacts::OperationHash::operator()( - const Operation& operation) const { - std::u32string hash; - hash.push_back(operation.opcode); - for (auto operand : operation.operands) { - hash.push_back(static_cast(DataDescriptorHash()(operand))); - } - return std::hash()(hash); -} - -bool DataSynonymAndIdEquationFacts::OperationEquals::operator()( - const Operation& first, const Operation& second) const { - // Equal operations require... - // - // Equal opcodes. - if (first.opcode != second.opcode) { - return false; - } - // Matching operand counts. - if (first.operands.size() != second.operands.size()) { - return false; - } - // Equal operands. - for (uint32_t i = 0; i < first.operands.size(); i++) { - if (!DataDescriptorEquals()(first.operands[i], second.operands[i])) { - return false; - } - } - return true; -} - -void DataSynonymAndIdEquationFacts::AddFact( - const protobufs::FactDataSynonym& fact, opt::IRContext* context) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550) - // Assert that ids are not irrelevant. - - // Add the fact, including all facts relating sub-components of the data - // descriptors that are involved. - AddDataSynonymFactRecursive(fact.data1(), fact.data2(), context); -} - -void DataSynonymAndIdEquationFacts::AddFact( - const protobufs::FactIdEquation& fact, opt::IRContext* context) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550) - // Assert that ids are not irrelevant. - - protobufs::DataDescriptor lhs_dd = MakeDataDescriptor(fact.lhs_id(), {}); - - // Register the LHS in the equivalence relation if needed. - RegisterDataDescriptor(lhs_dd); - - // Get equivalence class representatives for all ids used on the RHS of the - // equation. - std::vector rhs_dds; - for (auto rhs_id : fact.rhs_id()) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550) - // Assert that ids are not irrelevant. - - // Register a data descriptor based on this id in the equivalence relation - // if needed, and then record the equivalence class representative. - rhs_dds.push_back(RegisterDataDescriptor(MakeDataDescriptor(rhs_id, {}))); - } - - // Now add the fact. - AddEquationFactRecursive(lhs_dd, static_cast(fact.opcode()), rhs_dds, - context); -} - -DataSynonymAndIdEquationFacts::OperationSet -DataSynonymAndIdEquationFacts::GetEquations( - const protobufs::DataDescriptor* lhs) const { - auto existing = id_equations_.find(lhs); - if (existing == id_equations_.end()) { - return OperationSet(); - } - return existing->second; -} - -void DataSynonymAndIdEquationFacts::AddEquationFactRecursive( - const protobufs::DataDescriptor& lhs_dd, SpvOp opcode, - const std::vector& rhs_dds, - opt::IRContext* context) { - assert(synonymous_.Exists(lhs_dd) && - "The LHS must be known to the equivalence relation."); - for (auto rhs_dd : rhs_dds) { - // Keep release compilers happy. - (void)(rhs_dd); - assert(synonymous_.Exists(*rhs_dd) && - "The RHS operands must be known to the equivalence relation."); - } - - auto lhs_dd_representative = synonymous_.Find(&lhs_dd); - - if (id_equations_.count(lhs_dd_representative) == 0) { - // We have not seen an equation with this LHS before, so associate the LHS - // with an initially empty set. - id_equations_.insert({lhs_dd_representative, OperationSet()}); - } - - { - auto existing_equations = id_equations_.find(lhs_dd_representative); - assert(existing_equations != id_equations_.end() && - "A set of operations should be present, even if empty."); - - Operation new_operation = {opcode, rhs_dds}; - if (existing_equations->second.count(new_operation)) { - // This equation is known, so there is nothing further to be done. - return; - } - // Add the equation to the set of known equations. - existing_equations->second.insert(new_operation); - } - - // Now try to work out corollaries implied by the new equation and existing - // facts. - switch (opcode) { - case SpvOpConvertSToF: - case SpvOpConvertUToF: - ComputeConversionDataSynonymFacts(*rhs_dds[0], context); - break; - case SpvOpBitcast: { - assert(DataDescriptorsAreWellFormedAndComparable(context, lhs_dd, - *rhs_dds[0]) && - "Operands of OpBitcast equation fact must have compatible types"); - if (!synonymous_.IsEquivalent(lhs_dd, *rhs_dds[0])) { - AddDataSynonymFactRecursive(lhs_dd, *rhs_dds[0], context); - } - } break; - case SpvOpIAdd: { - // Equation form: "a = b + c" - for (const auto& equation : GetEquations(rhs_dds[0])) { - if (equation.opcode == SpvOpISub) { - // Equation form: "a = (d - e) + c" - if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) { - // Equation form: "a = (d - c) + c" - // We can thus infer "a = d" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); - } - if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) { - // Equation form: "a = (c - e) + c" - // We can thus infer "a = -e" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[1]}, context); - } - } - } - for (const auto& equation : GetEquations(rhs_dds[1])) { - if (equation.opcode == SpvOpISub) { - // Equation form: "a = b + (d - e)" - if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) { - // Equation form: "a = b + (d - b)" - // We can thus infer "a = d" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); - } - } - } - break; - } - case SpvOpISub: { - // Equation form: "a = b - c" - for (const auto& equation : GetEquations(rhs_dds[0])) { - if (equation.opcode == SpvOpIAdd) { - // Equation form: "a = (d + e) - c" - if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) { - // Equation form: "a = (c + e) - c" - // We can thus infer "a = e" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context); - } - if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) { - // Equation form: "a = (d + c) - c" - // We can thus infer "a = d" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); - } - } - - if (equation.opcode == SpvOpISub) { - // Equation form: "a = (d - e) - c" - if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) { - // Equation form: "a = (c - e) - c" - // We can thus infer "a = -e" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[1]}, context); - } - } - } - - for (const auto& equation : GetEquations(rhs_dds[1])) { - if (equation.opcode == SpvOpIAdd) { - // Equation form: "a = b - (d + e)" - if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) { - // Equation form: "a = b - (b + e)" - // We can thus infer "a = -e" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[1]}, context); - } - if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) { - // Equation form: "a = b - (d + b)" - // We can thus infer "a = -d" - AddEquationFactRecursive(lhs_dd, SpvOpSNegate, - {equation.operands[0]}, context); - } - } - if (equation.opcode == SpvOpISub) { - // Equation form: "a = b - (d - e)" - if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) { - // Equation form: "a = b - (b - e)" - // We can thus infer "a = e" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context); - } - } - } - break; - } - case SpvOpLogicalNot: - case SpvOpSNegate: { - // Equation form: "a = !b" or "a = -b" - for (const auto& equation : GetEquations(rhs_dds[0])) { - if (equation.opcode == opcode) { - // Equation form: "a = !!b" or "a = -(-b)" - // We can thus infer "a = b" - AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context); - } - } - break; - } - default: - break; - } -} - -void DataSynonymAndIdEquationFacts::AddDataSynonymFactRecursive( - const protobufs::DataDescriptor& dd1, const protobufs::DataDescriptor& dd2, - opt::IRContext* context) { - assert(DataDescriptorsAreWellFormedAndComparable(context, dd1, dd2)); - - // Record that the data descriptors provided in the fact are equivalent. - MakeEquivalent(dd1, dd2); - assert(synonymous_.Find(&dd1) == synonymous_.Find(&dd2) && - "|dd1| and |dd2| must have a single representative"); - - // Compute various corollary facts. - - // |dd1| and |dd2| belong to the same equivalence class so it doesn't matter - // which one we use here. - ComputeConversionDataSynonymFacts(dd1, context); - - ComputeCompositeDataSynonymFacts(dd1, dd2, context); -} - -void DataSynonymAndIdEquationFacts::ComputeConversionDataSynonymFacts( - const protobufs::DataDescriptor& dd, opt::IRContext* context) { - assert(synonymous_.Exists(dd) && - "|dd| should've been registered in the equivalence relation"); - - const auto* representative = synonymous_.Find(&dd); - assert(representative && - "Representative can't be null for a registered descriptor"); - - const auto* type = - context->get_type_mgr()->GetType(fuzzerutil::WalkCompositeTypeIndices( - context, fuzzerutil::GetTypeId(context, representative->object()), - representative->index())); - assert(type && "Data descriptor has invalid type"); - - if ((type->AsVector() && type->AsVector()->element_type()->AsInteger()) || - type->AsInteger()) { - // If there exist equation facts of the form |%a = opcode %representative| - // and |%b = opcode %representative| where |opcode| is either OpConvertSToF - // or OpConvertUToF, then |a| and |b| are synonymous. - std::vector convert_s_to_f_lhs; - std::vector convert_u_to_f_lhs; - - for (const auto& fact : id_equations_) { - for (const auto& equation : fact.second) { - if (synonymous_.IsEquivalent(*equation.operands[0], *representative)) { - if (equation.opcode == SpvOpConvertSToF) { - convert_s_to_f_lhs.push_back(fact.first); - } else if (equation.opcode == SpvOpConvertUToF) { - convert_u_to_f_lhs.push_back(fact.first); - } - } - } - } - - for (const auto& synonyms : - {std::move(convert_s_to_f_lhs), std::move(convert_u_to_f_lhs)}) { - for (const auto* synonym_a : synonyms) { - for (const auto* synonym_b : synonyms) { - if (!synonymous_.IsEquivalent(*synonym_a, *synonym_b) && - DataDescriptorsAreWellFormedAndComparable(context, *synonym_a, - *synonym_b)) { - // |synonym_a| and |synonym_b| have compatible types - they are - // synonymous. - AddDataSynonymFactRecursive(*synonym_a, *synonym_b, context); - } - } - } - } - } -} - -void DataSynonymAndIdEquationFacts::ComputeCompositeDataSynonymFacts( - const protobufs::DataDescriptor& dd1, const protobufs::DataDescriptor& dd2, - opt::IRContext* context) { - // Check whether this is a synonym about composite objects. If it is, - // we can recursively add synonym facts about their associated sub-components. - - // Get the type of the object referred to by the first data descriptor in the - // synonym fact. - uint32_t type_id = fuzzerutil::WalkCompositeTypeIndices( - context, context->get_def_use_mgr()->GetDef(dd1.object())->type_id(), - dd1.index()); - auto type = context->get_type_mgr()->GetType(type_id); - auto type_instruction = context->get_def_use_mgr()->GetDef(type_id); - assert(type != nullptr && - "Invalid data synonym fact: one side has an unknown type."); - - // Check whether the type is composite, recording the number of elements - // associated with the composite if so. - uint32_t num_composite_elements; - if (type->AsArray()) { - num_composite_elements = - fuzzerutil::GetArraySize(*type_instruction, context); - } else if (type->AsMatrix()) { - num_composite_elements = type->AsMatrix()->element_count(); - } else if (type->AsStruct()) { - num_composite_elements = - fuzzerutil::GetNumberOfStructMembers(*type_instruction); - } else if (type->AsVector()) { - num_composite_elements = type->AsVector()->element_count(); - } else { - // The type is not a composite, so return. - return; - } - - // If the fact has the form: - // obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n] - // then for each composite index i, we add a fact of the form: - // obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i] - // - // However, to avoid adding a large number of synonym facts e.g. in the case - // of arrays, we bound the number of composite elements to which this is - // applied. Nevertheless, we always add a synonym fact for the final - // components, as this may be an interesting edge case. - - // The bound on the number of indices of the composite pair to note as being - // synonymous. - const uint32_t kCompositeElementBound = 10; - - for (uint32_t i = 0; i < num_composite_elements;) { - std::vector extended_indices1 = - fuzzerutil::RepeatedFieldToVector(dd1.index()); - extended_indices1.push_back(i); - std::vector extended_indices2 = - fuzzerutil::RepeatedFieldToVector(dd2.index()); - extended_indices2.push_back(i); - AddDataSynonymFactRecursive( - MakeDataDescriptor(dd1.object(), std::move(extended_indices1)), - MakeDataDescriptor(dd2.object(), std::move(extended_indices2)), - context); - - if (i < kCompositeElementBound - 1 || i == num_composite_elements - 1) { - // We have not reached the bound yet, or have already skipped ahead to the - // last element, so increment the loop counter as standard. - i++; - } else { - // We have reached the bound, so skip ahead to the last element. - assert(i == kCompositeElementBound - 1); - i = num_composite_elements - 1; - } - } -} - -void DataSynonymAndIdEquationFacts::ComputeClosureOfFacts( - opt::IRContext* context, uint32_t maximum_equivalence_class_size) { - // Suppose that obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n] are distinct - // data descriptors that describe objects of the same composite type, and that - // the composite type is comprised of k components. - // - // For example, if m is a mat4x4 and v a vec4, we might consider: - // m[2]: describes the 2nd column of m, a vec4 - // v[]: describes all of v, a vec4 - // - // Suppose that we know, for every 0 <= i < k, that the fact: - // obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i] - // holds - i.e. that the children of the two data descriptors are synonymous. - // - // Then we can conclude that: - // obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n] - // holds. - // - // For instance, if we have the facts: - // m[2, 0] == v[0] - // m[2, 1] == v[1] - // m[2, 2] == v[2] - // m[2, 3] == v[3] - // then we can conclude that: - // m[2] == v. - // - // This method repeatedly searches the equivalence relation of data - // descriptors, deducing and adding such facts, until a pass over the - // relation leads to no further facts being deduced. - - // The method relies on working with pairs of data descriptors, and in - // particular being able to hash and compare such pairs. - - using DataDescriptorPair = - std::pair; - - struct DataDescriptorPairHash { - std::size_t operator()(const DataDescriptorPair& pair) const { - return DataDescriptorHash()(&pair.first) ^ - DataDescriptorHash()(&pair.second); - } - }; - - struct DataDescriptorPairEquals { - bool operator()(const DataDescriptorPair& first, - const DataDescriptorPair& second) const { - return (DataDescriptorEquals()(&first.first, &second.first) && - DataDescriptorEquals()(&first.second, &second.second)) || - (DataDescriptorEquals()(&first.first, &second.second) && - DataDescriptorEquals()(&first.second, &second.first)); - } - }; - - // This map records, for a given pair of composite data descriptors of the - // same type, all the indices at which the data descriptors are known to be - // synonymous. A pair is a key to this map only if we have observed that - // the pair are synonymous at *some* index, but not at *all* indices. - // Once we find that a pair of data descriptors are equivalent at all indices - // we record the fact that they are synonymous and remove them from the map. - // - // Using the m and v example from above, initially the pair (m[2], v) would - // not be a key to the map. If we find that m[2, 2] == v[2] holds, we would - // add an entry: - // (m[2], v) -> [false, false, true, false] - // to record that they are synonymous at index 2. If we then find that - // m[2, 0] == v[0] holds, we would update this entry to: - // (m[2], v) -> [true, false, true, false] - // If we then find that m[2, 3] == v[3] holds, we would update this entry to: - // (m[2], v) -> [true, false, true, true] - // Finally, if we then find that m[2, 1] == v[1] holds, which would make the - // boolean vector true at every index, we would add the fact: - // m[2] == v - // to the equivalence relation and remove (m[2], v) from the map. - std::unordered_map, - DataDescriptorPairHash, DataDescriptorPairEquals> - candidate_composite_synonyms; - - // We keep looking for new facts until we perform a complete pass over the - // equivalence relation without finding any new facts. - while (closure_computation_required_) { - // We have not found any new facts yet during this pass; we set this to - // 'true' if we do find a new fact. - closure_computation_required_ = false; - - // Consider each class in the equivalence relation. - for (auto representative : - synonymous_.GetEquivalenceClassRepresentatives()) { - auto equivalence_class = synonymous_.GetEquivalenceClass(*representative); - - if (equivalence_class.size() > maximum_equivalence_class_size) { - // This equivalence class is larger than the maximum size we are willing - // to consider, so we skip it. This potentially leads to missed fact - // deductions, but avoids excessive runtime for closure computation. - continue; - } - - // Consider every data descriptor in the equivalence class. - for (auto dd1_it = equivalence_class.begin(); - dd1_it != equivalence_class.end(); ++dd1_it) { - // If this data descriptor has no indices then it does not have the form - // obj_1[a_1, ..., a_m, i], so move on. - auto dd1 = *dd1_it; - if (dd1->index_size() == 0) { - continue; - } - - // Consider every other data descriptor later in the equivalence class - // (due to symmetry, there is no need to compare with previous data - // descriptors). - auto dd2_it = dd1_it; - for (++dd2_it; dd2_it != equivalence_class.end(); ++dd2_it) { - auto dd2 = *dd2_it; - // If this data descriptor has no indices then it does not have the - // form obj_2[b_1, ..., b_n, i], so move on. - if (dd2->index_size() == 0) { - continue; - } - - // At this point we know that: - // - |dd1| has the form obj_1[a_1, ..., a_m, i] - // - |dd2| has the form obj_2[b_1, ..., b_n, j] - assert(dd1->index_size() > 0 && dd2->index_size() > 0 && - "Control should not reach here if either data descriptor has " - "no indices."); - - // We are only interested if i == j. - if (dd1->index(dd1->index_size() - 1) != - dd2->index(dd2->index_size() - 1)) { - continue; - } - - const uint32_t common_final_index = dd1->index(dd1->index_size() - 1); - - // Make data descriptors |dd1_prefix| and |dd2_prefix| for - // obj_1[a_1, ..., a_m] - // and - // obj_2[b_1, ..., b_n] - // These are the two data descriptors we might be getting closer to - // deducing as being synonymous, due to knowing that they are - // synonymous when extended by a particular index. - protobufs::DataDescriptor dd1_prefix; - dd1_prefix.set_object(dd1->object()); - for (uint32_t i = 0; i < static_cast(dd1->index_size() - 1); - i++) { - dd1_prefix.add_index(dd1->index(i)); - } - protobufs::DataDescriptor dd2_prefix; - dd2_prefix.set_object(dd2->object()); - for (uint32_t i = 0; i < static_cast(dd2->index_size() - 1); - i++) { - dd2_prefix.add_index(dd2->index(i)); - } - assert(!DataDescriptorEquals()(&dd1_prefix, &dd2_prefix) && - "By construction these prefixes should be different."); - - // If we already know that these prefixes are synonymous, move on. - if (synonymous_.Exists(dd1_prefix) && - synonymous_.Exists(dd2_prefix) && - synonymous_.IsEquivalent(dd1_prefix, dd2_prefix)) { - continue; - } - - // Get the type of obj_1 - auto dd1_root_type_id = - context->get_def_use_mgr()->GetDef(dd1->object())->type_id(); - // Use this type, together with a_1, ..., a_m, to get the type of - // obj_1[a_1, ..., a_m]. - auto dd1_prefix_type = fuzzerutil::WalkCompositeTypeIndices( - context, dd1_root_type_id, dd1_prefix.index()); - - // Similarly, get the type of obj_2 and use it to get the type of - // obj_2[b_1, ..., b_n]. - auto dd2_root_type_id = - context->get_def_use_mgr()->GetDef(dd2->object())->type_id(); - auto dd2_prefix_type = fuzzerutil::WalkCompositeTypeIndices( - context, dd2_root_type_id, dd2_prefix.index()); - - // If the types of dd1_prefix and dd2_prefix are not the same, they - // cannot be synonymous. - if (dd1_prefix_type != dd2_prefix_type) { - continue; - } - - // At this point, we know we have synonymous data descriptors of the - // form: - // obj_1[a_1, ..., a_m, i] - // obj_2[b_1, ..., b_n, i] - // with the same last_index i, such that: - // obj_1[a_1, ..., a_m] - // and - // obj_2[b_1, ..., b_n] - // have the same type. - - // Work out how many components there are in the (common) commposite - // type associated with obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n]. - // This depends on whether the composite type is array, matrix, struct - // or vector. - uint32_t num_components_in_composite; - auto composite_type = - context->get_type_mgr()->GetType(dd1_prefix_type); - auto composite_type_instruction = - context->get_def_use_mgr()->GetDef(dd1_prefix_type); - if (composite_type->AsArray()) { - num_components_in_composite = - fuzzerutil::GetArraySize(*composite_type_instruction, context); - if (num_components_in_composite == 0) { - // This indicates that the array has an unknown size, in which - // case we cannot be sure we have matched all of its elements with - // synonymous elements of another array. - continue; - } - } else if (composite_type->AsMatrix()) { - num_components_in_composite = - composite_type->AsMatrix()->element_count(); - } else if (composite_type->AsStruct()) { - num_components_in_composite = fuzzerutil::GetNumberOfStructMembers( - *composite_type_instruction); - } else { - assert(composite_type->AsVector()); - num_components_in_composite = - composite_type->AsVector()->element_count(); - } - - // We are one step closer to being able to say that |dd1_prefix| and - // |dd2_prefix| are synonymous. - DataDescriptorPair candidate_composite_synonym(dd1_prefix, - dd2_prefix); - - // We look up what we already know about this pair. - auto existing_entry = - candidate_composite_synonyms.find(candidate_composite_synonym); - - if (existing_entry == candidate_composite_synonyms.end()) { - // If this is the first time we have seen the pair, we make a vector - // of size |num_components_in_composite| that is 'true' at the - // common final index associated with |dd1| and |dd2|, and 'false' - // everywhere else, and register this vector as being associated - // with the pair. - std::vector entry; - for (uint32_t i = 0; i < num_components_in_composite; i++) { - entry.push_back(i == common_final_index); - } - candidate_composite_synonyms[candidate_composite_synonym] = entry; - existing_entry = - candidate_composite_synonyms.find(candidate_composite_synonym); - } else { - // We have seen this pair of data descriptors before, and we now - // know that they are synonymous at one further index, so we - // update the entry to record that. - existing_entry->second[common_final_index] = true; - } - assert(existing_entry != candidate_composite_synonyms.end()); - - // Check whether |dd1_prefix| and |dd2_prefix| are now known to match - // at every sub-component. - bool all_components_match = true; - for (uint32_t i = 0; i < num_components_in_composite; i++) { - if (!existing_entry->second[i]) { - all_components_match = false; - break; - } - } - if (all_components_match) { - // The two prefixes match on all sub-components, so we know that - // they are synonymous. We add this fact *non-recursively*, as we - // have deduced that |dd1_prefix| and |dd2_prefix| are synonymous - // by observing that all their sub-components are already - // synonymous. - assert(DataDescriptorsAreWellFormedAndComparable( - context, dd1_prefix, dd2_prefix)); - MakeEquivalent(dd1_prefix, dd2_prefix); - // Now that we know this pair of data descriptors are synonymous, - // there is no point recording how close they are to being - // synonymous. - candidate_composite_synonyms.erase(candidate_composite_synonym); - } - } - } - } - } -} - -void DataSynonymAndIdEquationFacts::MakeEquivalent( - const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2) { - // Register the data descriptors if they are not already known to the - // equivalence relation. - RegisterDataDescriptor(dd1); - RegisterDataDescriptor(dd2); - - if (synonymous_.IsEquivalent(dd1, dd2)) { - // The data descriptors are already known to be equivalent, so there is - // nothing to do. - return; - } - - // We must make the data descriptors equivalent, and also make sure any - // equation facts known about their representatives are merged. - - // Record the original equivalence class representatives of the data - // descriptors. - auto dd1_original_representative = synonymous_.Find(&dd1); - auto dd2_original_representative = synonymous_.Find(&dd2); - - // Make the data descriptors equivalent. - synonymous_.MakeEquivalent(dd1, dd2); - // As we have updated the equivalence relation, we might be able to deduce - // more facts by performing a closure computation, so we record that such a - // computation is required. - closure_computation_required_ = true; - - // At this point, exactly one of |dd1_original_representative| and - // |dd2_original_representative| will be the representative of the combined - // equivalence class. We work out which one of them is still the class - // representative and which one is no longer the class representative. - - auto still_representative = synonymous_.Find(dd1_original_representative) == - dd1_original_representative - ? dd1_original_representative - : dd2_original_representative; - auto no_longer_representative = - still_representative == dd1_original_representative - ? dd2_original_representative - : dd1_original_representative; - - assert(no_longer_representative != still_representative && - "The current and former representatives cannot be the same."); - - // We now need to add all equations about |no_longer_representative| to the - // set of equations known about |still_representative|. - - // Get the equations associated with |no_longer_representative|. - auto no_longer_representative_id_equations = - id_equations_.find(no_longer_representative); - if (no_longer_representative_id_equations != id_equations_.end()) { - // There are some equations to transfer. There might not yet be any - // equations about |still_representative|; create an empty set of equations - // if this is the case. - if (!id_equations_.count(still_representative)) { - id_equations_.insert({still_representative, OperationSet()}); - } - auto still_representative_id_equations = - id_equations_.find(still_representative); - assert(still_representative_id_equations != id_equations_.end() && - "At this point there must be a set of equations."); - // Add all the equations known about |no_longer_representative| to the set - // of equations known about |still_representative|. - still_representative_id_equations->second.insert( - no_longer_representative_id_equations->second.begin(), - no_longer_representative_id_equations->second.end()); - } - // Delete the no longer-relevant equations about |no_longer_representative|. - id_equations_.erase(no_longer_representative); -} - -const protobufs::DataDescriptor* -DataSynonymAndIdEquationFacts::RegisterDataDescriptor( - const protobufs::DataDescriptor& dd) { - return synonymous_.Exists(dd) ? synonymous_.Find(&dd) - : synonymous_.Register(dd); -} - -bool DataSynonymAndIdEquationFacts::DataDescriptorsAreWellFormedAndComparable( - opt::IRContext* context, const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2) { - auto end_type_id_1 = fuzzerutil::WalkCompositeTypeIndices( - context, context->get_def_use_mgr()->GetDef(dd1.object())->type_id(), - dd1.index()); - auto end_type_id_2 = fuzzerutil::WalkCompositeTypeIndices( - context, context->get_def_use_mgr()->GetDef(dd2.object())->type_id(), - dd2.index()); - // The end types of the data descriptors must exist. - if (end_type_id_1 == 0 || end_type_id_2 == 0) { - return false; - } - // Neither end type is allowed to be void. - if (context->get_def_use_mgr()->GetDef(end_type_id_1)->opcode() == - SpvOpTypeVoid || - context->get_def_use_mgr()->GetDef(end_type_id_2)->opcode() == - SpvOpTypeVoid) { - return false; - } - // If the end types are the same, the data descriptors are comparable. - if (end_type_id_1 == end_type_id_2) { - return true; - } - // Otherwise they are only comparable if they are integer scalars or integer - // vectors that differ only in signedness. - - // Get both types. - const auto* type_a = context->get_type_mgr()->GetType(end_type_id_1); - const auto* type_b = context->get_type_mgr()->GetType(end_type_id_2); - assert(type_a && type_b && "Data descriptors have invalid type(s)"); - - // If both types are numerical or vectors of numerical components, then they - // are compatible if they have the same number of components and the same bit - // count per component. - - if (type_a->AsVector() && type_b->AsVector()) { - const auto* vector_a = type_a->AsVector(); - const auto* vector_b = type_b->AsVector(); - - if (vector_a->element_count() != vector_b->element_count() || - vector_a->element_type()->AsBool() || - vector_b->element_type()->AsBool()) { - // The case where both vectors have boolean elements and the same number - // of components is handled by the direct equality check earlier. - // You can't have multiple identical boolean vector types. - return false; - } - - type_a = vector_a->element_type(); - type_b = vector_b->element_type(); - } - - auto get_bit_count_for_numeric_type = - [](const opt::analysis::Type& type) -> uint32_t { - if (const auto* integer = type.AsInteger()) { - return integer->width(); - } else if (const auto* floating = type.AsFloat()) { - return floating->width(); - } else { - assert(false && "|type| must be a numerical type"); - return 0; - } - }; - - // Checks that both |type_a| and |type_b| are either numerical or vectors of - // numerical components and have the same number of bits. - return (type_a->AsInteger() || type_a->AsFloat()) && - (type_b->AsInteger() || type_b->AsFloat()) && - (get_bit_count_for_numeric_type(*type_a) == - get_bit_count_for_numeric_type(*type_b)); -} - -std::vector -DataSynonymAndIdEquationFacts::GetSynonymsForDataDescriptor( - const protobufs::DataDescriptor& data_descriptor) const { - if (synonymous_.Exists(data_descriptor)) { - return synonymous_.GetEquivalenceClass(data_descriptor); - } - return {}; -} - -std::vector -DataSynonymAndIdEquationFacts::GetIdsForWhichSynonymsAreKnown() const { - std::vector result; - for (auto& data_descriptor : synonymous_.GetAllKnownValues()) { - if (data_descriptor->index().empty()) { - result.push_back(data_descriptor->object()); - } - } - return result; -} - -bool DataSynonymAndIdEquationFacts::IsSynonymous( - const protobufs::DataDescriptor& data_descriptor1, - const protobufs::DataDescriptor& data_descriptor2) const { - return synonymous_.Exists(data_descriptor1) && - synonymous_.Exists(data_descriptor2) && - synonymous_.IsEquivalent(data_descriptor1, data_descriptor2); -} - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h b/3rdparty/spirv-tools/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h deleted file mode 100644 index fb15e2ce8..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FACT_MANAGER_DATA_SYNONYM_AND_ID_EQUATION_FACTS_H_ -#define SOURCE_FUZZ_FACT_MANAGER_DATA_SYNONYM_AND_ID_EQUATION_FACTS_H_ - -#include -#include - -#include "source/fuzz/data_descriptor.h" -#include "source/fuzz/equivalence_relation.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -// The purpose of this class is to group the fields and data used to represent -// facts about data synonyms and id equations. -class DataSynonymAndIdEquationFacts { - public: - // See method in FactManager which delegates to this method. - void AddFact(const protobufs::FactDataSynonym& fact, opt::IRContext* context); - - // See method in FactManager which delegates to this method. - void AddFact(const protobufs::FactIdEquation& fact, opt::IRContext* context); - - // See method in FactManager which delegates to this method. - std::vector GetSynonymsForDataDescriptor( - const protobufs::DataDescriptor& data_descriptor) const; - - // See method in FactManager which delegates to this method. - std::vector GetIdsForWhichSynonymsAreKnown() const; - - // See method in FactManager which delegates to this method. - bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1, - const protobufs::DataDescriptor& data_descriptor2) const; - - // See method in FactManager which delegates to this method. - void ComputeClosureOfFacts(opt::IRContext* context, - uint32_t maximum_equivalence_class_size); - - private: - // This helper struct represents the right hand side of an equation as an - // operator applied to a number of data descriptor operands. - struct Operation { - SpvOp opcode; - std::vector operands; - }; - - // Hashing for operations, to allow deterministic unordered sets. - struct OperationHash { - size_t operator()(const Operation& operation) const; - }; - - // Equality for operations, to allow deterministic unordered sets. - struct OperationEquals { - bool operator()(const Operation& first, const Operation& second) const; - }; - - using OperationSet = - std::unordered_set; - - // Adds the synonym |dd1| = |dd2| to the set of managed facts, and recurses - // into sub-components of the data descriptors, if they are composites, to - // record that their components are pairwise-synonymous. - void AddDataSynonymFactRecursive(const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2, - opt::IRContext* context); - - // Computes various corollary facts from the data descriptor |dd| if members - // of its equivalence class participate in equation facts with OpConvert* - // opcodes. The descriptor should be registered in the equivalence relation. - void ComputeConversionDataSynonymFacts(const protobufs::DataDescriptor& dd, - opt::IRContext* context); - - // Recurses into sub-components of the data descriptors, if they are - // composites, to record that their components are pairwise-synonymous. - void ComputeCompositeDataSynonymFacts(const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2, - opt::IRContext* context); - - // Records the fact that |dd1| and |dd2| are equivalent, and merges the sets - // of equations that are known about them. - void MakeEquivalent(const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2); - - // Registers a data descriptor in the equivalence relation if it hasn't been - // registered yet, and returns its representative. - const protobufs::DataDescriptor* RegisterDataDescriptor( - const protobufs::DataDescriptor& dd); - - // Returns true if and only if |dd1| and |dd2| are valid data descriptors - // whose associated data have compatible types. Two types are compatible if: - // - they are the same - // - they both are numerical or vectors of numerical components with the same - // number of components and the same bit count per component - static bool DataDescriptorsAreWellFormedAndComparable( - opt::IRContext* context, const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2); - - OperationSet GetEquations(const protobufs::DataDescriptor* lhs) const; - - // Requires that |lhs_dd| and every element of |rhs_dds| is present in the - // |synonymous_| equivalence relation, but is not necessarily its own - // representative. Records the fact that the equation - // "|lhs_dd| |opcode| |rhs_dds_non_canonical|" holds, and adds any - // corollaries, in the form of data synonym or equation facts, that follow - // from this and other known facts. - void AddEquationFactRecursive( - const protobufs::DataDescriptor& lhs_dd, SpvOp opcode, - const std::vector& rhs_dds, - opt::IRContext* context); - - // The data descriptors that are known to be synonymous with one another are - // captured by this equivalence relation. - EquivalenceRelation - synonymous_; - - // When a new synonym fact is added, it may be possible to deduce further - // synonym facts by computing a closure of all known facts. However, this is - // an expensive operation, so it should be performed sparingly and only there - // is some chance of new facts being deduced. This boolean tracks whether a - // closure computation is required - i.e., whether a new fact has been added - // since the last time such a computation was performed. - bool closure_computation_required_ = false; - - // Represents a set of equations on data descriptors as a map indexed by - // left-hand-side, mapping a left-hand-side to a set of operations, each of - // which (together with the left-hand-side) defines an equation. - // - // All data descriptors occurring in equations are required to be present in - // the |synonymous_| equivalence relation, and to be their own representatives - // in that relation. - std::unordered_map - id_equations_; -}; - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FACT_MANAGER_DATA_SYNONYM_AND_ID_EQUATION_FACTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/dead_block_facts.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager/dead_block_facts.cpp deleted file mode 100644 index 86d51af5c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/dead_block_facts.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fact_manager/dead_block_facts.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -void DeadBlockFacts::AddFact(const protobufs::FactBlockIsDead& fact) { - dead_block_ids_.insert(fact.block_id()); -} - -bool DeadBlockFacts::BlockIsDead(uint32_t block_id) const { - return dead_block_ids_.count(block_id) != 0; -} - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/dead_block_facts.h b/3rdparty/spirv-tools/source/fuzz/fact_manager/dead_block_facts.h deleted file mode 100644 index ca3f71acf..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/dead_block_facts.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FACT_MANAGER_DEAD_BLOCK_FACTS_H_ -#define SOURCE_FUZZ_FACT_MANAGER_DEAD_BLOCK_FACTS_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -// The purpose of this class is to group the fields and data used to represent -// facts about data blocks. -class DeadBlockFacts { - public: - // See method in FactManager which delegates to this method. - void AddFact(const protobufs::FactBlockIsDead& fact); - - // See method in FactManager which delegates to this method. - bool BlockIsDead(uint32_t block_id) const; - - private: - std::unordered_set dead_block_ids_; -}; - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FACT_MANAGER_DEAD_BLOCK_FACTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/fact_manager.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager/fact_manager.cpp deleted file mode 100644 index cd9fccd44..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/fact_manager.cpp +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "fact_manager.h" - -#include -#include - -#include "source/fuzz/uniform_buffer_element_descriptor.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { -namespace { - -std::string ToString(const protobufs::FactConstantUniform& fact) { - std::stringstream stream; - stream << "(" << fact.uniform_buffer_element_descriptor().descriptor_set() - << ", " << fact.uniform_buffer_element_descriptor().binding() << ")["; - - bool first = true; - for (auto index : fact.uniform_buffer_element_descriptor().index()) { - if (first) { - first = false; - } else { - stream << ", "; - } - stream << index; - } - - stream << "] == ["; - - first = true; - for (auto constant_word : fact.constant_word()) { - if (first) { - first = false; - } else { - stream << ", "; - } - stream << constant_word; - } - - stream << "]"; - return stream.str(); -} - -std::string ToString(const protobufs::FactDataSynonym& fact) { - std::stringstream stream; - stream << fact.data1() << " = " << fact.data2(); - return stream.str(); -} - -std::string ToString(const protobufs::FactIdEquation& fact) { - std::stringstream stream; - stream << fact.lhs_id(); - stream << " " << static_cast(fact.opcode()); - for (auto rhs_id : fact.rhs_id()) { - stream << " " << rhs_id; - } - return stream.str(); -} - -std::string ToString(const protobufs::Fact& fact) { - switch (fact.fact_case()) { - case protobufs::Fact::kConstantUniformFact: - return ToString(fact.constant_uniform_fact()); - case protobufs::Fact::kDataSynonymFact: - return ToString(fact.data_synonym_fact()); - case protobufs::Fact::kIdEquationFact: - return ToString(fact.id_equation_fact()); - default: - assert(false && "Stringification not supported for this fact."); - return ""; - } -} - -} // namespace - -void FactManager::AddFacts(const MessageConsumer& message_consumer, - const protobufs::FactSequence& initial_facts, - opt::IRContext* context) { - for (auto& fact : initial_facts.fact()) { - if (!AddFact(fact, context)) { - auto message = "Invalid fact " + ToString(fact) + " ignored."; - message_consumer(SPV_MSG_WARNING, nullptr, {}, message.c_str()); - } - } -} - -bool FactManager::AddFact(const fuzz::protobufs::Fact& fact, - opt::IRContext* context) { - switch (fact.fact_case()) { - case protobufs::Fact::kConstantUniformFact: - return constant_uniform_facts_.AddFact(fact.constant_uniform_fact(), - context); - case protobufs::Fact::kDataSynonymFact: - data_synonym_and_id_equation_facts_.AddFact(fact.data_synonym_fact(), - context); - return true; - case protobufs::Fact::kBlockIsDeadFact: - dead_block_facts_.AddFact(fact.block_is_dead_fact()); - return true; - case protobufs::Fact::kFunctionIsLivesafeFact: - livesafe_function_facts_.AddFact(fact.function_is_livesafe_fact()); - return true; - default: - assert(false && "Unknown fact type."); - return false; - } -} - -void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1, - const protobufs::DataDescriptor& data2, - opt::IRContext* context) { - protobufs::FactDataSynonym fact; - *fact.mutable_data1() = data1; - *fact.mutable_data2() = data2; - data_synonym_and_id_equation_facts_.AddFact(fact, context); -} - -std::vector FactManager::GetConstantsAvailableFromUniformsForType( - opt::IRContext* ir_context, uint32_t type_id) const { - return constant_uniform_facts_.GetConstantsAvailableFromUniformsForType( - ir_context, type_id); -} - -std::vector -FactManager::GetUniformDescriptorsForConstant(opt::IRContext* ir_context, - uint32_t constant_id) const { - return constant_uniform_facts_.GetUniformDescriptorsForConstant(ir_context, - constant_id); -} - -uint32_t FactManager::GetConstantFromUniformDescriptor( - opt::IRContext* context, - const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const { - return constant_uniform_facts_.GetConstantFromUniformDescriptor( - context, uniform_descriptor); -} - -std::vector FactManager::GetTypesForWhichUniformValuesAreKnown() - const { - return constant_uniform_facts_.GetTypesForWhichUniformValuesAreKnown(); -} - -const std::vector>& -FactManager::GetConstantUniformFactsAndTypes() const { - return constant_uniform_facts_.GetConstantUniformFactsAndTypes(); -} - -std::vector FactManager::GetIdsForWhichSynonymsAreKnown() const { - return data_synonym_and_id_equation_facts_.GetIdsForWhichSynonymsAreKnown(); -} - -std::vector -FactManager::GetSynonymsForDataDescriptor( - const protobufs::DataDescriptor& data_descriptor) const { - return data_synonym_and_id_equation_facts_.GetSynonymsForDataDescriptor( - data_descriptor); -} - -std::vector FactManager::GetSynonymsForId( - uint32_t id) const { - return GetSynonymsForDataDescriptor(MakeDataDescriptor(id, {})); -} - -bool FactManager::IsSynonymous( - const protobufs::DataDescriptor& data_descriptor1, - const protobufs::DataDescriptor& data_descriptor2) const { - return data_synonym_and_id_equation_facts_.IsSynonymous(data_descriptor1, - data_descriptor2); -} - -bool FactManager::BlockIsDead(uint32_t block_id) const { - return dead_block_facts_.BlockIsDead(block_id); -} - -void FactManager::AddFactBlockIsDead(uint32_t block_id) { - protobufs::FactBlockIsDead fact; - fact.set_block_id(block_id); - dead_block_facts_.AddFact(fact); -} - -bool FactManager::FunctionIsLivesafe(uint32_t function_id) const { - return livesafe_function_facts_.FunctionIsLivesafe(function_id); -} - -void FactManager::AddFactFunctionIsLivesafe(uint32_t function_id) { - protobufs::FactFunctionIsLivesafe fact; - fact.set_function_id(function_id); - livesafe_function_facts_.AddFact(fact); -} - -bool FactManager::PointeeValueIsIrrelevant(uint32_t pointer_id) const { - return irrelevant_value_facts_.PointeeValueIsIrrelevant(pointer_id); -} - -bool FactManager::IdIsIrrelevant(uint32_t result_id) const { - return irrelevant_value_facts_.IdIsIrrelevant(result_id); -} - -void FactManager::AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id) { - protobufs::FactPointeeValueIsIrrelevant fact; - fact.set_pointer_id(pointer_id); - irrelevant_value_facts_.AddFact(fact); -} - -void FactManager::AddFactIdIsIrrelevant(uint32_t result_id) { - protobufs::FactIdIsIrrelevant fact; - fact.set_result_id(result_id); - irrelevant_value_facts_.AddFact(fact); -} - -void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode, - const std::vector& rhs_id, - opt::IRContext* context) { - protobufs::FactIdEquation fact; - fact.set_lhs_id(lhs_id); - fact.set_opcode(opcode); - for (auto an_rhs_id : rhs_id) { - fact.add_rhs_id(an_rhs_id); - } - data_synonym_and_id_equation_facts_.AddFact(fact, context); -} - -void FactManager::ComputeClosureOfFacts( - opt::IRContext* ir_context, uint32_t maximum_equivalence_class_size) { - data_synonym_and_id_equation_facts_.ComputeClosureOfFacts( - ir_context, maximum_equivalence_class_size); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/fact_manager.h b/3rdparty/spirv-tools/source/fuzz/fact_manager/fact_manager.h deleted file mode 100644 index 89d1ab04e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/fact_manager.h +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FACT_MANAGER_FACT_MANAGER_H_ -#define SOURCE_FUZZ_FACT_MANAGER_FACT_MANAGER_H_ - -#include -#include -#include - -#include "source/fuzz/data_descriptor.h" -#include "source/fuzz/fact_manager/constant_uniform_facts.h" -#include "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h" -#include "source/fuzz/fact_manager/dead_block_facts.h" -#include "source/fuzz/fact_manager/irrelevant_value_facts.h" -#include "source/fuzz/fact_manager/livesafe_function_facts.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/constants.h" - -namespace spvtools { -namespace fuzz { - -// Keeps track of facts about the module being transformed on which the fuzzing -// process can depend. Some initial facts can be provided, for example about -// guarantees on the values of inputs to SPIR-V entry points. Transformations -// may then rely on these facts, can add further facts that they establish. -// Facts are intended to be simple properties that either cannot be deduced from -// the module (such as properties that are guaranteed to hold for entry point -// inputs), or that are established by transformations, likely to be useful for -// future transformations, and not completely trivial to deduce straight from -// the module. -class FactManager { - public: - // Adds all the facts from |facts|, checking them for validity with respect to - // |context|. Warnings about invalid facts are communicated via - // |message_consumer|; such facts are otherwise ignored. - void AddFacts(const MessageConsumer& message_consumer, - const protobufs::FactSequence& facts, opt::IRContext* context); - - // Checks the fact for validity with respect to |context|. Returns false, - // with no side effects, if the fact is invalid. Otherwise adds |fact| to the - // fact manager. - bool AddFact(const protobufs::Fact& fact, opt::IRContext* context); - - // Record the fact that |data1| and |data2| are synonymous. - void AddFactDataSynonym(const protobufs::DataDescriptor& data1, - const protobufs::DataDescriptor& data2, - opt::IRContext* context); - - // Records the fact that |block_id| is dead. - void AddFactBlockIsDead(uint32_t block_id); - - // Records the fact that |function_id| is livesafe. - void AddFactFunctionIsLivesafe(uint32_t function_id); - - // Records the fact that the value of the pointee associated with |pointer_id| - // is irrelevant: it does not affect the observable behaviour of the module. - void AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id); - - // Records a fact that the |result_id| is irrelevant (i.e. it doesn't affect - // the semantics of the module) - void AddFactIdIsIrrelevant(uint32_t result_id); - - // Records the fact that |lhs_id| is defined by the equation: - // - // |lhs_id| = |opcode| |rhs_id[0]| ... |rhs_id[N-1]| - // - void AddFactIdEquation(uint32_t lhs_id, SpvOp opcode, - const std::vector& rhs_id, - opt::IRContext* context); - - // Inspects all known facts and adds corollary facts; e.g. if we know that - // a.x == b.x and a.y == b.y, where a and b have vec2 type, we can record - // that a == b holds. - // - // This method is expensive, and should only be called (by applying a - // transformation) at the start of a fuzzer pass that depends on data - // synonym facts, rather than calling it every time a new data synonym fact - // is added. - // - // The parameter |maximum_equivalence_class_size| specifies the size beyond - // which equivalence classes should not be mined for new facts, to avoid - // excessively-long closure computations. - void ComputeClosureOfFacts(opt::IRContext* ir_context, - uint32_t maximum_equivalence_class_size); - - // The fact manager is responsible for managing a few distinct categories of - // facts. In principle there could be different fact managers for each kind - // of fact, but in practice providing one 'go to' place for facts is - // convenient. To keep some separation, the public methods of the fact - // manager should be grouped according to the kind of fact to which they - // relate. - - //============================== - // Querying facts about uniform constants - - // Provides the distinct type ids for which at least one "constant == - // uniform element" fact is known. - std::vector GetTypesForWhichUniformValuesAreKnown() const; - - // Provides distinct constant ids with type |type_id| for which at least one - // "constant == uniform element" fact is known. If multiple identically- - // valued constants are relevant, only one will appear in the sequence. - std::vector GetConstantsAvailableFromUniformsForType( - opt::IRContext* ir_context, uint32_t type_id) const; - - // Provides details of all uniform elements that are known to be equal to the - // constant associated with |constant_id| in |ir_context|. - std::vector - GetUniformDescriptorsForConstant(opt::IRContext* ir_context, - uint32_t constant_id) const; - - // Returns the id of a constant whose value is known to match that of - // |uniform_descriptor|, and whose type matches the type of the uniform - // element. If multiple such constant is exist, the one that is returned - // is arbitrary. Returns 0 if no such constant id exists. - uint32_t GetConstantFromUniformDescriptor( - opt::IRContext* context, - const protobufs::UniformBufferElementDescriptor& uniform_descriptor) - const; - - // Returns all "constant == uniform element" facts known to the fact - // manager, pairing each fact with id of the type that is associated with - // both the constant and the uniform element. - const std::vector>& - GetConstantUniformFactsAndTypes() const; - - // End of uniform constant facts - //============================== - - //============================== - // Querying facts about id synonyms - - // Returns every id for which a fact of the form "this id is synonymous with - // this piece of data" is known. - std::vector GetIdsForWhichSynonymsAreKnown() const; - - // Returns the equivalence class of all known synonyms of |id|, or an empty - // set if no synonyms are known. - std::vector GetSynonymsForId( - uint32_t id) const; - - // Returns the equivalence class of all known synonyms of |data_descriptor|, - // or empty if no synonyms are known. - std::vector GetSynonymsForDataDescriptor( - const protobufs::DataDescriptor& data_descriptor) const; - - // Returns true if and ony if |data_descriptor1| and |data_descriptor2| are - // known to be synonymous. - bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1, - const protobufs::DataDescriptor& data_descriptor2) const; - - // End of id synonym facts - //============================== - - //============================== - // Querying facts about dead blocks - - // Returns true if and ony if |block_id| is the id of a block known to be - // dynamically unreachable. - bool BlockIsDead(uint32_t block_id) const; - - // End of dead block facts - //============================== - - //============================== - // Querying facts about livesafe function - - // Returns true if and ony if |function_id| is the id of a function known - // to be livesafe. - bool FunctionIsLivesafe(uint32_t function_id) const; - - // End of dead livesafe function facts - //============================== - - //============================== - // Querying facts about irrelevant values - - // Returns true if and ony if the value of the pointee associated with - // |pointer_id| is irrelevant. - bool PointeeValueIsIrrelevant(uint32_t pointer_id) const; - - // Returns true iff there exists a fact that the |result_id| is irrelevant. - bool IdIsIrrelevant(uint32_t result_id) const; - - // End of irrelevant value facts - //============================== - - private: - // Keep these in alphabetical order. - fact_manager::ConstantUniformFacts constant_uniform_facts_; - fact_manager::DataSynonymAndIdEquationFacts - data_synonym_and_id_equation_facts_; - fact_manager::DeadBlockFacts dead_block_facts_; - fact_manager::LivesafeFunctionFacts livesafe_function_facts_; - fact_manager::IrrelevantValueFacts irrelevant_value_facts_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FACT_MANAGER_FACT_MANAGER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/irrelevant_value_facts.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager/irrelevant_value_facts.cpp deleted file mode 100644 index 85e2b6f1e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/irrelevant_value_facts.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fact_manager/irrelevant_value_facts.h" - -#include "source/fuzz/data_descriptor.h" -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -void IrrelevantValueFacts::AddFact( - const protobufs::FactPointeeValueIsIrrelevant& fact) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550) - // Assert that the id does not participate in DataSynonym facts and is a - // pointer. - - pointers_to_irrelevant_pointees_ids_.insert(fact.pointer_id()); -} - -void IrrelevantValueFacts::AddFact(const protobufs::FactIdIsIrrelevant& fact) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550) - // Assert that the id does not participate in DataSynonym facts and is not a - // pointer. - - irrelevant_ids_.insert(fact.result_id()); -} - -bool IrrelevantValueFacts::PointeeValueIsIrrelevant(uint32_t pointer_id) const { - return pointers_to_irrelevant_pointees_ids_.count(pointer_id) != 0; -} - -bool IrrelevantValueFacts::IdIsIrrelevant(uint32_t pointer_id) const { - return irrelevant_ids_.count(pointer_id) != 0; -} - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/irrelevant_value_facts.h b/3rdparty/spirv-tools/source/fuzz/fact_manager/irrelevant_value_facts.h deleted file mode 100644 index ca926c78a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/irrelevant_value_facts.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FACT_MANAGER_IRRELEVANT_VALUE_FACTS_H_ -#define SOURCE_FUZZ_FACT_MANAGER_IRRELEVANT_VALUE_FACTS_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -// The purpose of this class is to group the fields and data used to represent -// facts about various irrelevant values in the module. -class IrrelevantValueFacts { - public: - // See method in FactManager which delegates to this method. - void AddFact(const protobufs::FactPointeeValueIsIrrelevant& fact); - - // See method in FactManager which delegates to this method. - void AddFact(const protobufs::FactIdIsIrrelevant& fact); - - // See method in FactManager which delegates to this method. - bool PointeeValueIsIrrelevant(uint32_t pointer_id) const; - - // See method in FactManager which delegates to this method. - bool IdIsIrrelevant(uint32_t pointer_id) const; - - private: - std::unordered_set pointers_to_irrelevant_pointees_ids_; - std::unordered_set irrelevant_ids_; -}; - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FACT_MANAGER_IRRELEVANT_VALUE_FACTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/livesafe_function_facts.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager/livesafe_function_facts.cpp deleted file mode 100644 index 6f36afb6e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/livesafe_function_facts.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fact_manager/livesafe_function_facts.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -void LivesafeFunctionFacts::AddFact( - const protobufs::FactFunctionIsLivesafe& fact) { - livesafe_function_ids_.insert(fact.function_id()); -} - -bool LivesafeFunctionFacts::FunctionIsLivesafe(uint32_t function_id) const { - return livesafe_function_ids_.count(function_id) != 0; -} - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager/livesafe_function_facts.h b/3rdparty/spirv-tools/source/fuzz/fact_manager/livesafe_function_facts.h deleted file mode 100644 index 8c4850630..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager/livesafe_function_facts.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FACT_MANAGER_LIVESAFE_FUNCTION_FACTS_H_ -#define SOURCE_FUZZ_FACT_MANAGER_LIVESAFE_FUNCTION_FACTS_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" - -namespace spvtools { -namespace fuzz { -namespace fact_manager { - -// The purpose of this class is to group the fields and data used to represent -// facts about livesafe functions. -class LivesafeFunctionFacts { - public: - // See method in FactManager which delegates to this method. - void AddFact(const protobufs::FactFunctionIsLivesafe& fact); - - // See method in FactManager which delegates to this method. - bool FunctionIsLivesafe(uint32_t function_id) const; - - private: - std::unordered_set livesafe_function_ids_; -}; - -} // namespace fact_manager -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FACT_MANAGER_LIVESAFE_FUNCTION_FACTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/force_render_red.cpp b/3rdparty/spirv-tools/source/fuzz/force_render_red.cpp deleted file mode 100644 index 2a9d56f9f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/force_render_red.cpp +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/force_render_red.h" - -#include "source/fuzz/fact_manager/fact_manager.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/transformation_context.h" -#include "source/fuzz/transformation_replace_constant_with_uniform.h" -#include "source/fuzz/uniform_buffer_element_descriptor.h" -#include "source/opt/build_module.h" -#include "source/opt/ir_context.h" -#include "source/opt/types.h" -#include "source/util/make_unique.h" -#include "tools/util/cli_consumer.h" - -namespace spvtools { -namespace fuzz { - -namespace { - -// Helper method to find the fragment shader entry point, complaining if there -// is no shader or if there is no fragment entry point. -opt::Function* FindFragmentShaderEntryPoint(opt::IRContext* ir_context, - MessageConsumer message_consumer) { - // Check that this is a fragment shader - bool found_capability_shader = false; - for (auto& capability : ir_context->capabilities()) { - assert(capability.opcode() == SpvOpCapability); - if (capability.GetSingleWordInOperand(0) == SpvCapabilityShader) { - found_capability_shader = true; - break; - } - } - if (!found_capability_shader) { - message_consumer( - SPV_MSG_ERROR, nullptr, {}, - "Forcing of red rendering requires the Shader capability."); - return nullptr; - } - - opt::Instruction* fragment_entry_point = nullptr; - for (auto& entry_point : ir_context->module()->entry_points()) { - if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelFragment) { - fragment_entry_point = &entry_point; - break; - } - } - if (fragment_entry_point == nullptr) { - message_consumer(SPV_MSG_ERROR, nullptr, {}, - "Forcing of red rendering requires an entry point with " - "the Fragment execution model."); - return nullptr; - } - - for (auto& function : *ir_context->module()) { - if (function.result_id() == - fragment_entry_point->GetSingleWordInOperand(1)) { - return &function; - } - } - assert( - false && - "A valid module must have a function associate with each entry point."); - return nullptr; -} - -// Helper method to check that there is a single vec4 output variable and get a -// pointer to it. -opt::Instruction* FindVec4OutputVariable(opt::IRContext* ir_context, - MessageConsumer message_consumer) { - opt::Instruction* output_variable = nullptr; - for (auto& inst : ir_context->types_values()) { - if (inst.opcode() == SpvOpVariable && - inst.GetSingleWordInOperand(0) == SpvStorageClassOutput) { - if (output_variable != nullptr) { - message_consumer(SPV_MSG_ERROR, nullptr, {}, - "Only one output variable can be handled at present; " - "found multiple."); - return nullptr; - } - output_variable = &inst; - // Do not break, as we want to check for multiple output variables. - } - } - if (output_variable == nullptr) { - message_consumer(SPV_MSG_ERROR, nullptr, {}, - "No output variable to which to write red was found."); - return nullptr; - } - - auto output_variable_base_type = ir_context->get_type_mgr() - ->GetType(output_variable->type_id()) - ->AsPointer() - ->pointee_type() - ->AsVector(); - if (!output_variable_base_type || - output_variable_base_type->element_count() != 4 || - !output_variable_base_type->element_type()->AsFloat()) { - message_consumer(SPV_MSG_ERROR, nullptr, {}, - "The output variable must have type vec4."); - return nullptr; - } - - return output_variable; -} - -// Helper to get the ids of float constants 0.0 and 1.0, creating them if -// necessary. -std::pair FindOrCreateFloatZeroAndOne( - opt::IRContext* ir_context, opt::analysis::Float* float_type) { - float one = 1.0; - uint32_t one_as_uint; - memcpy(&one_as_uint, &one, sizeof(float)); - std::vector zero_bytes = {0}; - std::vector one_bytes = {one_as_uint}; - auto constant_zero = ir_context->get_constant_mgr()->RegisterConstant( - MakeUnique(float_type, zero_bytes)); - auto constant_one = ir_context->get_constant_mgr()->RegisterConstant( - MakeUnique(float_type, one_bytes)); - auto constant_zero_id = ir_context->get_constant_mgr() - ->GetDefiningInstruction(constant_zero) - ->result_id(); - auto constant_one_id = ir_context->get_constant_mgr() - ->GetDefiningInstruction(constant_one) - ->result_id(); - return std::pair(constant_zero_id, constant_one_id); -} - -std::unique_ptr -MakeConstantUniformReplacement(opt::IRContext* ir_context, - const FactManager& fact_manager, - uint32_t constant_id, - uint32_t greater_than_instruction, - uint32_t in_operand_index) { - return MakeUnique( - MakeIdUseDescriptor(constant_id, - MakeInstructionDescriptor(greater_than_instruction, - SpvOpFOrdGreaterThan, 0), - in_operand_index), - fact_manager.GetUniformDescriptorsForConstant(ir_context, constant_id)[0], - ir_context->TakeNextId(), ir_context->TakeNextId()); -} - -} // namespace - -bool ForceRenderRed( - const spv_target_env& target_env, spv_validator_options validator_options, - const std::vector& binary_in, - const spvtools::fuzz::protobufs::FactSequence& initial_facts, - std::vector* binary_out) { - auto message_consumer = spvtools::utils::CLIMessageConsumer; - spvtools::SpirvTools tools(target_env); - if (!tools.IsValid()) { - message_consumer(SPV_MSG_ERROR, nullptr, {}, - "Failed to create SPIRV-Tools interface; stopping."); - return false; - } - - // Initial binary should be valid. - if (!tools.Validate(&binary_in[0], binary_in.size(), validator_options)) { - message_consumer(SPV_MSG_ERROR, nullptr, {}, - "Initial binary is invalid; stopping."); - return false; - } - - // Build the module from the input binary. - std::unique_ptr ir_context = BuildModule( - target_env, message_consumer, binary_in.data(), binary_in.size()); - assert(ir_context); - - // Set up a fact manager with any given initial facts. - FactManager fact_manager; - for (auto& fact : initial_facts.fact()) { - fact_manager.AddFact(fact, ir_context.get()); - } - TransformationContext transformation_context(&fact_manager, - validator_options); - - auto entry_point_function = - FindFragmentShaderEntryPoint(ir_context.get(), message_consumer); - auto output_variable = - FindVec4OutputVariable(ir_context.get(), message_consumer); - if (entry_point_function == nullptr || output_variable == nullptr) { - return false; - } - - opt::analysis::Float temp_float_type(32); - opt::analysis::Float* float_type = ir_context->get_type_mgr() - ->GetRegisteredType(&temp_float_type) - ->AsFloat(); - std::pair zero_one_float_ids = - FindOrCreateFloatZeroAndOne(ir_context.get(), float_type); - - // Make the new exit block - auto new_exit_block_id = ir_context->TakeNextId(); - { - auto label = MakeUnique(ir_context.get(), SpvOpLabel, 0, - new_exit_block_id, - opt::Instruction::OperandList()); - auto new_exit_block = MakeUnique(std::move(label)); - new_exit_block->AddInstruction(MakeUnique( - ir_context.get(), SpvOpReturn, 0, 0, opt::Instruction::OperandList())); - entry_point_function->AddBasicBlock(std::move(new_exit_block)); - } - - // Make the new entry block - { - auto label = MakeUnique(ir_context.get(), SpvOpLabel, 0, - ir_context->TakeNextId(), - opt::Instruction::OperandList()); - auto new_entry_block = MakeUnique(std::move(label)); - - // Make an instruction to construct vec4(1.0, 0.0, 0.0, 1.0), representing - // the colour red. - opt::Operand zero_float = {SPV_OPERAND_TYPE_ID, {zero_one_float_ids.first}}; - opt::Operand one_float = {SPV_OPERAND_TYPE_ID, {zero_one_float_ids.second}}; - opt::Instruction::OperandList op_composite_construct_operands = { - one_float, zero_float, zero_float, one_float}; - auto temp_vec4 = opt::analysis::Vector(float_type, 4); - auto vec4_id = ir_context->get_type_mgr()->GetId(&temp_vec4); - auto red = MakeUnique( - ir_context.get(), SpvOpCompositeConstruct, vec4_id, - ir_context->TakeNextId(), op_composite_construct_operands); - auto red_id = red->result_id(); - new_entry_block->AddInstruction(std::move(red)); - - // Make an instruction to store red into the output color. - opt::Operand variable_to_store_into = {SPV_OPERAND_TYPE_ID, - {output_variable->result_id()}}; - opt::Operand value_to_be_stored = {SPV_OPERAND_TYPE_ID, {red_id}}; - opt::Instruction::OperandList op_store_operands = {variable_to_store_into, - value_to_be_stored}; - new_entry_block->AddInstruction(MakeUnique( - ir_context.get(), SpvOpStore, 0, 0, op_store_operands)); - - // We are going to attempt to construct 'false' as an expression of the form - // 'literal1 > literal2'. If we succeed, we will later replace each literal - // with a uniform of the same value - we can only do that replacement once - // we have added the entry block to the module. - std::unique_ptr - first_greater_then_operand_replacement = nullptr; - std::unique_ptr - second_greater_then_operand_replacement = nullptr; - uint32_t id_guaranteed_to_be_false = 0; - - opt::analysis::Bool temp_bool_type; - opt::analysis::Bool* registered_bool_type = - ir_context->get_type_mgr() - ->GetRegisteredType(&temp_bool_type) - ->AsBool(); - - auto float_type_id = ir_context->get_type_mgr()->GetId(float_type); - auto types_for_which_uniforms_are_known = - fact_manager.GetTypesForWhichUniformValuesAreKnown(); - - // Check whether we have any float uniforms. - if (std::find(types_for_which_uniforms_are_known.begin(), - types_for_which_uniforms_are_known.end(), - float_type_id) != types_for_which_uniforms_are_known.end()) { - // We have at least one float uniform; let's see whether we have at least - // two. - auto available_constants = - fact_manager.GetConstantsAvailableFromUniformsForType( - ir_context.get(), float_type_id); - if (available_constants.size() > 1) { - // Grab the float constants associated with the first two known float - // uniforms. - auto first_constant = - ir_context->get_constant_mgr() - ->GetConstantFromInst(ir_context->get_def_use_mgr()->GetDef( - available_constants[0])) - ->AsFloatConstant(); - auto second_constant = - ir_context->get_constant_mgr() - ->GetConstantFromInst(ir_context->get_def_use_mgr()->GetDef( - available_constants[1])) - ->AsFloatConstant(); - - // Now work out which of the two constants is larger than the other. - uint32_t larger_constant_index = 0; - uint32_t smaller_constant_index = 0; - if (first_constant->GetFloat() > second_constant->GetFloat()) { - larger_constant_index = 0; - smaller_constant_index = 1; - } else if (first_constant->GetFloat() < second_constant->GetFloat()) { - larger_constant_index = 1; - smaller_constant_index = 0; - } - - // Only proceed with these constants if they have turned out to be - // distinct. - if (larger_constant_index != smaller_constant_index) { - // We are in a position to create 'false' as 'literal1 > literal2', so - // reserve an id for this computation; this id will end up being - // guaranteed to be 'false'. - id_guaranteed_to_be_false = ir_context->TakeNextId(); - - auto smaller_constant = available_constants[smaller_constant_index]; - auto larger_constant = available_constants[larger_constant_index]; - - opt::Instruction::OperandList greater_than_operands = { - {SPV_OPERAND_TYPE_ID, {smaller_constant}}, - {SPV_OPERAND_TYPE_ID, {larger_constant}}}; - new_entry_block->AddInstruction(MakeUnique( - ir_context.get(), SpvOpFOrdGreaterThan, - ir_context->get_type_mgr()->GetId(registered_bool_type), - id_guaranteed_to_be_false, greater_than_operands)); - - first_greater_then_operand_replacement = - MakeConstantUniformReplacement(ir_context.get(), fact_manager, - smaller_constant, - id_guaranteed_to_be_false, 0); - second_greater_then_operand_replacement = - MakeConstantUniformReplacement(ir_context.get(), fact_manager, - larger_constant, - id_guaranteed_to_be_false, 1); - } - } - } - - if (id_guaranteed_to_be_false == 0) { - auto constant_false = ir_context->get_constant_mgr()->RegisterConstant( - MakeUnique(registered_bool_type, false)); - id_guaranteed_to_be_false = ir_context->get_constant_mgr() - ->GetDefiningInstruction(constant_false) - ->result_id(); - } - - opt::Operand false_condition = {SPV_OPERAND_TYPE_ID, - {id_guaranteed_to_be_false}}; - opt::Operand then_block = {SPV_OPERAND_TYPE_ID, - {entry_point_function->entry()->id()}}; - opt::Operand else_block = {SPV_OPERAND_TYPE_ID, {new_exit_block_id}}; - opt::Instruction::OperandList op_branch_conditional_operands = { - false_condition, then_block, else_block}; - new_entry_block->AddInstruction( - MakeUnique(ir_context.get(), SpvOpBranchConditional, - 0, 0, op_branch_conditional_operands)); - - entry_point_function->InsertBasicBlockBefore( - std::move(new_entry_block), entry_point_function->entry().get()); - - for (auto& replacement : {first_greater_then_operand_replacement.get(), - second_greater_then_operand_replacement.get()}) { - if (replacement) { - assert(replacement->IsApplicable(ir_context.get(), - transformation_context)); - replacement->Apply(ir_context.get(), &transformation_context); - } - } - } - - // Write out the module as a binary. - ir_context->module()->ToBinary(binary_out, false); - return true; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/force_render_red.h b/3rdparty/spirv-tools/source/fuzz/force_render_red.h deleted file mode 100644 index b51c72b46..000000000 --- a/3rdparty/spirv-tools/source/fuzz/force_render_red.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FORCE_RENDER_RED_H_ -#define SOURCE_FORCE_RENDER_RED_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace fuzz { - -// Requires |binary_in| to be a valid SPIR-V module with Shader capability, -// containing an entry point with the Fragment execution model, and a single -// output variable of type vec4. -// -// Turns the body of this entry point into effectively: -// -// output_variable = vec4(1.0, 0.0, 0.0, 1.0); -// if (false) { -// original_body -// } -// -// If suitable facts about values of uniforms are available, the 'false' will -// instead become: 'u > v', where 'u' and 'v' are pieces of uniform data for -// which it is known that 'u < v' holds. -bool ForceRenderRed( - const spv_target_env& target_env, spv_validator_options validator_options, - const std::vector& binary_in, - const spvtools::fuzz::protobufs::FactSequence& initial_facts, - std::vector* binary_out); - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FORCE_RENDER_RED_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp deleted file mode 100644 index 4cf3ba37c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer.h" - -#include -#include - -#include "source/fuzz/fact_manager/fact_manager.h" -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_pass_add_access_chains.h" -#include "source/fuzz/fuzzer_pass_add_composite_inserts.h" -#include "source/fuzz/fuzzer_pass_add_composite_types.h" -#include "source/fuzz/fuzzer_pass_add_copy_memory.h" -#include "source/fuzz/fuzzer_pass_add_dead_blocks.h" -#include "source/fuzz/fuzzer_pass_add_dead_breaks.h" -#include "source/fuzz/fuzzer_pass_add_dead_continues.h" -#include "source/fuzz/fuzzer_pass_add_equation_instructions.h" -#include "source/fuzz/fuzzer_pass_add_function_calls.h" -#include "source/fuzz/fuzzer_pass_add_global_variables.h" -#include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h" -#include "source/fuzz/fuzzer_pass_add_loads.h" -#include "source/fuzz/fuzzer_pass_add_local_variables.h" -#include "source/fuzz/fuzzer_pass_add_loop_preheaders.h" -#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h" -#include "source/fuzz/fuzzer_pass_add_opphi_synonyms.h" -#include "source/fuzz/fuzzer_pass_add_parameters.h" -#include "source/fuzz/fuzzer_pass_add_relaxed_decorations.h" -#include "source/fuzz/fuzzer_pass_add_stores.h" -#include "source/fuzz/fuzzer_pass_add_synonyms.h" -#include "source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h" -#include "source/fuzz/fuzzer_pass_adjust_branch_weights.h" -#include "source/fuzz/fuzzer_pass_adjust_function_controls.h" -#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h" -#include "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h" -#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h" -#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h" -#include "source/fuzz/fuzzer_pass_construct_composites.h" -#include "source/fuzz/fuzzer_pass_copy_objects.h" -#include "source/fuzz/fuzzer_pass_donate_modules.h" -#include "source/fuzz/fuzzer_pass_inline_functions.h" -#include "source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h" -#include "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h" -#include "source/fuzz/fuzzer_pass_invert_comparison_operators.h" -#include "source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h" -#include "source/fuzz/fuzzer_pass_merge_blocks.h" -#include "source/fuzz/fuzzer_pass_obfuscate_constants.h" -#include "source/fuzz/fuzzer_pass_outline_functions.h" -#include "source/fuzz/fuzzer_pass_permute_blocks.h" -#include "source/fuzz/fuzzer_pass_permute_function_parameters.h" -#include "source/fuzz/fuzzer_pass_permute_instructions.h" -#include "source/fuzz/fuzzer_pass_permute_phi_operands.h" -#include "source/fuzz/fuzzer_pass_propagate_instructions_up.h" -#include "source/fuzz/fuzzer_pass_push_ids_through_variables.h" -#include "source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h" -#include "source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h" -#include "source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h" -#include "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h" -#include "source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h" -#include "source/fuzz/fuzzer_pass_replace_parameter_with_global.h" -#include "source/fuzz/fuzzer_pass_replace_params_with_struct.h" -#include "source/fuzz/fuzzer_pass_split_blocks.h" -#include "source/fuzz/fuzzer_pass_swap_commutable_operands.h" -#include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h" -#include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/pseudo_random_generator.h" -#include "source/fuzz/transformation_context.h" -#include "source/opt/build_module.h" -#include "source/spirv_fuzzer_options.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { - -namespace { -const uint32_t kIdBoundGap = 100; - -const uint32_t kTransformationLimit = 500; - -const uint32_t kChanceOfApplyingAnotherPass = 85; - -// A convenience method to add a fuzzer pass to |passes| with probability 0.5. -// All fuzzer passes take |ir_context|, |transformation_context|, -// |fuzzer_context| and |transformation_sequence_out| as parameters. Extra -// arguments can be provided via |extra_args|. -template -void MaybeAddPass( - std::vector>* passes, - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformation_sequence_out, - Args&&... extra_args) { - if (fuzzer_context->ChooseEven()) { - passes->push_back(MakeUnique(ir_context, transformation_context, - fuzzer_context, transformation_sequence_out, - std::forward(extra_args)...)); - } -} - -} // namespace - -Fuzzer::Fuzzer(spv_target_env target_env, uint32_t seed, - bool validate_after_each_fuzzer_pass, - spv_validator_options validator_options) - : target_env_(target_env), - seed_(seed), - validate_after_each_fuzzer_pass_(validate_after_each_fuzzer_pass), - validator_options_(validator_options) {} - -Fuzzer::~Fuzzer() = default; - -void Fuzzer::SetMessageConsumer(MessageConsumer consumer) { - consumer_ = std::move(consumer); -} - -bool Fuzzer::ApplyPassAndCheckValidity( - FuzzerPass* pass, const opt::IRContext& ir_context, - const spvtools::SpirvTools& tools) const { - pass->Apply(); - if (validate_after_each_fuzzer_pass_) { - std::vector binary_to_validate; - ir_context.module()->ToBinary(&binary_to_validate, false); - if (!tools.Validate(&binary_to_validate[0], binary_to_validate.size(), - validator_options_)) { - consumer_(SPV_MSG_INFO, nullptr, {}, - "Binary became invalid during fuzzing (set a breakpoint to " - "inspect); stopping."); - return false; - } - } - return true; -} - -Fuzzer::FuzzerResultStatus Fuzzer::Run( - const std::vector& binary_in, - const protobufs::FactSequence& initial_facts, - const std::vector& donor_suppliers, - std::vector* binary_out, - protobufs::TransformationSequence* transformation_sequence_out) const { - // Check compatibility between the library version being linked with and the - // header files being used. - GOOGLE_PROTOBUF_VERIFY_VERSION; - - spvtools::SpirvTools tools(target_env_); - tools.SetMessageConsumer(consumer_); - if (!tools.IsValid()) { - consumer_(SPV_MSG_ERROR, nullptr, {}, - "Failed to create SPIRV-Tools interface; stopping."); - return Fuzzer::FuzzerResultStatus::kFailedToCreateSpirvToolsInterface; - } - - // Initial binary should be valid. - if (!tools.Validate(&binary_in[0], binary_in.size(), validator_options_)) { - consumer_(SPV_MSG_ERROR, nullptr, {}, - "Initial binary is invalid; stopping."); - return Fuzzer::FuzzerResultStatus::kInitialBinaryInvalid; - } - - // Build the module from the input binary. - std::unique_ptr ir_context = - BuildModule(target_env_, consumer_, binary_in.data(), binary_in.size()); - assert(ir_context); - - // Make a PRNG from the seed passed to the fuzzer on creation. - PseudoRandomGenerator random_generator(seed_); - - // The fuzzer will introduce new ids into the module. The module's id bound - // gives the smallest id that can be used for this purpose. We add an offset - // to this so that there is a sizeable gap between the ids used in the - // original module and the ids used for fuzzing, as a readability aid. - // - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the - // case where the maximum id bound is reached. - auto minimum_fresh_id = ir_context->module()->id_bound() + kIdBoundGap; - FuzzerContext fuzzer_context(&random_generator, minimum_fresh_id); - - FactManager fact_manager; - fact_manager.AddFacts(consumer_, initial_facts, ir_context.get()); - TransformationContext transformation_context(&fact_manager, - validator_options_); - - // Apply some semantics-preserving passes. - std::vector> passes; - while (passes.empty()) { - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass(&passes, ir_context.get(), - &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass(&passes, ir_context.get(), - &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out, donor_suppliers); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - } - - bool is_first = true; - while (static_cast( - transformation_sequence_out->transformation_size()) < - kTransformationLimit && - (is_first || - fuzzer_context.ChoosePercentage(kChanceOfApplyingAnotherPass))) { - is_first = false; - if (!ApplyPassAndCheckValidity( - passes[fuzzer_context.RandomIndex(passes)].get(), *ir_context, - tools)) { - return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule; - } - } - - // Now apply some passes that it does not make sense to apply repeatedly, - // as they do not unlock other passes. - std::vector> final_passes; - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - MaybeAddPass( - &final_passes, ir_context.get(), &transformation_context, &fuzzer_context, - transformation_sequence_out); - for (auto& pass : final_passes) { - if (!ApplyPassAndCheckValidity(pass.get(), *ir_context, tools)) { - return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule; - } - } - - // Encode the module as a binary. - ir_context->module()->ToBinary(binary_out, false); - - return Fuzzer::FuzzerResultStatus::kComplete; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer.h b/3rdparty/spirv-tools/source/fuzz/fuzzer.h deleted file mode 100644 index a437d5809..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_H_ -#define SOURCE_FUZZ_FUZZER_H_ - -#include -#include - -#include "source/fuzz/fuzzer_pass.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace fuzz { - -// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by -// running a number of randomized fuzzer passes. -class Fuzzer { - public: - // Possible statuses that can result from running the fuzzer. - enum class FuzzerResultStatus { - kComplete, - kFailedToCreateSpirvToolsInterface, - kFuzzerPassLedToInvalidModule, - kInitialBinaryInvalid, - }; - - // Constructs a fuzzer from the given target environment |target_env|. |seed| - // is a seed for pseudo-random number generation. - // |validate_after_each_fuzzer_pass| controls whether the validator will be - // invoked after every fuzzer pass is applied. - Fuzzer(spv_target_env target_env, uint32_t seed, - bool validate_after_each_fuzzer_pass, - spv_validator_options validator_options); - - // Disables copy/move constructor/assignment operations. - Fuzzer(const Fuzzer&) = delete; - Fuzzer(Fuzzer&&) = delete; - Fuzzer& operator=(const Fuzzer&) = delete; - Fuzzer& operator=(Fuzzer&&) = delete; - - ~Fuzzer(); - - // Sets the message consumer to the given |consumer|. The |consumer| will be - // invoked once for each message communicated from the library. - void SetMessageConsumer(MessageConsumer consumer); - - // Transforms |binary_in| to |binary_out| by running a number of randomized - // fuzzer passes. Initial facts about the input binary and the context in - // which it will execute are provided via |initial_facts|. A source of donor - // modules to be used by transformations is provided via |donor_suppliers|. - // The transformation sequence that was applied is returned via - // |transformation_sequence_out|. - FuzzerResultStatus Run( - const std::vector& binary_in, - const protobufs::FactSequence& initial_facts, - const std::vector& donor_suppliers, - std::vector* binary_out, - protobufs::TransformationSequence* transformation_sequence_out) const; - - private: - // Applies |pass|, which must be a pass constructed with |ir_context|, and - // then returns true if and only if |ir_context| is valid. |tools| is used to - // check validity. - bool ApplyPassAndCheckValidity(FuzzerPass* pass, - const opt::IRContext& ir_context, - const spvtools::SpirvTools& tools) const; - - // Target environment. - const spv_target_env target_env_; - - // Message consumer. - MessageConsumer consumer_; - - // Seed for random number generator. - const uint32_t seed_; - - // Determines whether the validator should be invoked after every fuzzer pass. - bool validate_after_each_fuzzer_pass_; - - // Options to control validation. - spv_validator_options validator_options_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp deleted file mode 100644 index 6f76bbb67..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_context.h" - -#include - -namespace spvtools { -namespace fuzz { - -namespace { -// Default pairs of probabilities for applying various -// transformations. All values are percentages. Keep them in alphabetical order. - -const std::pair kChanceOfAddingAccessChain = {5, 50}; -const std::pair kChanceOfAddingAnotherStructField = {20, - 90}; -const std::pair kChanceOfAddingArrayOrStructType = {20, 90}; -const std::pair kChanceOfAddingCompositeInsert = {20, 50}; -const std::pair kChanceOfAddingCopyMemory = {20, 50}; -const std::pair kChanceOfAddingDeadBlock = {20, 90}; -const std::pair kChanceOfAddingDeadBreak = {5, 80}; -const std::pair kChanceOfAddingDeadContinue = {5, 80}; -const std::pair kChanceOfAddingEquationInstruction = {5, - 90}; -const std::pair kChanceOfAddingGlobalVariable = {20, 90}; -const std::pair kChanceOfAddingImageSampleUnusedComponents = - {20, 90}; -const std::pair kChanceOfAddingLoad = {5, 50}; -const std::pair kChanceOfAddingLocalVariable = {20, 90}; -const std::pair kChanceOfAddingLoopPreheader = {20, 90}; -const std::pair kChanceOfAddingMatrixType = {20, 70}; -const std::pair kChanceOfAddingNoContractionDecoration = { - 5, 70}; -const std::pair kChanceOfAddingOpPhiSynonym = {5, 70}; -const std::pair kChanceOfAddingParameters = {5, 70}; -const std::pair kChanceOfAddingRelaxedDecoration = {20, 90}; -const std::pair kChanceOfAddingStore = {5, 50}; -const std::pair kChanceOfAddingSynonyms = {20, 50}; -const std::pair kChanceOfAddingVectorType = {20, 70}; -const std::pair kChanceOfAddingVectorShuffle = {20, 70}; -const std::pair kChanceOfAdjustingBranchWeights = {20, 90}; -const std::pair kChanceOfAdjustingFunctionControl = {20, - 70}; -const std::pair kChanceOfAdjustingLoopControl = {20, 90}; -const std::pair kChanceOfAdjustingMemoryOperandsMask = {20, - 90}; -const std::pair kChanceOfAdjustingSelectionControl = {20, - 90}; -const std::pair kChanceOfCallingFunction = {1, 10}; -const std::pair kChanceOfChoosingStructTypeVsArrayType = { - 20, 80}; -const std::pair kChanceOfChoosingWorkgroupStorageClass = { - 50, 50}; -const std::pair kChanceOfConstructingComposite = {20, 50}; -const std::pair kChanceOfCopyingObject = {20, 50}; -const std::pair kChanceOfDonatingAdditionalModule = {5, 50}; -const std::pair kChanceOfGoingDeeperToInsertInComposite = { - 30, 70}; -const std::pair kChanceOfGoingDeeperWhenMakingAccessChain = - {50, 95}; -const std::pair kChanceOfInliningFunction = {10, 90}; -const std::pair kChanceOfInterchangingZeroLikeConstants = { - 10, 90}; -const std::pair - kChanceOfInterchangingSignednessOfIntegerOperands = {10, 90}; -const std::pair kChanceOfInvertingComparisonOperators = { - 20, 50}; -const std::pair kChanceOfMakingDonorLivesafe = {40, 60}; -const std::pair kChanceOfMakingVectorOperationDynamic = { - 20, 90}; -const std::pair kChanceOfMergingBlocks = {20, 95}; -const std::pair kChanceOfMovingBlockDown = {20, 50}; -const std::pair kChanceOfObfuscatingConstant = {10, 90}; -const std::pair kChanceOfOutliningFunction = {10, 90}; -const std::pair kChanceOfPermutingInstructions = {20, 70}; -const std::pair kChanceOfPermutingParameters = {30, 90}; -const std::pair kChanceOfPermutingPhiOperands = {30, 90}; -const std::pair kChanceOfPropagatingInstructionsUp = {20, - 70}; -const std::pair kChanceOfPushingIdThroughVariable = {5, 50}; -const std::pair - kChanceOfReplacingAddSubMulWithCarryingExtended = {20, 70}; -const std::pair kChanceOfReplacingCopyMemoryWithLoadStore = - {20, 90}; -const std::pair kChanceOfReplacingCopyObjectWithStoreLoad = - {20, 90}; -const std::pair kChanceOfReplacingIdWithSynonym = {10, 90}; -const std::pair - kChanceOfReplacingLinearAlgebraInstructions = {10, 90}; -const std::pair kChanceOfReplacingLoadStoreWithCopyMemory = - {20, 90}; -const std::pair kChanceOfReplacingParametersWithGlobals = { - 30, 70}; -const std::pair kChanceOfReplacingParametersWithStruct = { - 20, 40}; -const std::pair kChanceOfSplittingBlock = {40, 95}; -const std::pair kChanceOfSwappingConditionalBranchOperands = - {10, 70}; -const std::pair kChanceOfTogglingAccessChainInstruction = { - 20, 90}; - -// Default limits for various quantities that are chosen during fuzzing. -// Keep them in alphabetical order. -const uint32_t kDefaultMaxEquivalenceClassSizeForDataSynonymFactClosure = 1000; -const uint32_t kDefaultMaxLoopControlPartialCount = 100; -const uint32_t kDefaultMaxLoopControlPeelCount = 100; -const uint32_t kDefaultMaxLoopLimit = 20; -const uint32_t kDefaultMaxNewArraySizeLimit = 100; -// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3424): -// think whether there is a better limit on the maximum number of parameters. -const uint32_t kDefaultMaxNumberOfFunctionParameters = 128; -const uint32_t kDefaultMaxNumberOfNewParameters = 15; -const uint32_t kGetDefaultMaxNumberOfParametersReplacedWithStruct = 5; - -// Default functions for controlling how deep to go during recursive -// generation/transformation. Keep them in alphabetical order. - -const std::function - kDefaultGoDeeperInConstantObfuscation = - [](uint32_t current_depth, RandomGenerator* random_generator) -> bool { - double chance = 1.0 / std::pow(3.0, static_cast(current_depth + 1)); - return random_generator->RandomDouble() < chance; -}; - -} // namespace - -FuzzerContext::FuzzerContext(RandomGenerator* random_generator, - uint32_t min_fresh_id) - : random_generator_(random_generator), - next_fresh_id_(min_fresh_id), - max_equivalence_class_size_for_data_synonym_fact_closure_( - kDefaultMaxEquivalenceClassSizeForDataSynonymFactClosure), - max_loop_control_partial_count_(kDefaultMaxLoopControlPartialCount), - max_loop_control_peel_count_(kDefaultMaxLoopControlPeelCount), - max_loop_limit_(kDefaultMaxLoopLimit), - max_new_array_size_limit_(kDefaultMaxNewArraySizeLimit), - max_number_of_function_parameters_(kDefaultMaxNumberOfFunctionParameters), - max_number_of_new_parameters_(kDefaultMaxNumberOfNewParameters), - max_number_of_parameters_replaced_with_struct_( - kGetDefaultMaxNumberOfParametersReplacedWithStruct), - go_deeper_in_constant_obfuscation_( - kDefaultGoDeeperInConstantObfuscation) { - chance_of_adding_access_chain_ = - ChooseBetweenMinAndMax(kChanceOfAddingAccessChain); - chance_of_adding_another_struct_field_ = - ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField); - chance_of_adding_array_or_struct_type_ = - ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType); - chance_of_adding_composite_insert_ = - ChooseBetweenMinAndMax(kChanceOfAddingCompositeInsert); - chance_of_adding_copy_memory_ = - ChooseBetweenMinAndMax(kChanceOfAddingCopyMemory); - chance_of_adding_dead_block_ = - ChooseBetweenMinAndMax(kChanceOfAddingDeadBlock); - chance_of_adding_dead_break_ = - ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak); - chance_of_adding_dead_continue_ = - ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue); - chance_of_adding_equation_instruction_ = - ChooseBetweenMinAndMax(kChanceOfAddingEquationInstruction); - chance_of_adding_global_variable_ = - ChooseBetweenMinAndMax(kChanceOfAddingGlobalVariable); - chance_of_adding_load_ = ChooseBetweenMinAndMax(kChanceOfAddingLoad); - chance_of_adding_loop_preheader_ = - ChooseBetweenMinAndMax(kChanceOfAddingLoopPreheader); - chance_of_adding_image_sample_unused_components_ = - ChooseBetweenMinAndMax(kChanceOfAddingImageSampleUnusedComponents); - chance_of_adding_local_variable_ = - ChooseBetweenMinAndMax(kChanceOfAddingLocalVariable); - chance_of_adding_matrix_type_ = - ChooseBetweenMinAndMax(kChanceOfAddingMatrixType); - chance_of_adding_no_contraction_decoration_ = - ChooseBetweenMinAndMax(kChanceOfAddingNoContractionDecoration); - chance_of_adding_opphi_synonym_ = - ChooseBetweenMinAndMax(kChanceOfAddingOpPhiSynonym); - chance_of_adding_parameters = - ChooseBetweenMinAndMax(kChanceOfAddingParameters); - chance_of_adding_relaxed_decoration_ = - ChooseBetweenMinAndMax(kChanceOfAddingRelaxedDecoration); - chance_of_adding_store_ = ChooseBetweenMinAndMax(kChanceOfAddingStore); - chance_of_adding_vector_shuffle_ = - ChooseBetweenMinAndMax(kChanceOfAddingVectorShuffle); - chance_of_adding_vector_type_ = - ChooseBetweenMinAndMax(kChanceOfAddingVectorType); - chance_of_adjusting_branch_weights_ = - ChooseBetweenMinAndMax(kChanceOfAdjustingBranchWeights); - chance_of_adjusting_function_control_ = - ChooseBetweenMinAndMax(kChanceOfAdjustingFunctionControl); - chance_of_adding_synonyms_ = ChooseBetweenMinAndMax(kChanceOfAddingSynonyms); - chance_of_adjusting_loop_control_ = - ChooseBetweenMinAndMax(kChanceOfAdjustingLoopControl); - chance_of_adjusting_memory_operands_mask_ = - ChooseBetweenMinAndMax(kChanceOfAdjustingMemoryOperandsMask); - chance_of_adjusting_selection_control_ = - ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl); - chance_of_calling_function_ = - ChooseBetweenMinAndMax(kChanceOfCallingFunction); - chance_of_choosing_struct_type_vs_array_type_ = - ChooseBetweenMinAndMax(kChanceOfChoosingStructTypeVsArrayType); - chance_of_choosing_workgroup_storage_class_ = - ChooseBetweenMinAndMax(kChanceOfChoosingWorkgroupStorageClass); - chance_of_constructing_composite_ = - ChooseBetweenMinAndMax(kChanceOfConstructingComposite); - chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject); - chance_of_donating_additional_module_ = - ChooseBetweenMinAndMax(kChanceOfDonatingAdditionalModule); - chance_of_going_deeper_to_insert_in_composite_ = - ChooseBetweenMinAndMax(kChanceOfGoingDeeperToInsertInComposite); - chance_of_going_deeper_when_making_access_chain_ = - ChooseBetweenMinAndMax(kChanceOfGoingDeeperWhenMakingAccessChain); - chance_of_inlining_function_ = - ChooseBetweenMinAndMax(kChanceOfInliningFunction); - chance_of_interchanging_signedness_of_integer_operands_ = - ChooseBetweenMinAndMax(kChanceOfInterchangingSignednessOfIntegerOperands); - chance_of_interchanging_zero_like_constants_ = - ChooseBetweenMinAndMax(kChanceOfInterchangingZeroLikeConstants); - chance_of_inverting_comparison_operators_ = - ChooseBetweenMinAndMax(kChanceOfInvertingComparisonOperators); - chance_of_making_donor_livesafe_ = - ChooseBetweenMinAndMax(kChanceOfMakingDonorLivesafe); - chance_of_making_vector_operation_dynamic_ = - ChooseBetweenMinAndMax(kChanceOfMakingVectorOperationDynamic); - chance_of_merging_blocks_ = ChooseBetweenMinAndMax(kChanceOfMergingBlocks); - chance_of_moving_block_down_ = - ChooseBetweenMinAndMax(kChanceOfMovingBlockDown); - chance_of_obfuscating_constant_ = - ChooseBetweenMinAndMax(kChanceOfObfuscatingConstant); - chance_of_outlining_function_ = - ChooseBetweenMinAndMax(kChanceOfOutliningFunction); - chance_of_permuting_instructions_ = - ChooseBetweenMinAndMax(kChanceOfPermutingInstructions); - chance_of_permuting_parameters_ = - ChooseBetweenMinAndMax(kChanceOfPermutingParameters); - chance_of_permuting_phi_operands_ = - ChooseBetweenMinAndMax(kChanceOfPermutingPhiOperands); - chance_of_propagating_instructions_up_ = - ChooseBetweenMinAndMax(kChanceOfPropagatingInstructionsUp); - chance_of_pushing_id_through_variable_ = - ChooseBetweenMinAndMax(kChanceOfPushingIdThroughVariable); - chance_of_replacing_add_sub_mul_with_carrying_extended_ = - ChooseBetweenMinAndMax(kChanceOfReplacingAddSubMulWithCarryingExtended); - chance_of_replacing_copy_memory_with_load_store_ = - ChooseBetweenMinAndMax(kChanceOfReplacingCopyMemoryWithLoadStore); - chance_of_replacing_copyobject_with_store_load_ = - ChooseBetweenMinAndMax(kChanceOfReplacingCopyObjectWithStoreLoad); - chance_of_replacing_id_with_synonym_ = - ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym); - chance_of_replacing_linear_algebra_instructions_ = - ChooseBetweenMinAndMax(kChanceOfReplacingLinearAlgebraInstructions); - chance_of_replacing_load_store_with_copy_memory_ = - ChooseBetweenMinAndMax(kChanceOfReplacingLoadStoreWithCopyMemory); - chance_of_replacing_parameters_with_globals_ = - ChooseBetweenMinAndMax(kChanceOfReplacingParametersWithGlobals); - chance_of_replacing_parameters_with_struct_ = - ChooseBetweenMinAndMax(kChanceOfReplacingParametersWithStruct); - chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock); - chance_of_swapping_conditional_branch_operands_ = - ChooseBetweenMinAndMax(kChanceOfSwappingConditionalBranchOperands); - chance_of_toggling_access_chain_instruction_ = - ChooseBetweenMinAndMax(kChanceOfTogglingAccessChainInstruction); -} - -FuzzerContext::~FuzzerContext() = default; - -uint32_t FuzzerContext::GetFreshId() { return next_fresh_id_++; } - -std::vector FuzzerContext::GetFreshIds(const uint32_t count) { - std::vector fresh_ids(count); - - for (uint32_t& fresh_id : fresh_ids) { - fresh_id = next_fresh_id_++; - } - - return fresh_ids; -} - -bool FuzzerContext::ChooseEven() { return random_generator_->RandomBool(); } - -bool FuzzerContext::ChoosePercentage(uint32_t percentage_chance) { - assert(percentage_chance <= 100); - return random_generator_->RandomPercentage() < percentage_chance; -} - -uint32_t FuzzerContext::ChooseBetweenMinAndMax( - const std::pair& min_max) { - assert(min_max.first <= min_max.second); - return min_max.first + - random_generator_->RandomUint32(min_max.second - min_max.first + 1); -} - -protobufs::TransformationAddSynonym::SynonymType -FuzzerContext::GetRandomSynonymType() { - // value_count method is guaranteed to return a value greater than 0. - auto result_index = ChooseBetweenMinAndMax( - {0, static_cast( - protobufs::TransformationAddSynonym::SynonymType_descriptor() - ->value_count() - - 1)}); - auto result = protobufs::TransformationAddSynonym::SynonymType_descriptor() - ->value(result_index) - ->number(); - assert(protobufs::TransformationAddSynonym::SynonymType_IsValid(result) && - "|result| is not a value of SynonymType"); - return static_cast(result); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h deleted file mode 100644 index bc98bc0c9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_CONTEXT_H_ -#define SOURCE_FUZZ_FUZZER_CONTEXT_H_ - -#include -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/random_generator.h" -#include "source/opt/function.h" - -namespace spvtools { -namespace fuzz { - -// Encapsulates all parameters that control the fuzzing process, such as the -// source of randomness and the probabilities with which transformations are -// applied. -class FuzzerContext { - public: - // Constructs a fuzzer context with a given random generator and the minimum - // value that can be used for fresh ids. - FuzzerContext(RandomGenerator* random_generator, uint32_t min_fresh_id); - - ~FuzzerContext(); - - // Returns a random boolean. - bool ChooseEven(); - - // Returns true if and only if a randomly-chosen integer in the range [0, 100] - // is less than |percentage_chance|. - bool ChoosePercentage(uint32_t percentage_chance); - - // Returns a random index into |sequence|, which is expected to have a 'size' - // method, and which must be non-empty. Typically 'HasSizeMethod' will be an - // std::vector. - template - uint32_t RandomIndex(const HasSizeMethod& sequence) const { - assert(sequence.size() > 0); - return random_generator_->RandomUint32( - static_cast(sequence.size())); - } - - // Selects a random index into |sequence|, removes the element at that index - // and returns it. - template - T RemoveAtRandomIndex(std::vector* sequence) const { - uint32_t index = RandomIndex(*sequence); - T result = sequence->at(index); - sequence->erase(sequence->begin() + index); - return result; - } - - // Randomly shuffles a |sequence| between |lo| and |hi| indices inclusively. - // |lo| and |hi| must be valid indices to the |sequence| - template - void Shuffle(std::vector* sequence, size_t lo, size_t hi) const { - auto& array = *sequence; - - if (array.empty()) { - return; - } - - assert(lo <= hi && hi < array.size() && "lo and/or hi indices are invalid"); - - // i > lo to account for potential infinite loop when lo == 0 - for (size_t i = hi; i > lo; --i) { - auto index = - random_generator_->RandomUint32(static_cast(i - lo + 1)); - - if (lo + index != i) { - // Introduce std::swap to the scope but don't use it - // directly since there might be a better overload - using std::swap; - swap(array[lo + index], array[i]); - } - } - } - - // Ramdomly shuffles a |sequence| - template - void Shuffle(std::vector* sequence) const { - if (!sequence->empty()) { - Shuffle(sequence, 0, sequence->size() - 1); - } - } - - // Yields an id that is guaranteed not to be used in the module being fuzzed, - // or to have been issued before. - uint32_t GetFreshId(); - - // Returns a vector of |count| fresh ids. - std::vector GetFreshIds(const uint32_t count); - - // Probabilities associated with applying various transformations. - // Keep them in alphabetical order. - uint32_t GetChanceOfAddingAccessChain() { - return chance_of_adding_access_chain_; - } - uint32_t GetChanceOfAddingAnotherStructField() { - return chance_of_adding_another_struct_field_; - } - uint32_t GetChanceOfAddingArrayOrStructType() { - return chance_of_adding_array_or_struct_type_; - } - uint32_t GetChanceOfAddingCompositeInsert() { - return chance_of_adding_composite_insert_; - } - uint32_t GetChanceOfAddingCopyMemory() { - return chance_of_adding_copy_memory_; - } - uint32_t GetChanceOfAddingDeadBlock() { return chance_of_adding_dead_block_; } - uint32_t GetChanceOfAddingDeadBreak() { return chance_of_adding_dead_break_; } - uint32_t GetChanceOfAddingDeadContinue() { - return chance_of_adding_dead_continue_; - } - uint32_t GetChanceOfAddingEquationInstruction() { - return chance_of_adding_equation_instruction_; - } - uint32_t GetChanceOfAddingGlobalVariable() { - return chance_of_adding_global_variable_; - } - uint32_t GetChanceOfAddingImageSampleUnusedComponents() { - return chance_of_adding_image_sample_unused_components_; - } - uint32_t GetChanceOfAddingLoad() { return chance_of_adding_load_; } - uint32_t GetChanceOfAddingLocalVariable() { - return chance_of_adding_local_variable_; - } - uint32_t GetChanceOfAddingLoopPreheader() { - return chance_of_adding_loop_preheader_; - } - uint32_t GetChanceOfAddingMatrixType() { - return chance_of_adding_matrix_type_; - } - uint32_t GetChanceOfAddingNoContractionDecoration() { - return chance_of_adding_no_contraction_decoration_; - } - uint32_t GetChanceOfAddingOpPhiSynonym() { - return chance_of_adding_opphi_synonym_; - } - uint32_t GetChanceOfAddingParameters() { return chance_of_adding_parameters; } - uint32_t GetChanceOfAddingRelaxedDecoration() { - return chance_of_adding_relaxed_decoration_; - } - uint32_t GetChanceOfAddingStore() { return chance_of_adding_store_; } - uint32_t GetChanceOfAddingSynonyms() { return chance_of_adding_synonyms_; } - uint32_t GetChanceOfAddingVectorShuffle() { - return chance_of_adding_vector_shuffle_; - } - uint32_t GetChanceOfAddingVectorType() { - return chance_of_adding_vector_type_; - } - uint32_t GetChanceOfAdjustingBranchWeights() { - return chance_of_adjusting_branch_weights_; - } - uint32_t GetChanceOfAdjustingFunctionControl() { - return chance_of_adjusting_function_control_; - } - uint32_t GetChanceOfAdjustingLoopControl() { - return chance_of_adjusting_loop_control_; - } - uint32_t GetChanceOfAdjustingMemoryOperandsMask() { - return chance_of_adjusting_memory_operands_mask_; - } - uint32_t GetChanceOfAdjustingSelectionControl() { - return chance_of_adjusting_selection_control_; - } - uint32_t GetChanceOfCallingFunction() { return chance_of_calling_function_; } - uint32_t GetChanceOfChoosingStructTypeVsArrayType() { - return chance_of_choosing_struct_type_vs_array_type_; - } - uint32_t GetChanceOfChoosingWorkgroupStorageClass() { - return chance_of_choosing_workgroup_storage_class_; - } - uint32_t GetChanceOfConstructingComposite() { - return chance_of_constructing_composite_; - } - uint32_t GetChanceOfCopyingObject() { return chance_of_copying_object_; } - uint32_t GetChanceOfDonatingAdditionalModule() { - return chance_of_donating_additional_module_; - } - uint32_t GetChanceOfGoingDeeperToInsertInComposite() { - return chance_of_going_deeper_to_insert_in_composite_; - } - uint32_t GetChanceOfGoingDeeperWhenMakingAccessChain() { - return chance_of_going_deeper_when_making_access_chain_; - } - uint32_t GetChanceOfInliningFunction() { - return chance_of_inlining_function_; - } - uint32_t GetChanceOfInterchangingSignednessOfIntegerOperands() { - return chance_of_interchanging_signedness_of_integer_operands_; - } - uint32_t GetChanceOfInterchangingZeroLikeConstants() { - return chance_of_interchanging_zero_like_constants_; - } - uint32_t GetChanceOfInvertingComparisonOperators() { - return chance_of_inverting_comparison_operators_; - } - uint32_t ChanceOfMakingDonorLivesafe() { - return chance_of_making_donor_livesafe_; - } - uint32_t GetChanceOfMakingVectorOperationDynamic() { - return chance_of_making_vector_operation_dynamic_; - } - uint32_t GetChanceOfMergingBlocks() { return chance_of_merging_blocks_; } - uint32_t GetChanceOfMovingBlockDown() { return chance_of_moving_block_down_; } - uint32_t GetChanceOfObfuscatingConstant() { - return chance_of_obfuscating_constant_; - } - uint32_t GetChanceOfOutliningFunction() { - return chance_of_outlining_function_; - } - uint32_t GetChanceOfPermutingInstructions() { - return chance_of_permuting_instructions_; - } - uint32_t GetChanceOfPermutingParameters() { - return chance_of_permuting_parameters_; - } - uint32_t GetChanceOfPermutingPhiOperands() { - return chance_of_permuting_phi_operands_; - } - uint32_t GetChanceOfPropagatingInstructionsUp() { - return chance_of_propagating_instructions_up_; - } - uint32_t GetChanceOfPushingIdThroughVariable() { - return chance_of_pushing_id_through_variable_; - } - uint32_t GetChanceOfReplacingAddSubMulWithCarryingExtended() { - return chance_of_replacing_add_sub_mul_with_carrying_extended_; - } - uint32_t GetChanceOfReplacingCopyMemoryWithLoadStore() { - return chance_of_replacing_copy_memory_with_load_store_; - } - uint32_t GetChanceOfReplacingCopyObjectWithStoreLoad() { - return chance_of_replacing_copyobject_with_store_load_; - } - uint32_t GetChanceOfReplacingIdWithSynonym() { - return chance_of_replacing_id_with_synonym_; - } - uint32_t GetChanceOfReplacingLinearAlgebraInstructions() { - return chance_of_replacing_linear_algebra_instructions_; - } - uint32_t GetChanceOfReplacingLoadStoreWithCopyMemory() { - return chance_of_replacing_load_store_with_copy_memory_; - } - uint32_t GetChanceOfReplacingParametersWithGlobals() { - return chance_of_replacing_parameters_with_globals_; - } - uint32_t GetChanceOfReplacingParametersWithStruct() { - return chance_of_replacing_parameters_with_struct_; - } - uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; } - uint32_t GetChanceOfSwappingConditionalBranchOperands() { - return chance_of_swapping_conditional_branch_operands_; - } - uint32_t GetChanceOfTogglingAccessChainInstruction() { - return chance_of_toggling_access_chain_instruction_; - } - - // Other functions to control transformations. Keep them in alphabetical - // order. - uint32_t GetMaximumEquivalenceClassSizeForDataSynonymFactClosure() { - return max_equivalence_class_size_for_data_synonym_fact_closure_; - } - uint32_t GetMaximumNumberOfFunctionParameters() { - return max_number_of_function_parameters_; - } - uint32_t GetMaximumNumberOfParametersReplacedWithStruct() { - return max_number_of_parameters_replaced_with_struct_; - } - std::pair GetRandomBranchWeights() { - std::pair branch_weights = {0, 0}; - - while (branch_weights.first == 0 && branch_weights.second == 0) { - // Using INT32_MAX to do not overflow UINT32_MAX when the branch weights - // are added together. - branch_weights.first = random_generator_->RandomUint32(INT32_MAX); - branch_weights.second = random_generator_->RandomUint32(INT32_MAX); - } - - return branch_weights; - } - std::vector GetRandomComponentsForVectorShuffle( - uint32_t max_component_index) { - // Component count must be in range [2, 4]. - std::vector components(random_generator_->RandomUint32(2) + 2); - - for (uint32_t& component : components) { - component = random_generator_->RandomUint32(max_component_index); - } - - return components; - } - uint32_t GetRandomIndexForAccessChain(uint32_t composite_size_bound) { - return random_generator_->RandomUint32(composite_size_bound); - } - uint32_t GetRandomIndexForCompositeInsert(uint32_t number_of_components) { - return random_generator_->RandomUint32(number_of_components); - } - uint32_t GetRandomLoopControlPartialCount() { - return random_generator_->RandomUint32(max_loop_control_partial_count_); - } - uint32_t GetRandomLoopControlPeelCount() { - return random_generator_->RandomUint32(max_loop_control_peel_count_); - } - uint32_t GetRandomLoopLimit() { - return random_generator_->RandomUint32(max_loop_limit_); - } - uint32_t GetRandomNumberOfNewParameters(uint32_t num_of_params) { - assert(num_of_params < GetMaximumNumberOfFunctionParameters()); - return ChooseBetweenMinAndMax( - {1, std::min(max_number_of_new_parameters_, - GetMaximumNumberOfFunctionParameters() - num_of_params)}); - } - uint32_t GetRandomNumberOfParametersReplacedWithStruct(uint32_t num_params) { - assert(num_params != 0 && "A function must have parameters to replace"); - return ChooseBetweenMinAndMax( - {1, std::min(num_params, - GetMaximumNumberOfParametersReplacedWithStruct())}); - } - uint32_t GetRandomSizeForNewArray() { - // Ensure that the array size is non-zero. - return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1; - } - protobufs::TransformationAddSynonym::SynonymType GetRandomSynonymType(); - uint32_t GetRandomUnusedComponentCountForImageSample( - uint32_t max_unused_component_count) { - // Ensure that the number of unused components is non-zero. - return random_generator_->RandomUint32(max_unused_component_count) + 1; - } - bool GoDeeperInConstantObfuscation(uint32_t depth) { - return go_deeper_in_constant_obfuscation_(depth, random_generator_); - } - - private: - // The source of randomness. - RandomGenerator* random_generator_; - // The next fresh id to be issued. - uint32_t next_fresh_id_; - - // Probabilities associated with applying various transformations. - // Keep them in alphabetical order. - uint32_t chance_of_adding_access_chain_; - uint32_t chance_of_adding_another_struct_field_; - uint32_t chance_of_adding_array_or_struct_type_; - uint32_t chance_of_adding_composite_insert_; - uint32_t chance_of_adding_copy_memory_; - uint32_t chance_of_adding_dead_block_; - uint32_t chance_of_adding_dead_break_; - uint32_t chance_of_adding_dead_continue_; - uint32_t chance_of_adding_equation_instruction_; - uint32_t chance_of_adding_global_variable_; - uint32_t chance_of_adding_image_sample_unused_components_; - uint32_t chance_of_adding_load_; - uint32_t chance_of_adding_local_variable_; - uint32_t chance_of_adding_loop_preheader_; - uint32_t chance_of_adding_matrix_type_; - uint32_t chance_of_adding_no_contraction_decoration_; - uint32_t chance_of_adding_opphi_synonym_; - uint32_t chance_of_adding_parameters; - uint32_t chance_of_adding_relaxed_decoration_; - uint32_t chance_of_adding_store_; - uint32_t chance_of_adding_synonyms_; - uint32_t chance_of_adding_vector_shuffle_; - uint32_t chance_of_adding_vector_type_; - uint32_t chance_of_adjusting_branch_weights_; - uint32_t chance_of_adjusting_function_control_; - uint32_t chance_of_adjusting_loop_control_; - uint32_t chance_of_adjusting_memory_operands_mask_; - uint32_t chance_of_adjusting_selection_control_; - uint32_t chance_of_calling_function_; - uint32_t chance_of_choosing_struct_type_vs_array_type_; - uint32_t chance_of_choosing_workgroup_storage_class_; - uint32_t chance_of_constructing_composite_; - uint32_t chance_of_copying_object_; - uint32_t chance_of_donating_additional_module_; - uint32_t chance_of_going_deeper_to_insert_in_composite_; - uint32_t chance_of_going_deeper_when_making_access_chain_; - uint32_t chance_of_inlining_function_; - uint32_t chance_of_interchanging_signedness_of_integer_operands_; - uint32_t chance_of_interchanging_zero_like_constants_; - uint32_t chance_of_inverting_comparison_operators_; - uint32_t chance_of_making_donor_livesafe_; - uint32_t chance_of_making_vector_operation_dynamic_; - uint32_t chance_of_merging_blocks_; - uint32_t chance_of_moving_block_down_; - uint32_t chance_of_obfuscating_constant_; - uint32_t chance_of_outlining_function_; - uint32_t chance_of_permuting_instructions_; - uint32_t chance_of_permuting_parameters_; - uint32_t chance_of_permuting_phi_operands_; - uint32_t chance_of_propagating_instructions_up_; - uint32_t chance_of_pushing_id_through_variable_; - uint32_t chance_of_replacing_add_sub_mul_with_carrying_extended_; - uint32_t chance_of_replacing_copy_memory_with_load_store_; - uint32_t chance_of_replacing_copyobject_with_store_load_; - uint32_t chance_of_replacing_id_with_synonym_; - uint32_t chance_of_replacing_linear_algebra_instructions_; - uint32_t chance_of_replacing_load_store_with_copy_memory_; - uint32_t chance_of_replacing_parameters_with_globals_; - uint32_t chance_of_replacing_parameters_with_struct_; - uint32_t chance_of_splitting_block_; - uint32_t chance_of_swapping_conditional_branch_operands_; - uint32_t chance_of_toggling_access_chain_instruction_; - - // Limits associated with various quantities for which random values are - // chosen during fuzzing. - // Keep them in alphabetical order. - uint32_t max_equivalence_class_size_for_data_synonym_fact_closure_; - uint32_t max_loop_control_partial_count_; - uint32_t max_loop_control_peel_count_; - uint32_t max_loop_limit_; - uint32_t max_new_array_size_limit_; - uint32_t max_number_of_function_parameters_; - uint32_t max_number_of_new_parameters_; - uint32_t max_number_of_parameters_replaced_with_struct_; - - // Functions to determine with what probability to go deeper when generating - // or mutating constructs recursively. - const std::function& - go_deeper_in_constant_obfuscation_; - - // Requires |min_max.first| <= |min_max.second|, and returns a value in the - // range [ |min_max.first|, |min_max.second| ] - uint32_t ChooseBetweenMinAndMax(const std::pair& min_max); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_CONTEXT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp deleted file mode 100644 index a6a698ecd..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/id_use_descriptor.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_add_constant_boolean.h" -#include "source/fuzz/transformation_add_constant_composite.h" -#include "source/fuzz/transformation_add_constant_null.h" -#include "source/fuzz/transformation_add_constant_scalar.h" -#include "source/fuzz/transformation_add_global_undef.h" -#include "source/fuzz/transformation_add_global_variable.h" -#include "source/fuzz/transformation_add_local_variable.h" -#include "source/fuzz/transformation_add_loop_preheader.h" -#include "source/fuzz/transformation_add_type_boolean.h" -#include "source/fuzz/transformation_add_type_float.h" -#include "source/fuzz/transformation_add_type_function.h" -#include "source/fuzz/transformation_add_type_int.h" -#include "source/fuzz/transformation_add_type_matrix.h" -#include "source/fuzz/transformation_add_type_pointer.h" -#include "source/fuzz/transformation_add_type_struct.h" -#include "source/fuzz/transformation_add_type_vector.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPass::FuzzerPass(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : ir_context_(ir_context), - transformation_context_(transformation_context), - fuzzer_context_(fuzzer_context), - transformations_(transformations) {} - -FuzzerPass::~FuzzerPass() = default; - -std::vector FuzzerPass::FindAvailableInstructions( - opt::Function* function, opt::BasicBlock* block, - const opt::BasicBlock::iterator& inst_it, - std::function - instruction_is_relevant) const { - // TODO(afd) The following is (relatively) simple, but may end up being - // prohibitively inefficient, as it walks the whole dominator tree for - // every instruction that is considered. - - std::vector result; - // Consider all global declarations - for (auto& global : GetIRContext()->module()->types_values()) { - if (instruction_is_relevant(GetIRContext(), &global)) { - result.push_back(&global); - } - } - - // Consider all function parameters - function->ForEachParam( - [this, &instruction_is_relevant, &result](opt::Instruction* param) { - if (instruction_is_relevant(GetIRContext(), param)) { - result.push_back(param); - } - }); - - // Consider all previous instructions in this block - for (auto prev_inst_it = block->begin(); prev_inst_it != inst_it; - ++prev_inst_it) { - if (instruction_is_relevant(GetIRContext(), &*prev_inst_it)) { - result.push_back(&*prev_inst_it); - } - } - - // Walk the dominator tree to consider all instructions from dominating - // blocks - auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(function); - for (auto next_dominator = dominator_analysis->ImmediateDominator(block); - next_dominator != nullptr; - next_dominator = - dominator_analysis->ImmediateDominator(next_dominator)) { - for (auto& dominating_inst : *next_dominator) { - if (instruction_is_relevant(GetIRContext(), &dominating_inst)) { - result.push_back(&dominating_inst); - } - } - } - return result; -} - -void FuzzerPass::ForEachInstructionWithInstructionDescriptor( - std::function< - void(opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor)> - action) { - // Consider every block in every function. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // We now consider every instruction in the block, randomly deciding - // whether to apply a transformation before it. - - // In order for transformations to insert new instructions, they need to - // be able to identify the instruction to insert before. We describe an - // instruction via its opcode, 'opc', a base instruction 'base' that has a - // result id, and the number of instructions with opcode 'opc' that we - // should skip when searching from 'base' for the desired instruction. - // (An instruction that has a result id is represented by its own opcode, - // itself as 'base', and a skip-count of 0.) - std::vector> - base_opcode_skip_triples; - - // The initial base instruction is the block label. - uint32_t base = block.id(); - - // Counts the number of times we have seen each opcode since we reset the - // base instruction. - std::map skip_count; - - // Consider every instruction in the block. The label is excluded: it is - // only necessary to consider it as a base in case the first instruction - // in the block does not have a result id. - for (auto inst_it = block.begin(); inst_it != block.end(); ++inst_it) { - if (inst_it->HasResultId()) { - // In the case that the instruction has a result id, we use the - // instruction as its own base, and clear the skip counts we have - // collected. - base = inst_it->result_id(); - skip_count.clear(); - } - const SpvOp opcode = inst_it->opcode(); - - // Invoke the provided function, which might apply a transformation. - action(&function, &block, inst_it, - MakeInstructionDescriptor( - base, opcode, - skip_count.count(opcode) ? skip_count.at(opcode) : 0)); - - if (!inst_it->HasResultId()) { - skip_count[opcode] = - skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1; - } - } - } - } -} - -uint32_t FuzzerPass::FindOrCreateBoolType() { - if (auto existing_id = fuzzerutil::MaybeGetBoolType(GetIRContext())) { - return existing_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeBoolean(result)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateIntegerType(uint32_t width, bool is_signed) { - opt::analysis::Integer int_type(width, is_signed); - auto existing_id = GetIRContext()->get_type_mgr()->GetId(&int_type); - if (existing_id) { - return existing_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeInt(result, width, is_signed)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateFloatType(uint32_t width) { - opt::analysis::Float float_type(width); - auto existing_id = GetIRContext()->get_type_mgr()->GetId(&float_type); - if (existing_id) { - return existing_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeFloat(result, width)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateFunctionType( - uint32_t return_type_id, const std::vector& argument_id) { - // FindFunctionType has a sigle argument for OpTypeFunction operands - // so we will have to copy them all in this vector - std::vector type_ids(argument_id.size() + 1); - type_ids[0] = return_type_id; - std::copy(argument_id.begin(), argument_id.end(), type_ids.begin() + 1); - - // Check if type exists - auto existing_id = fuzzerutil::FindFunctionType(GetIRContext(), type_ids); - if (existing_id) { - return existing_id; - } - - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation( - TransformationAddTypeFunction(result, return_type_id, argument_id)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateVectorType(uint32_t component_type_id, - uint32_t component_count) { - assert(component_count >= 2 && component_count <= 4 && - "Precondition: component count must be in range [2, 4]."); - opt::analysis::Type* component_type = - GetIRContext()->get_type_mgr()->GetType(component_type_id); - assert(component_type && "Precondition: the component type must exist."); - opt::analysis::Vector vector_type(component_type, component_count); - auto existing_id = GetIRContext()->get_type_mgr()->GetId(&vector_type); - if (existing_id) { - return existing_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation( - TransformationAddTypeVector(result, component_type_id, component_count)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateMatrixType(uint32_t column_count, - uint32_t row_count) { - assert(column_count >= 2 && column_count <= 4 && - "Precondition: column count must be in range [2, 4]."); - assert(row_count >= 2 && row_count <= 4 && - "Precondition: row count must be in range [2, 4]."); - uint32_t column_type_id = - FindOrCreateVectorType(FindOrCreateFloatType(32), row_count); - opt::analysis::Type* column_type = - GetIRContext()->get_type_mgr()->GetType(column_type_id); - opt::analysis::Matrix matrix_type(column_type, column_count); - auto existing_id = GetIRContext()->get_type_mgr()->GetId(&matrix_type); - if (existing_id) { - return existing_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation( - TransformationAddTypeMatrix(result, column_type_id, column_count)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateStructType( - const std::vector& component_type_ids) { - if (auto existing_id = - fuzzerutil::MaybeGetStructType(GetIRContext(), component_type_ids)) { - return existing_id; - } - auto new_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeStruct(new_id, component_type_ids)); - return new_id; -} - -uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id, - SpvStorageClass storage_class) { - // We do not use the type manager here, due to problems related to isomorphic - // but distinct structs not being regarded as different. - auto existing_id = fuzzerutil::MaybeGetPointerType( - GetIRContext(), base_type_id, storage_class); - if (existing_id) { - return existing_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation( - TransformationAddTypePointer(result, storage_class, base_type_id)); - return result; -} - -uint32_t FuzzerPass::FindOrCreatePointerToIntegerType( - uint32_t width, bool is_signed, SpvStorageClass storage_class) { - return FindOrCreatePointerType(FindOrCreateIntegerType(width, is_signed), - storage_class); -} - -uint32_t FuzzerPass::FindOrCreateIntegerConstant( - const std::vector& words, uint32_t width, bool is_signed, - bool is_irrelevant) { - auto int_type_id = FindOrCreateIntegerType(width, is_signed); - if (auto constant_id = fuzzerutil::MaybeGetScalarConstant( - GetIRContext(), *GetTransformationContext(), words, int_type_id, - is_irrelevant)) { - return constant_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddConstantScalar(result, int_type_id, - words, is_irrelevant)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateFloatConstant( - const std::vector& words, uint32_t width, bool is_irrelevant) { - auto float_type_id = FindOrCreateFloatType(width); - if (auto constant_id = fuzzerutil::MaybeGetScalarConstant( - GetIRContext(), *GetTransformationContext(), words, float_type_id, - is_irrelevant)) { - return constant_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddConstantScalar(result, float_type_id, - words, is_irrelevant)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateBoolConstant(bool value, bool is_irrelevant) { - auto bool_type_id = FindOrCreateBoolType(); - if (auto constant_id = fuzzerutil::MaybeGetScalarConstant( - GetIRContext(), *GetTransformationContext(), {value ? 1u : 0u}, - bool_type_id, is_irrelevant)) { - return constant_id; - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation( - TransformationAddConstantBoolean(result, value, is_irrelevant)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateConstant(const std::vector& words, - uint32_t type_id, - bool is_irrelevant) { - assert(type_id && "Constant's type id can't be 0."); - - const auto* type = GetIRContext()->get_type_mgr()->GetType(type_id); - assert(type && "Type does not exist."); - - if (type->AsBool()) { - assert(words.size() == 1); - return FindOrCreateBoolConstant(words[0], is_irrelevant); - } else if (const auto* integer = type->AsInteger()) { - return FindOrCreateIntegerConstant(words, integer->width(), - integer->IsSigned(), is_irrelevant); - } else if (const auto* floating = type->AsFloat()) { - return FindOrCreateFloatConstant(words, floating->width(), is_irrelevant); - } - - // This assertion will fail in debug build but not in release build - // so we return 0 to make compiler happy. - assert(false && "Constant type is not supported"); - return 0; -} - -uint32_t FuzzerPass::FindOrCreateCompositeConstant( - const std::vector& component_ids, uint32_t type_id, - bool is_irrelevant) { - if (auto existing_constant = fuzzerutil::MaybeGetCompositeConstant( - GetIRContext(), *GetTransformationContext(), component_ids, type_id, - is_irrelevant)) { - return existing_constant; - } - uint32_t result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddConstantComposite( - result, type_id, component_ids, is_irrelevant)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) { - for (auto& inst : GetIRContext()->types_values()) { - if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) { - return inst.result_id(); - } - } - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddGlobalUndef(result, type_id)); - return result; -} - -uint32_t FuzzerPass::FindOrCreateNullConstant(uint32_t type_id) { - // Find existing declaration - opt::analysis::NullConstant null_constant( - GetIRContext()->get_type_mgr()->GetType(type_id)); - auto existing_constant = - GetIRContext()->get_constant_mgr()->FindConstant(&null_constant); - - // Return if found - if (existing_constant) { - return GetIRContext() - ->get_constant_mgr() - ->GetDefiningInstruction(existing_constant) - ->result_id(); - } - - // Create new if not found - auto result = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddConstantNull(result, type_id)); - return result; -} - -std::pair, std::map>> -FuzzerPass::GetAvailableBasicTypesAndPointers( - SpvStorageClass storage_class) const { - // Records all of the basic types available in the module. - std::set basic_types; - - // For each basic type, records all the associated pointer types that target - // the basic type and that have |storage_class| as their storage class. - std::map> basic_type_to_pointers; - - for (auto& inst : GetIRContext()->types_values()) { - // For each basic type that we come across, record type, and the fact that - // we cannot yet have seen any pointers that use the basic type as its - // pointee type. - // - // For pointer types with basic pointee types, associate the pointer type - // with the basic type. - switch (inst.opcode()) { - case SpvOpTypeBool: - case SpvOpTypeFloat: - case SpvOpTypeInt: - case SpvOpTypeMatrix: - case SpvOpTypeVector: - // These are all basic types. - basic_types.insert(inst.result_id()); - basic_type_to_pointers.insert({inst.result_id(), {}}); - break; - case SpvOpTypeArray: - // An array type is basic if its base type is basic. - if (basic_types.count(inst.GetSingleWordInOperand(0))) { - basic_types.insert(inst.result_id()); - basic_type_to_pointers.insert({inst.result_id(), {}}); - } - break; - case SpvOpTypeStruct: { - // A struct type is basic if all of its members are basic. - bool all_members_are_basic_types = true; - for (uint32_t i = 0; i < inst.NumInOperands(); i++) { - if (!basic_types.count(inst.GetSingleWordInOperand(i))) { - all_members_are_basic_types = false; - break; - } - } - if (all_members_are_basic_types) { - basic_types.insert(inst.result_id()); - basic_type_to_pointers.insert({inst.result_id(), {}}); - } - break; - } - case SpvOpTypePointer: { - // We are interested in the pointer if its pointee type is basic and it - // has the right storage class. - auto pointee_type = inst.GetSingleWordInOperand(1); - if (inst.GetSingleWordInOperand(0) == storage_class && - basic_types.count(pointee_type)) { - // The pointer has the desired storage class, and its pointee type is - // a basic type, so we are interested in it. Associate it with its - // basic type. - basic_type_to_pointers.at(pointee_type).push_back(inst.result_id()); - } - break; - } - default: - break; - } - } - return {{basic_types.begin(), basic_types.end()}, basic_type_to_pointers}; -} - -uint32_t FuzzerPass::FindOrCreateZeroConstant( - uint32_t scalar_or_composite_type_id, bool is_irrelevant) { - auto type_instruction = - GetIRContext()->get_def_use_mgr()->GetDef(scalar_or_composite_type_id); - assert(type_instruction && "The type instruction must exist."); - switch (type_instruction->opcode()) { - case SpvOpTypeBool: - return FindOrCreateBoolConstant(false, is_irrelevant); - case SpvOpTypeFloat: { - auto width = type_instruction->GetSingleWordInOperand(0); - auto num_words = (width + 32 - 1) / 32; - return FindOrCreateFloatConstant(std::vector(num_words, 0), - width, is_irrelevant); - } - case SpvOpTypeInt: { - auto width = type_instruction->GetSingleWordInOperand(0); - auto num_words = (width + 32 - 1) / 32; - return FindOrCreateIntegerConstant( - std::vector(num_words, 0), width, - type_instruction->GetSingleWordInOperand(1), is_irrelevant); - } - case SpvOpTypeArray: { - auto component_type_id = type_instruction->GetSingleWordInOperand(0); - auto num_components = - fuzzerutil::GetArraySize(*type_instruction, GetIRContext()); - return FindOrCreateCompositeConstant( - std::vector( - num_components, - FindOrCreateZeroConstant(component_type_id, is_irrelevant)), - scalar_or_composite_type_id, is_irrelevant); - } - case SpvOpTypeMatrix: - case SpvOpTypeVector: { - auto component_type_id = type_instruction->GetSingleWordInOperand(0); - auto num_components = type_instruction->GetSingleWordInOperand(1); - return FindOrCreateCompositeConstant( - std::vector( - num_components, - FindOrCreateZeroConstant(component_type_id, is_irrelevant)), - scalar_or_composite_type_id, is_irrelevant); - } - case SpvOpTypeStruct: { - std::vector field_zero_ids; - for (uint32_t index = 0; index < type_instruction->NumInOperands(); - index++) { - field_zero_ids.push_back(FindOrCreateZeroConstant( - type_instruction->GetSingleWordInOperand(index), is_irrelevant)); - } - return FindOrCreateCompositeConstant( - field_zero_ids, scalar_or_composite_type_id, is_irrelevant); - } - default: - assert(false && "Unknown type."); - return 0; - } -} - -bool FuzzerPass::CanFindOrCreateZeroConstant(const opt::analysis::Type& type) { - switch (type.kind()) { - case opt::analysis::Type::kBool: - case opt::analysis::Type::kInteger: - case opt::analysis::Type::kFloat: - case opt::analysis::Type::kArray: - case opt::analysis::Type::kMatrix: - case opt::analysis::Type::kVector: - return true; - case opt::analysis::Type::kStruct: - return std::all_of(type.AsStruct()->element_types().begin(), - type.AsStruct()->element_types().end(), - [this](const opt::analysis::Type* element_type) { - return CanFindOrCreateZeroConstant(*element_type); - }); - default: - return false; - } -} - -void FuzzerPass::MaybeAddUseToReplace( - opt::Instruction* use_inst, uint32_t use_index, uint32_t replacement_id, - std::vector>* - uses_to_replace) { - // Only consider this use if it is in a block - if (!GetIRContext()->get_instr_block(use_inst)) { - return; - } - - // Get the index of the operand restricted to input operands. - uint32_t in_operand_index = - fuzzerutil::InOperandIndexFromOperandIndex(*use_inst, use_index); - auto id_use_descriptor = - MakeIdUseDescriptorFromUse(GetIRContext(), use_inst, in_operand_index); - uses_to_replace->emplace_back( - std::make_pair(id_use_descriptor, replacement_id)); -} - -opt::BasicBlock* FuzzerPass::GetOrCreateSimpleLoopPreheader( - uint32_t header_id) { - auto header_block = fuzzerutil::MaybeFindBlock(GetIRContext(), header_id); - - assert(header_block && header_block->IsLoopHeader() && - "|header_id| should be the label id of a loop header"); - - auto predecessors = GetIRContext()->cfg()->preds(header_id); - - assert(predecessors.size() >= 2 && - "The block |header_id| should be reachable."); - - auto function = header_block->GetParent(); - - if (predecessors.size() == 2) { - // The header has a single out-of-loop predecessor, which could be a - // preheader. - - opt::BasicBlock* maybe_preheader; - - if (GetIRContext()->GetDominatorAnalysis(function)->Dominates( - header_id, predecessors[0])) { - // The first predecessor is the back-edge block, because the header - // dominates it, so the second one is out of the loop. - maybe_preheader = &*function->FindBlock(predecessors[1]); - } else { - // The first predecessor is out of the loop. - maybe_preheader = &*function->FindBlock(predecessors[0]); - } - - // |maybe_preheader| is a preheader if it branches unconditionally to - // the header. We also require it not to be a loop header. - if (maybe_preheader->terminator()->opcode() == SpvOpBranch && - !maybe_preheader->IsLoopHeader()) { - return maybe_preheader; - } - } - - // We need to add a preheader. - - // Get a fresh id for the preheader. - uint32_t preheader_id = GetFuzzerContext()->GetFreshId(); - - // Get a fresh id for each OpPhi instruction, if there is more than one - // out-of-loop predecessor. - std::vector phi_ids; - if (predecessors.size() > 2) { - header_block->ForEachPhiInst( - [this, &phi_ids](opt::Instruction* /* unused */) { - phi_ids.push_back(GetFuzzerContext()->GetFreshId()); - }); - } - - // Add the preheader. - ApplyTransformation( - TransformationAddLoopPreheader(header_id, preheader_id, phi_ids)); - - // Make the newly-created preheader the new entry block. - return &*function->FindBlock(preheader_id); -} - -uint32_t FuzzerPass::FindOrCreateLocalVariable( - uint32_t pointer_type_id, uint32_t function_id, - bool pointee_value_is_irrelevant) { - auto pointer_type = GetIRContext()->get_type_mgr()->GetType(pointer_type_id); - // No unused variables in release mode. - (void)pointer_type; - assert(pointer_type && pointer_type->AsPointer() && - pointer_type->AsPointer()->storage_class() == - SpvStorageClassFunction && - "The pointer_type_id must refer to a defined pointer type with " - "storage class Function"); - auto function = fuzzerutil::FindFunction(GetIRContext(), function_id); - assert(function && "The function must be defined."); - - // First we try to find a suitable existing variable. - // All of the local variable declarations are located in the first block. - for (auto& instruction : *function->begin()) { - if (instruction.opcode() != SpvOpVariable) { - continue; - } - // The existing OpVariable must have type |pointer_type_id|. - if (instruction.type_id() != pointer_type_id) { - continue; - } - // Check if the found variable is marked with PointeeValueIsIrrelevant - // according to |pointee_value_is_irrelevant|. - if (GetTransformationContext()->GetFactManager()->PointeeValueIsIrrelevant( - instruction.result_id()) != pointee_value_is_irrelevant) { - continue; - } - return instruction.result_id(); - } - - // No such variable was found. Apply a transformation to get one. - uint32_t pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType( - GetIRContext(), pointer_type_id); - uint32_t result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddLocalVariable( - result_id, pointer_type_id, function_id, - FindOrCreateZeroConstant(pointee_type_id, pointee_value_is_irrelevant), - pointee_value_is_irrelevant)); - return result_id; -} - -uint32_t FuzzerPass::FindOrCreateGlobalVariable( - uint32_t pointer_type_id, bool pointee_value_is_irrelevant) { - auto pointer_type = GetIRContext()->get_type_mgr()->GetType(pointer_type_id); - // No unused variables in release mode. - (void)pointer_type; - assert( - pointer_type && pointer_type->AsPointer() && - (pointer_type->AsPointer()->storage_class() == SpvStorageClassPrivate || - pointer_type->AsPointer()->storage_class() == - SpvStorageClassWorkgroup) && - "The pointer_type_id must refer to a defined pointer type with storage " - "class Private or Workgroup"); - - // First we try to find a suitable existing variable. - for (auto& instruction : GetIRContext()->module()->types_values()) { - if (instruction.opcode() != SpvOpVariable) { - continue; - } - // The existing OpVariable must have type |pointer_type_id|. - if (instruction.type_id() != pointer_type_id) { - continue; - } - // Check if the found variable is marked with PointeeValueIsIrrelevant - // according to |pointee_value_is_irrelevant|. - if (GetTransformationContext()->GetFactManager()->PointeeValueIsIrrelevant( - instruction.result_id()) != pointee_value_is_irrelevant) { - continue; - } - return instruction.result_id(); - } - - // No such variable was found. Apply a transformation to get one. - uint32_t pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType( - GetIRContext(), pointer_type_id); - auto storage_class = fuzzerutil::GetStorageClassFromPointerType( - GetIRContext(), pointer_type_id); - uint32_t result_id = GetFuzzerContext()->GetFreshId(); - - // A variable with storage class Workgroup shouldn't have an initializer. - if (storage_class == SpvStorageClassWorkgroup) { - ApplyTransformation(TransformationAddGlobalVariable( - result_id, pointer_type_id, SpvStorageClassWorkgroup, 0, - pointee_value_is_irrelevant)); - } else { - ApplyTransformation(TransformationAddGlobalVariable( - result_id, pointer_type_id, SpvStorageClassPrivate, - FindOrCreateZeroConstant(pointee_type_id, pointee_value_is_irrelevant), - pointee_value_is_irrelevant)); - } - return result_id; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h deleted file mode 100644 index 1e6992a6d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_H_ - -#include -#include - -#include "source/fuzz/fuzzer_context.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 { - -// Interface for applying a pass of transformations to a module. -class FuzzerPass { - public: - FuzzerPass(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - virtual ~FuzzerPass(); - - // Applies the pass to the module |ir_context_|, assuming and updating - // information from |transformation_context_|, and using |fuzzer_context_| to - // guide the process. Appends to |transformations_| all transformations that - // were applied during the pass. - virtual void Apply() = 0; - - protected: - opt::IRContext* GetIRContext() const { return ir_context_; } - - TransformationContext* GetTransformationContext() const { - return transformation_context_; - } - - FuzzerContext* GetFuzzerContext() const { return fuzzer_context_; } - - protobufs::TransformationSequence* GetTransformations() const { - return transformations_; - } - - // Returns all instructions that are *available* at |inst_it|, which is - // required to be inside block |block| of function |function| - that is, all - // instructions at global scope and all instructions that strictly dominate - // |inst_it|. - // - // Filters said instructions to return only those that satisfy the - // |instruction_is_relevant| predicate. This, for instance, could ignore all - // instructions that have a particular decoration. - std::vector FindAvailableInstructions( - opt::Function* function, opt::BasicBlock* block, - const opt::BasicBlock::iterator& inst_it, - std::function - instruction_is_relevant) const; - - // A helper method that iterates through each instruction in each block, at - // all times tracking an instruction descriptor that allows the latest - // instruction to be located even if it has no result id. - // - // The code to manipulate the instruction descriptor is a bit fiddly. The - // point of this method is to avoiding having to duplicate it in multiple - // transformation passes. - // - // The function |action| is invoked for each instruction |inst_it| in block - // |block| of function |function| that is encountered. The - // |instruction_descriptor| parameter to the function object allows |inst_it| - // to be identified. - // - // In most intended use cases, the job of |action| is to randomly decide - // whether to try to apply some transformation, and then - if selected - to - // attempt to apply it. - void ForEachInstructionWithInstructionDescriptor( - std::function< - void(opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor)> - action); - - // A generic helper for applying a transformation that should be applicable - // by construction, and adding it to the sequence of applied transformations. - void ApplyTransformation(const Transformation& transformation) { - assert(transformation.IsApplicable(GetIRContext(), - *GetTransformationContext()) && - "Transformation should be applicable by construction."); - transformation.Apply(GetIRContext(), GetTransformationContext()); - *GetTransformations()->add_transformation() = transformation.ToMessage(); - } - - // A generic helper for applying a transformation only if it is applicable. - // If it is applicable, the transformation is applied and then added to the - // sequence of applied transformations and the function returns true. - // Otherwise, the function returns false. - bool MaybeApplyTransformation(const Transformation& transformation) { - if (transformation.IsApplicable(GetIRContext(), - *GetTransformationContext())) { - transformation.Apply(GetIRContext(), GetTransformationContext()); - *GetTransformations()->add_transformation() = transformation.ToMessage(); - return true; - } - return false; - } - - // Returns the id of an OpTypeBool instruction. If such an instruction does - // not exist, a transformation is applied to add it. - uint32_t FindOrCreateBoolType(); - - // Returns the id of an OpTypeInt instruction, with width and signedness - // specified by |width| and |is_signed|, respectively. If such an instruction - // does not exist, a transformation is applied to add it. - uint32_t FindOrCreateIntegerType(uint32_t width, bool is_signed); - - // Returns the id of an OpTypeFloat instruction, with width specified by - // |width|. If such an instruction does not exist, a transformation is - // applied to add it. - uint32_t FindOrCreateFloatType(uint32_t width); - - // Returns the id of an OpTypeFunction % %<...argument_id> - // instruction. If such an instruction doesn't exist, a transformation - // is applied to create a new one. - uint32_t FindOrCreateFunctionType(uint32_t return_type_id, - const std::vector& argument_id); - - // Returns the id of an OpTypeVector instruction, with |component_type_id| - // (which must already exist) as its base type, and |component_count| - // elements (which must be in the range [2, 4]). If such an instruction does - // not exist, a transformation is applied to add it. - uint32_t FindOrCreateVectorType(uint32_t component_type_id, - uint32_t component_count); - - // Returns the id of an OpTypeMatrix instruction, with |column_count| columns - // and |row_count| rows (each of which must be in the range [2, 4]). If the - // float and vector types required to build this matrix type or the matrix - // type itself do not exist, transformations are applied to add them. - uint32_t FindOrCreateMatrixType(uint32_t column_count, uint32_t row_count); - - // Returns the id of an OpTypeStruct instruction with |component_type_ids| as - // type ids for struct's components. If no such a struct type exists, - // transformations are applied to add it. |component_type_ids| may not contain - // a result id of an OpTypeFunction. - uint32_t FindOrCreateStructType( - const std::vector& component_type_ids); - - // Returns the id of a pointer type with base type |base_type_id| (which must - // already exist) and storage class |storage_class|. A transformation is - // applied to add the pointer if it does not already exist. - uint32_t FindOrCreatePointerType(uint32_t base_type_id, - SpvStorageClass storage_class); - - // Returns the id of an OpTypePointer instruction, with a integer base - // type of width and signedness specified by |width| and |is_signed|, - // respectively. If the pointer type or required integer base type do not - // exist, transformations are applied to add them. - uint32_t FindOrCreatePointerToIntegerType(uint32_t width, bool is_signed, - SpvStorageClass storage_class); - - // Returns the id of an OpConstant instruction, with a integer type of - // width and signedness specified by |width| and |is_signed|, respectively, - // with |words| as its value. If either the required integer type or the - // constant do not exist, transformations are applied to add them. - // The returned id either participates in IdIsIrrelevant fact or not, - // depending on the |is_irrelevant| parameter. - uint32_t FindOrCreateIntegerConstant(const std::vector& words, - uint32_t width, bool is_signed, - bool is_irrelevant); - - // Returns the id of an OpConstant instruction, with a floating-point - // type of width specified by |width|, with |words| as its value. If either - // the required floating-point type or the constant do not exist, - // transformations are applied to add them. The returned id either - // participates in IdIsIrrelevant fact or not, depending on the - // |is_irrelevant| parameter. - uint32_t FindOrCreateFloatConstant(const std::vector& words, - uint32_t width, bool is_irrelevant); - - // Returns the id of an OpConstantTrue or OpConstantFalse instruction, - // according to |value|. If either the required instruction or the bool - // type do not exist, transformations are applied to add them. - // The returned id either participates in IdIsIrrelevant fact or not, - // depending on the |is_irrelevant| parameter. - uint32_t FindOrCreateBoolConstant(bool value, bool is_irrelevant); - - // Returns the id of an OpConstant instruction of type with |type_id| - // that consists of |words|. If that instruction doesn't exist, - // transformations are applied to add it. |type_id| must be a valid - // result id of either scalar or boolean OpType* instruction that exists - // in the module. The returned id either participates in IdIsIrrelevant fact - // or not, depending on the |is_irrelevant| parameter. - uint32_t FindOrCreateConstant(const std::vector& words, - uint32_t type_id, bool is_irrelevant); - - // Returns the id of an OpConstantComposite instruction of type with |type_id| - // that consists of |component_ids|. If that instruction doesn't exist, - // transformations are applied to add it. |type_id| must be a valid - // result id of an OpType* instruction that represents a composite type - // (i.e. a vector, matrix, struct or array). - // The returned id either participates in IdIsIrrelevant fact or not, - // depending on the |is_irrelevant| parameter. - uint32_t FindOrCreateCompositeConstant( - const std::vector& component_ids, uint32_t type_id, - bool is_irrelevant); - - // Returns the result id of an instruction of the form: - // %id = OpUndef %|type_id| - // If no such instruction exists, a transformation is applied to add it. - uint32_t FindOrCreateGlobalUndef(uint32_t type_id); - - // Returns the id of an OpNullConstant instruction of type |type_id|. If - // that instruction doesn't exist, it is added through a transformation. - // |type_id| must be a valid result id of an OpType* instruction that exists - // in the module. - uint32_t FindOrCreateNullConstant(uint32_t type_id); - - // Define a *basic type* to be an integer, boolean or floating-point type, - // or a matrix, vector, struct or fixed-size array built from basic types. In - // particular, a basic type cannot contain an opaque type (such as an image), - // or a runtime-sized array. - // - // Yields a pair, (basic_type_ids, basic_type_ids_to_pointers), such that: - // - basic_type_ids captures every basic type declared in the module. - // - basic_type_ids_to_pointers maps every such basic type to the sequence - // of all pointer types that have storage class |storage_class| and the - // given basic type as their pointee type. The sequence may be empty for - // some basic types if no pointers to those types are defined for the given - // storage class, and the sequence will have multiple elements if there are - // repeated pointer declarations for the same basic type and storage class. - std::pair, std::map>> - GetAvailableBasicTypesAndPointers(SpvStorageClass storage_class) const; - - // Given a type id, |scalar_or_composite_type_id|, which must correspond to - // some scalar or composite type, returns the result id of an instruction - // defining a constant of the given type that is zero or false at everywhere. - // If such an instruction does not yet exist, transformations are applied to - // add it. The returned id either participates in IdIsIrrelevant fact or not, - // depending on the |is_irrelevant| parameter. - // - // Examples: - // --------------+------------------------------- - // TYPE | RESULT is id corresponding to - // --------------+------------------------------- - // bool | false - // --------------+------------------------------- - // bvec4 | (false, false, false, false) - // --------------+------------------------------- - // float | 0.0 - // --------------+------------------------------- - // vec2 | (0.0, 0.0) - // --------------+------------------------------- - // int[3] | [0, 0, 0] - // --------------+------------------------------- - // struct S { | - // int i; | S(0, false, (0u, 0u)) - // bool b; | - // uint2 u; | - // } | - // --------------+------------------------------- - uint32_t FindOrCreateZeroConstant(uint32_t scalar_or_composite_type_id, - bool is_irrelevant); - - // Checks if FindOrCreateZeroConstant can be called on this type. - bool CanFindOrCreateZeroConstant(const opt::analysis::Type& type); - - // Adds a pair (id_use_descriptor, |replacement_id|) to the vector - // |uses_to_replace|, where id_use_descriptor is the id use descriptor - // representing the usage of an id in the |use_inst| instruction, at operand - // index |use_index|, only if the instruction is in a basic block. - // If the instruction is not in a basic block, it does nothing. - void MaybeAddUseToReplace( - opt::Instruction* use_inst, uint32_t use_index, uint32_t replacement_id, - std::vector>* - uses_to_replace); - - // Returns the preheader of the loop with header |header_id|, which satisfies - // all of the following conditions: - // - It is the only out-of-loop predecessor of the header - // - It unconditionally branches to the header - // - It is not a loop header itself - // If such preheader does not exist, a new one is added and returned. - // Requires |header_id| to be the label id of a loop header block that is - // reachable in the CFG (and thus has at least 2 predecessors). - opt::BasicBlock* GetOrCreateSimpleLoopPreheader(uint32_t header_id); - - // Returns the id of an available local variable (storage class Function) with - // the fact PointeeValueIsIrrelevant set according to - // |pointee_value_is_irrelevant|. If there is no such variable, it creates one - // in the |function| adding a zero initializer constant that is irrelevant. - // The new variable has the fact PointeeValueIsIrrelevant set according to - // |pointee_value_is_irrelevant|. The function returns the id of the created - // variable. - uint32_t FindOrCreateLocalVariable(uint32_t pointer_type_id, - uint32_t function_id, - bool pointee_value_is_irrelevant); - - // Returns the id of an available global variable (storage class Private or - // Workgroup) with the fact PointeeValueIsIrrelevant set according to - // |pointee_value_is_irrelevant|. If there is no such variable, it creates - // one, adding a zero initializer constant that is irrelevant. The new - // variable has the fact PointeeValueIsIrrelevant set according to - // |pointee_value_is_irrelevant|. The function returns the id of the created - // variable. - uint32_t FindOrCreateGlobalVariable(uint32_t pointer_type_id, - bool pointee_value_is_irrelevant); - - private: - opt::IRContext* ir_context_; - TransformationContext* transformation_context_; - FuzzerContext* fuzzer_context_; - protobufs::TransformationSequence* transformations_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.cpp deleted file mode 100644 index 11155f23d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.cpp +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_access_chains.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_access_chain.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddAccessChains::FuzzerPassAddAccessChains( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddAccessChains::~FuzzerPassAddAccessChains() = default; - -void FuzzerPassAddAccessChains::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - assert(inst_it->opcode() == - instruction_descriptor.target_instruction_opcode() && - "The opcode of the instruction we might insert before must be " - "the same as the opcode in the descriptor for the instruction"); - - // Check whether it is legitimate to insert an access chain - // instruction before this instruction. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAccessChain, - inst_it)) { - return; - } - - // Randomly decide whether to try inserting a load here. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingAccessChain())) { - return; - } - - // Get all of the pointers that are currently in scope, excluding - // explicitly null and undefined pointers. - std::vector relevant_pointer_instructions = - FindAvailableInstructions( - function, block, inst_it, - [](opt::IRContext* context, - opt::Instruction* instruction) -> bool { - if (!instruction->result_id() || !instruction->type_id()) { - // A pointer needs both a result and type id. - return false; - } - switch (instruction->opcode()) { - case SpvOpConstantNull: - case SpvOpUndef: - // Do not allow making an access chain from a null or - // undefined pointer. (We can eliminate these cases - // before actually checking that the instruction is a - // pointer.) - return false; - default: - break; - } - // If the instruction has pointer type, we can legitimately - // make an access chain from it. - return context->get_def_use_mgr() - ->GetDef(instruction->type_id()) - ->opcode() == SpvOpTypePointer; - }); - - // At this point, |relevant_instructions| contains all the pointers - // we might think of making an access chain from. - if (relevant_pointer_instructions.empty()) { - return; - } - - auto chosen_pointer = - relevant_pointer_instructions[GetFuzzerContext()->RandomIndex( - relevant_pointer_instructions)]; - std::vector index_ids; - - // Each index accessing a non-struct composite will be clamped, thus - // needing a pair of fresh ids - std::vector> fresh_ids_for_clamping; - - auto pointer_type = GetIRContext()->get_def_use_mgr()->GetDef( - chosen_pointer->type_id()); - uint32_t subobject_type_id = pointer_type->GetSingleWordInOperand(1); - while (true) { - auto subobject_type = - GetIRContext()->get_def_use_mgr()->GetDef(subobject_type_id); - if (!spvOpcodeIsComposite(subobject_type->opcode())) { - break; - } - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfGoingDeeperWhenMakingAccessChain())) { - break; - } - uint32_t bound; - switch (subobject_type->opcode()) { - case SpvOpTypeArray: - bound = fuzzerutil::GetArraySize(*subobject_type, GetIRContext()); - break; - case SpvOpTypeMatrix: - case SpvOpTypeVector: - bound = subobject_type->GetSingleWordInOperand(1); - break; - case SpvOpTypeStruct: - bound = fuzzerutil::GetNumberOfStructMembers(*subobject_type); - break; - default: - assert(false && "Not a composite type opcode."); - // Set the bound to a value in order to keep release compilers - // happy. - bound = 0; - break; - } - if (bound == 0) { - // It is possible for a composite type to legitimately have zero - // sub-components, at least in the case of a struct, which - // can have no fields. - break; - } - - uint32_t index_value = - GetFuzzerContext()->GetRandomIndexForAccessChain(bound); - - switch (subobject_type->opcode()) { - case SpvOpTypeArray: - case SpvOpTypeMatrix: - case SpvOpTypeVector: { - // The index will be clamped - - bool is_signed = GetFuzzerContext()->ChooseEven(); - - // Make the constant ready for clamping. We need: - // - an OpTypeBool to be present in the module - // - an OpConstant with the same type as the index and value - // the maximum value for an index - // - a new pair of fresh ids for the clamping instructions - FindOrCreateBoolType(); - FindOrCreateIntegerConstant({bound - 1}, 32, is_signed, false); - std::pair fresh_pair_of_ids = { - GetFuzzerContext()->GetFreshId(), - GetFuzzerContext()->GetFreshId()}; - fresh_ids_for_clamping.emplace_back(fresh_pair_of_ids); - - index_ids.push_back(FindOrCreateIntegerConstant( - {index_value}, 32, is_signed, false)); - subobject_type_id = subobject_type->GetSingleWordInOperand(0); - - } break; - case SpvOpTypeStruct: - index_ids.push_back(FindOrCreateIntegerConstant( - {index_value}, 32, GetFuzzerContext()->ChooseEven(), false)); - subobject_type_id = - subobject_type->GetSingleWordInOperand(index_value); - break; - default: - assert(false && "Not a composite type opcode."); - } - } - // The transformation we are about to create will only apply if a - // pointer suitable for the access chain's result type exists, so we - // create one if it does not. - FindOrCreatePointerType(subobject_type_id, - static_cast( - pointer_type->GetSingleWordInOperand(0))); - // Apply the transformation to add an access chain. - ApplyTransformation(TransformationAccessChain( - GetFuzzerContext()->GetFreshId(), chosen_pointer->result_id(), - index_ids, instruction_descriptor, fresh_ids_for_clamping)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.h deleted file mode 100644 index 8649296f0..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_access_chains.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_ACCESS_CHAINS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_ACCESS_CHAINS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that randomly adds access chains based on pointers available in -// the module. Other passes can use these access chains, e.g. by loading from -// them. -class FuzzerPassAddAccessChains : public FuzzerPass { - public: - FuzzerPassAddAccessChains(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddAccessChains(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_ACCESS_CHAINS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.cpp deleted file mode 100644 index 092a1d5bd..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_composite_inserts.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/pseudo_random_generator.h" -#include "source/fuzz/transformation_composite_insert.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddCompositeInserts::FuzzerPassAddCompositeInserts( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddCompositeInserts::~FuzzerPassAddCompositeInserts() = default; - -void FuzzerPassAddCompositeInserts::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator instruction_iterator, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - assert(instruction_iterator->opcode() == - instruction_descriptor.target_instruction_opcode() && - "The opcode of the instruction we might insert before must be " - "the same as the opcode in the descriptor for the instruction"); - - // Randomly decide whether to try adding an OpCompositeInsert - // instruction. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingCompositeInsert())) { - return; - } - - // It must be possible to insert an OpCompositeInsert instruction - // before |instruction_iterator|. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpCompositeInsert, instruction_iterator)) { - return; - } - - // Look for available values that have composite type. - std::vector available_composites = - FindAvailableInstructions( - function, block, instruction_iterator, - [instruction_descriptor]( - opt::IRContext* ir_context, - opt::Instruction* instruction) -> bool { - // |instruction| must be a supported instruction of composite - // type. - if (!TransformationCompositeInsert:: - IsCompositeInstructionSupported(ir_context, - instruction)) { - return false; - } - - auto instruction_type = ir_context->get_type_mgr()->GetType( - instruction->type_id()); - - // No components of the composite can have type - // OpTypeRuntimeArray. - if (ContainsRuntimeArray(*instruction_type)) { - return false; - } - - // No components of the composite can be pointers. - // TODO: - // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3658) - // Structs can have components of pointer type. - // FindOrCreateZeroConstant cannot be called on a - // pointer. We ignore pointers for now. Consider adding - // support for pointer types. - if (ContainsPointer(*instruction_type)) { - return false; - } - - return true; - }); - - // If there are no available values, then return. - if (available_composites.empty()) { - return; - } - - // Choose randomly one available composite value. - auto available_composite = - available_composites[GetFuzzerContext()->RandomIndex( - available_composites)]; - - // Take a random component of the chosen composite value. If the chosen - // component is itself a composite, then randomly decide whether to take - // its component and repeat. - uint32_t current_node_type_id = available_composite->type_id(); - std::vector path_to_replaced; - while (true) { - auto current_node_type_inst = - GetIRContext()->get_def_use_mgr()->GetDef(current_node_type_id); - uint32_t num_of_components = fuzzerutil::GetBoundForCompositeIndex( - *current_node_type_inst, GetIRContext()); - - // If the composite is empty, then end the iteration. - if (num_of_components == 0) { - break; - } - uint32_t one_selected_index = - GetFuzzerContext()->GetRandomIndexForCompositeInsert( - num_of_components); - - // Construct a final index by appending the current index. - path_to_replaced.push_back(one_selected_index); - current_node_type_id = fuzzerutil::WalkOneCompositeTypeIndex( - GetIRContext(), current_node_type_id, one_selected_index); - - // If the component is not a composite then end the iteration. - if (!fuzzerutil::IsCompositeType( - GetIRContext()->get_type_mgr()->GetType( - current_node_type_id))) { - break; - } - - // If the component is a composite, but we decide not to go deeper, - // then end the iteration. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfGoingDeeperToInsertInComposite())) { - break; - } - } - - // Look for available objects that have the type id - // |current_node_type_id| and can be inserted. - std::vector available_objects = - FindAvailableInstructions( - function, block, instruction_iterator, - [instruction_descriptor, current_node_type_id]( - opt::IRContext* /*unused*/, - opt::Instruction* instruction) -> bool { - if (instruction->result_id() == 0 || - instruction->type_id() == 0) { - return false; - } - if (instruction->type_id() != current_node_type_id) { - return false; - } - return true; - }); - - // If there are no objects of the specific type available, check if - // FindOrCreateZeroConstant can be called and create a zero constant of - // this type. - uint32_t available_object_id; - if (available_objects.empty()) { - auto current_node_type = - GetIRContext()->get_type_mgr()->GetType(current_node_type_id); - if (!CanFindOrCreateZeroConstant(*current_node_type)) { - return; - } - available_object_id = - FindOrCreateZeroConstant(current_node_type_id, false); - } else { - available_object_id = - available_objects[GetFuzzerContext()->RandomIndex( - available_objects)] - ->result_id(); - } - auto new_result_id = GetFuzzerContext()->GetFreshId(); - - // Insert an OpCompositeInsert instruction which copies - // |available_composite| and in the copy inserts the object - // of type |available_object_id| at index |index_to_replace|. - ApplyTransformation(TransformationCompositeInsert( - instruction_descriptor, new_result_id, - available_composite->result_id(), available_object_id, - path_to_replaced)); - }); -} - -bool FuzzerPassAddCompositeInserts::ContainsPointer( - const opt::analysis::Type& type) { - switch (type.kind()) { - case opt::analysis::Type::kPointer: - return true; - case opt::analysis::Type::kArray: - return ContainsPointer(*type.AsArray()->element_type()); - case opt::analysis::Type::kMatrix: - return ContainsPointer(*type.AsMatrix()->element_type()); - case opt::analysis::Type::kVector: - return ContainsPointer(*type.AsVector()->element_type()); - case opt::analysis::Type::kStruct: - return std::any_of(type.AsStruct()->element_types().begin(), - type.AsStruct()->element_types().end(), - [](const opt::analysis::Type* element_type) { - return ContainsPointer(*element_type); - }); - default: - return false; - } -} - -bool FuzzerPassAddCompositeInserts::ContainsRuntimeArray( - const opt::analysis::Type& type) { - switch (type.kind()) { - case opt::analysis::Type::kRuntimeArray: - return true; - case opt::analysis::Type::kStruct: - // If any component of a struct is of type OpTypeRuntimeArray, return - // true. - return std::any_of(type.AsStruct()->element_types().begin(), - type.AsStruct()->element_types().end(), - [](const opt::analysis::Type* element_type) { - return ContainsRuntimeArray(*element_type); - }); - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.h deleted file mode 100644 index 665efc958..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_inserts.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_FUZZER_PASS_ADD_COMPOSITE_INSERTS_H -#define SPIRV_TOOLS_FUZZER_PASS_ADD_COMPOSITE_INSERTS_H - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that randomly adds new OpCompositeInsert instructions to -// available values that have the composite type. -class FuzzerPassAddCompositeInserts : public FuzzerPass { - public: - FuzzerPassAddCompositeInserts( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddCompositeInserts(); - void Apply() override; - - // Checks if any component of a composite is a pointer. - static bool ContainsPointer(const opt::analysis::Type& type); - - // Checks if any component of a composite has type OpTypeRuntimeArray. - static bool ContainsRuntimeArray(const opt::analysis::Type& type); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_FUZZER_PASS_ADD_COMPOSITE_INSERTS_H diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp deleted file mode 100644 index 653d7848a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_composite_types.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_type_array.h" -#include "source/fuzz/transformation_add_type_struct.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddCompositeTypes::FuzzerPassAddCompositeTypes( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddCompositeTypes::~FuzzerPassAddCompositeTypes() = default; - -void FuzzerPassAddCompositeTypes::Apply() { - MaybeAddMissingVectorTypes(); - MaybeAddMissingMatrixTypes(); - - // Randomly interleave between adding struct and array composite types - while (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingArrayOrStructType())) { - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfChoosingStructTypeVsArrayType())) { - AddNewStructType(); - } else { - AddNewArrayType(); - } - } -} - -void FuzzerPassAddCompositeTypes::MaybeAddMissingVectorTypes() { - // Functions to lazily supply scalar base types on demand if we decide to - // create vectors with the relevant base types. - std::function bool_type_supplier = [this]() -> uint32_t { - return FindOrCreateBoolType(); - }; - std::function float_type_supplier = [this]() -> uint32_t { - return FindOrCreateFloatType(32); - }; - std::function int_type_supplier = [this]() -> uint32_t { - return FindOrCreateIntegerType(32, true); - }; - std::function uint_type_supplier = [this]() -> uint32_t { - return FindOrCreateIntegerType(32, false); - }; - - // Consider each of the base types with which we can make vectors. - for (auto& base_type_supplier : {bool_type_supplier, float_type_supplier, - int_type_supplier, uint_type_supplier}) { - // Consider each valid vector size. - for (uint32_t size = 2; size <= 4; size++) { - // Randomly decide whether to create (if it does not already exist) a - // vector with this size and base type. - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingVectorType())) { - FindOrCreateVectorType(base_type_supplier(), size); - } - } - } -} - -void FuzzerPassAddCompositeTypes::MaybeAddMissingMatrixTypes() { - // Consider every valid matrix dimension. - for (uint32_t columns = 2; columns <= 4; columns++) { - for (uint32_t rows = 2; rows <= 4; rows++) { - // Randomly decide whether to create (if it does not already exist) a - // matrix with these dimensions. As matrices can only have floating-point - // base type, we do not need to consider multiple base types as in the - // case for vectors. - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingMatrixType())) { - FindOrCreateMatrixType(columns, rows); - } - } - } -} - -void FuzzerPassAddCompositeTypes::AddNewArrayType() { - ApplyTransformation(TransformationAddTypeArray( - GetFuzzerContext()->GetFreshId(), ChooseScalarOrCompositeType(), - FindOrCreateIntegerConstant( - {GetFuzzerContext()->GetRandomSizeForNewArray()}, 32, false, false))); -} - -void FuzzerPassAddCompositeTypes::AddNewStructType() { - std::vector field_type_ids; - do { - field_type_ids.push_back(ChooseScalarOrCompositeType()); - } while (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingAnotherStructField())); - ApplyTransformation(TransformationAddTypeStruct( - GetFuzzerContext()->GetFreshId(), field_type_ids)); -} - -uint32_t FuzzerPassAddCompositeTypes::ChooseScalarOrCompositeType() { - // Gather up all the possibly-relevant types. - std::vector candidates; - for (auto& inst : GetIRContext()->types_values()) { - switch (inst.opcode()) { - case SpvOpTypeArray: - case SpvOpTypeBool: - case SpvOpTypeFloat: - case SpvOpTypeInt: - case SpvOpTypeMatrix: - case SpvOpTypeStruct: - case SpvOpTypeVector: - candidates.push_back(inst.result_id()); - break; - default: - break; - } - } - assert(!candidates.empty() && - "This function should only be called if there is at least one scalar " - "or composite type available."); - // Return one of these types at random. - return candidates[GetFuzzerContext()->RandomIndex(candidates)]; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h deleted file mode 100644 index 87bc0ff3f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_COMPOSITE_TYPES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_COMPOSITE_TYPES_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that randomly adds missing vector and matrix types, and new -// array and struct types, to the module. -class FuzzerPassAddCompositeTypes : public FuzzerPass { - public: - FuzzerPassAddCompositeTypes( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddCompositeTypes(); - - void Apply() override; - - private: - // Creates an array of a random size with a random existing base type and adds - // it to the module. - void AddNewArrayType(); - - // Creates a struct with fields of random existing types and adds it to the - // module. - void AddNewStructType(); - - // For each vector type not already present in the module, randomly decides - // whether to add it to the module. - void MaybeAddMissingVectorTypes(); - - // For each matrix type not already present in the module, randomly decides - // whether to add it to the module. - void MaybeAddMissingMatrixTypes(); - - // Returns the id of a scalar or composite type declared in the module, - // chosen randomly. - uint32_t ChooseScalarOrCompositeType(); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_COMPOSITE_TYPES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp deleted file mode 100644 index d98619c26..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_copy_memory.h" - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_add_copy_memory.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddCopyMemory::FuzzerPassAddCopyMemory( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddCopyMemory::~FuzzerPassAddCopyMemory() = default; - -void FuzzerPassAddCopyMemory::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) { - // Check that we can insert an OpCopyMemory before this instruction. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory, - inst_it)) { - return; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingCopyMemory())) { - return; - } - - // Get all instructions available before |inst_it| according to the - // domination rules. - auto instructions = FindAvailableInstructions( - function, block, inst_it, - TransformationAddCopyMemory::IsInstructionSupported); - - if (instructions.empty()) { - return; - } - - const auto* inst = - instructions[GetFuzzerContext()->RandomIndex(instructions)]; - - // Decide whether to create global or local variable. - auto storage_class = GetFuzzerContext()->ChooseEven() - ? SpvStorageClassPrivate - : SpvStorageClassFunction; - - auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType( - GetIRContext(), inst->type_id()); - - // Create a pointer type with |storage_class| if needed. - FindOrCreatePointerType(pointee_type_id, storage_class); - - ApplyTransformation(TransformationAddCopyMemory( - instruction_descriptor, GetFuzzerContext()->GetFreshId(), - inst->result_id(), storage_class, - FindOrCreateZeroConstant(pointee_type_id, false))); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h deleted file mode 100644 index 321e4a1d6..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_COPY_MEMORY_INSTRUCTIONS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_COPY_MEMORY_INSTRUCTIONS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Randomly decides whether to add OpCopyMemory before some instruction in the -// module. -class FuzzerPassAddCopyMemory : public FuzzerPass { - public: - FuzzerPassAddCopyMemory(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddCopyMemory() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_COPY_MEMORY_INSTRUCTIONS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp deleted file mode 100644 index 84ed1fb99..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_dead_blocks.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_dead_block.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddDeadBlocks::~FuzzerPassAddDeadBlocks() = default; - -void FuzzerPassAddDeadBlocks::Apply() { - // We iterate over all blocks in the module collecting up those at which we - // might add a branch to a new dead block. We then loop over all such - // candidates and actually apply transformations. This separation is to - // avoid modifying the module as we traverse it. - std::vector candidate_transformations; - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingDeadBlock())) { - continue; - } - - // Make sure the module contains a boolean constant equal to - // |condition_value|. - bool condition_value = GetFuzzerContext()->ChooseEven(); - FindOrCreateBoolConstant(condition_value, false); - - // We speculatively create a transformation, and then apply it (below) if - // it turns out to be applicable. This avoids duplicating the logic for - // applicability checking. - // - // It means that fresh ids for transformations that turn out not to be - // applicable end up being unused. - candidate_transformations.emplace_back(TransformationAddDeadBlock( - GetFuzzerContext()->GetFreshId(), block.id(), condition_value)); - } - } - // Apply all those transformations that are in fact applicable. - for (auto& transformation : candidate_transformations) { - MaybeApplyTransformation(transformation); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h deleted file mode 100644 index d78f08836..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass to add dynamically unreachable blocks to the module. Future -// passes can then manipulate such blocks. -class FuzzerPassAddDeadBlocks : public FuzzerPass { - public: - FuzzerPassAddDeadBlocks(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddDeadBlocks(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp deleted file mode 100644 index cf4ecee1d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_dead_breaks.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_dead_break.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default; - -void FuzzerPassAddDeadBreaks::Apply() { - // We first collect up lots of possibly-applicable transformations. - std::vector candidate_transformations; - // We consider each function separately. - for (auto& function : *GetIRContext()->module()) { - // For a given function, we find all the merge blocks in that function. - std::vector merge_blocks; - for (auto& block : function) { - auto maybe_merge_id = block.MergeBlockIdIfAny(); - if (maybe_merge_id) { - auto merge_block = - fuzzerutil::MaybeFindBlock(GetIRContext(), maybe_merge_id); - - assert(merge_block && "Merge block can't be null"); - - merge_blocks.push_back(merge_block); - } - } - // We rather aggressively consider the possibility of adding a break from - // every block in the function to every merge block. Many of these will be - // inapplicable as they would be illegal. That's OK - we later discard the - // ones that turn out to be no good. - for (auto& block : function) { - for (auto* merge_block : merge_blocks) { - // Populate this vector with ids that are available at the branch point - // of this basic block. We will use these ids to update OpPhi - // instructions later. - std::vector phi_ids; - - // Determine how we need to adjust OpPhi instructions' operands - // for this transformation to be valid. - // - // If |block| has a branch to |merge_block|, the latter must have all of - // its OpPhi instructions set up correctly - we don't need to adjust - // anything. - if (!block.IsSuccessor(merge_block)) { - merge_block->ForEachPhiInst([this, &phi_ids](opt::Instruction* phi) { - // Add an additional operand for OpPhi instruction. - // - // We mark the constant as irrelevant so that we can replace it with - // a more interesting value later. - phi_ids.push_back(FindOrCreateZeroConstant(phi->type_id(), true)); - }); - } - - // Make sure the module has a required boolean constant to be used in - // OpBranchConditional instruction. - auto break_condition = GetFuzzerContext()->ChooseEven(); - FindOrCreateBoolConstant(break_condition, false); - - auto candidate_transformation = TransformationAddDeadBreak( - block.id(), merge_block->id(), break_condition, std::move(phi_ids)); - if (candidate_transformation.IsApplicable( - GetIRContext(), *GetTransformationContext())) { - // Only consider a transformation as a candidate if it is applicable. - candidate_transformations.push_back( - std::move(candidate_transformation)); - } - } - } - } - - // Go through the candidate transformations that were accumulated, - // probabilistically deciding whether to consider each one further and - // applying the still-applicable ones that are considered further. - // - // We iterate through the candidate transformations in a random order by - // repeatedly removing a random candidate transformation from the sequence - // until no candidate transformations remain. This is done because - // transformations can potentially disable one another, so that iterating - // through them in order would lead to a higher probability of - // transformations appearing early in the sequence being applied compared - // with later transformations. - while (!candidate_transformations.empty()) { - // Choose a random index into the sequence of remaining candidate - // transformations. - auto index = GetFuzzerContext()->RandomIndex(candidate_transformations); - // Remove the transformation at the chosen index from the sequence. - auto transformation = std::move(candidate_transformations[index]); - candidate_transformations.erase(candidate_transformations.begin() + index); - // Probabilistically decide whether to try to apply it vs. ignore it, in the - // case that it is applicable. - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingDeadBreak())) { - MaybeApplyTransformation(transformation); - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h deleted file mode 100644 index c379eed51..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for adding dead break edges to the module. -class FuzzerPassAddDeadBreaks : public FuzzerPass { - public: - FuzzerPassAddDeadBreaks(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddDeadBreaks(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp deleted file mode 100644 index 61a7c6daa..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_dead_continues.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_dead_continue.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddDeadContinues::FuzzerPassAddDeadContinues( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddDeadContinues::~FuzzerPassAddDeadContinues() = default; - -void FuzzerPassAddDeadContinues::Apply() { - // Consider every block in every function. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // Get the label id of the continue target of the innermost loop. - auto continue_block_id = - block.IsLoopHeader() - ? block.ContinueBlockId() - : GetIRContext()->GetStructuredCFGAnalysis()->LoopContinueBlock( - block.id()); - - // This transformation is not applicable if current block is not inside a - // loop. - if (continue_block_id == 0) { - continue; - } - - auto* continue_block = - fuzzerutil::MaybeFindBlock(GetIRContext(), continue_block_id); - assert(continue_block && "Continue block is null"); - - // Analyze return type of each OpPhi instruction in the continue target - // and provide an id for the transformation if needed. - std::vector phi_ids; - // Check whether current block has an edge to the continue target. - // If this is the case, we don't need to do anything. - if (!block.IsSuccessor(continue_block)) { - continue_block->ForEachPhiInst([this, &phi_ids](opt::Instruction* phi) { - // Add an additional operand for OpPhi instruction. - // - // We mark the constant as irrelevant so that we can replace it with a - // more interesting value later. - phi_ids.push_back(FindOrCreateZeroConstant(phi->type_id(), true)); - }); - } - - // Make sure the module contains a boolean constant equal to - // |condition_value|. - bool condition_value = GetFuzzerContext()->ChooseEven(); - FindOrCreateBoolConstant(condition_value, false); - - // Make a transformation to add a dead continue from this node; if the - // node turns out to be inappropriate (e.g. by not being in a loop) the - // precondition for the transformation will fail and it will be ignored. - auto candidate_transformation = TransformationAddDeadContinue( - block.id(), condition_value, std::move(phi_ids)); - // Probabilistically decide whether to apply the transformation in the - // case that it is applicable. - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingDeadContinue())) { - MaybeApplyTransformation(candidate_transformation); - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h deleted file mode 100644 index b2acb935e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -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(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.cpp deleted file mode 100644 index 62fcfea7f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.cpp +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_equation_instructions.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_equation_instruction.h" - -namespace spvtools { -namespace fuzz { -namespace { - -bool IsBitWidthSupported(opt::IRContext* ir_context, uint32_t bit_width) { - switch (bit_width) { - case 32: - return true; - case 64: - return ir_context->get_feature_mgr()->HasCapability( - SpvCapabilityFloat64) && - ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt64); - case 16: - return ir_context->get_feature_mgr()->HasCapability( - SpvCapabilityFloat16) && - ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt16); - default: - return false; - } -} - -} // namespace - -FuzzerPassAddEquationInstructions::FuzzerPassAddEquationInstructions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddEquationInstructions::~FuzzerPassAddEquationInstructions() = - default; - -void FuzzerPassAddEquationInstructions::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) { - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingEquationInstruction())) { - return; - } - - // Check that it is OK to add an equation instruction before the given - // instruction in principle - e.g. check that this does not lead to - // inserting before an OpVariable or OpPhi instruction. We use OpIAdd - // as an example opcode for this check, to be representative of *some* - // opcode that defines an equation, even though we may choose a - // different opcode below. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) { - return; - } - - // Get all available instructions with result ids and types that are not - // OpUndef. - std::vector available_instructions = - FindAvailableInstructions( - function, block, inst_it, - [this](opt::IRContext*, opt::Instruction* instruction) -> bool { - return instruction->result_id() && instruction->type_id() && - instruction->opcode() != SpvOpUndef && - !GetTransformationContext() - ->GetFactManager() - ->IdIsIrrelevant(instruction->result_id()); - }); - - // Try the opcodes for which we know how to make ids at random until - // something works. - std::vector candidate_opcodes = { - SpvOpIAdd, SpvOpISub, SpvOpLogicalNot, SpvOpSNegate, - SpvOpConvertUToF, SpvOpConvertSToF, SpvOpBitcast}; - do { - auto opcode = - GetFuzzerContext()->RemoveAtRandomIndex(&candidate_opcodes); - switch (opcode) { - case SpvOpConvertSToF: - case SpvOpConvertUToF: { - std::vector candidate_instructions; - for (const auto* inst : - GetIntegerInstructions(available_instructions)) { - const auto* type = - GetIRContext()->get_type_mgr()->GetType(inst->type_id()); - assert(type && "|inst| has invalid type"); - - if (const auto* vector_type = type->AsVector()) { - type = vector_type->element_type(); - } - - if (IsBitWidthSupported(GetIRContext(), - type->AsInteger()->width())) { - candidate_instructions.push_back(inst); - } - } - - if (candidate_instructions.empty()) { - break; - } - - const auto* operand = - candidate_instructions[GetFuzzerContext()->RandomIndex( - candidate_instructions)]; - - const auto* type = - GetIRContext()->get_type_mgr()->GetType(operand->type_id()); - assert(type && "Operand has invalid type"); - - // Make sure a result type exists in the module. - if (const auto* vector = type->AsVector()) { - // We store element count in a separate variable since the - // call FindOrCreate* functions below might invalidate - // |vector| pointer. - const auto element_count = vector->element_count(); - - FindOrCreateVectorType( - FindOrCreateFloatType( - vector->element_type()->AsInteger()->width()), - element_count); - } else { - FindOrCreateFloatType(type->AsInteger()->width()); - } - - ApplyTransformation(TransformationEquationInstruction( - GetFuzzerContext()->GetFreshId(), opcode, - {operand->result_id()}, instruction_descriptor)); - return; - } - case SpvOpBitcast: { - const auto candidate_instructions = - GetNumericalInstructions(available_instructions); - - if (!candidate_instructions.empty()) { - const auto* operand_inst = - candidate_instructions[GetFuzzerContext()->RandomIndex( - candidate_instructions)]; - const auto* operand_type = - GetIRContext()->get_type_mgr()->GetType( - operand_inst->type_id()); - assert(operand_type && "Operand instruction has invalid type"); - - // Make sure a result type exists in the module. - // - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3539): - // The only constraint on the types of OpBitcast's parameters - // is that they must have the same number of bits. Consider - // improving the code below to support this in full. - if (const auto* vector = operand_type->AsVector()) { - // We store element count in a separate variable since the - // call FindOrCreate* functions below might invalidate - // |vector| pointer. - const auto element_count = vector->element_count(); - - uint32_t element_type_id; - if (const auto* int_type = - vector->element_type()->AsInteger()) { - element_type_id = FindOrCreateFloatType(int_type->width()); - } else { - assert(vector->element_type()->AsFloat() && - "Vector must have numerical elements"); - element_type_id = FindOrCreateIntegerType( - vector->element_type()->AsFloat()->width(), - GetFuzzerContext()->ChooseEven()); - } - - FindOrCreateVectorType(element_type_id, element_count); - } else if (const auto* int_type = operand_type->AsInteger()) { - FindOrCreateFloatType(int_type->width()); - } else { - assert(operand_type->AsFloat() && - "Operand is not a scalar of numerical type"); - FindOrCreateIntegerType(operand_type->AsFloat()->width(), - GetFuzzerContext()->ChooseEven()); - } - - ApplyTransformation(TransformationEquationInstruction( - GetFuzzerContext()->GetFreshId(), opcode, - {operand_inst->result_id()}, instruction_descriptor)); - return; - } - } break; - case SpvOpIAdd: - case SpvOpISub: { - // Instructions of integer (scalar or vector) result type are - // suitable for these opcodes. - auto integer_instructions = - GetIntegerInstructions(available_instructions); - if (!integer_instructions.empty()) { - // There is at least one such instruction, so pick one at random - // for the LHS of an equation. - auto lhs = integer_instructions.at( - GetFuzzerContext()->RandomIndex(integer_instructions)); - - // For the RHS, we can use any instruction with an integer - // scalar/vector result type of the same number of components - // and the same bit-width for the underlying integer type. - - // Work out the element count and bit-width. - auto lhs_type = - GetIRContext()->get_type_mgr()->GetType(lhs->type_id()); - uint32_t lhs_element_count; - uint32_t lhs_bit_width; - if (lhs_type->AsVector()) { - lhs_element_count = lhs_type->AsVector()->element_count(); - lhs_bit_width = lhs_type->AsVector() - ->element_type() - ->AsInteger() - ->width(); - } else { - lhs_element_count = 1; - lhs_bit_width = lhs_type->AsInteger()->width(); - } - - // Get all the instructions that match on element count and - // bit-width. - auto candidate_rhs_instructions = RestrictToElementBitWidth( - RestrictToVectorWidth(integer_instructions, - lhs_element_count), - lhs_bit_width); - - // Choose a RHS instruction at random; there is guaranteed to - // be at least one choice as the LHS will be available. - auto rhs = candidate_rhs_instructions.at( - GetFuzzerContext()->RandomIndex( - candidate_rhs_instructions)); - - // Add the equation instruction. - ApplyTransformation(TransformationEquationInstruction( - GetFuzzerContext()->GetFreshId(), opcode, - {lhs->result_id(), rhs->result_id()}, - instruction_descriptor)); - return; - } - break; - } - case SpvOpLogicalNot: { - // Choose any available instruction of boolean scalar/vector - // result type and equate its negation with a fresh id. - auto boolean_instructions = - GetBooleanInstructions(available_instructions); - if (!boolean_instructions.empty()) { - ApplyTransformation(TransformationEquationInstruction( - GetFuzzerContext()->GetFreshId(), opcode, - {boolean_instructions - .at(GetFuzzerContext()->RandomIndex( - boolean_instructions)) - ->result_id()}, - instruction_descriptor)); - return; - } - break; - } - case SpvOpSNegate: { - // Similar to OpLogicalNot, but for signed integer negation. - auto integer_instructions = - GetIntegerInstructions(available_instructions); - if (!integer_instructions.empty()) { - ApplyTransformation(TransformationEquationInstruction( - GetFuzzerContext()->GetFreshId(), opcode, - {integer_instructions - .at(GetFuzzerContext()->RandomIndex( - integer_instructions)) - ->result_id()}, - instruction_descriptor)); - return; - } - break; - } - default: - assert(false && "Unexpected opcode."); - break; - } - } while (!candidate_opcodes.empty()); - // Reaching here means that we did not manage to apply any - // transformation at this point of the module. - }); -} - -std::vector -FuzzerPassAddEquationInstructions::GetIntegerInstructions( - const std::vector& instructions) const { - std::vector result; - for (auto& inst : instructions) { - auto type = GetIRContext()->get_type_mgr()->GetType(inst->type_id()); - if (type->AsInteger() || - (type->AsVector() && type->AsVector()->element_type()->AsInteger())) { - result.push_back(inst); - } - } - return result; -} - -std::vector -FuzzerPassAddEquationInstructions::GetFloatInstructions( - const std::vector& instructions) const { - std::vector result; - for (auto& inst : instructions) { - auto type = GetIRContext()->get_type_mgr()->GetType(inst->type_id()); - if (type->AsFloat() || - (type->AsVector() && type->AsVector()->element_type()->AsFloat())) { - result.push_back(inst); - } - } - return result; -} - -std::vector -FuzzerPassAddEquationInstructions::GetBooleanInstructions( - const std::vector& instructions) const { - std::vector result; - for (auto& inst : instructions) { - auto type = GetIRContext()->get_type_mgr()->GetType(inst->type_id()); - if (type->AsBool() || - (type->AsVector() && type->AsVector()->element_type()->AsBool())) { - result.push_back(inst); - } - } - return result; -} - -std::vector -FuzzerPassAddEquationInstructions::RestrictToVectorWidth( - const std::vector& instructions, - uint32_t vector_width) const { - std::vector result; - for (auto& inst : instructions) { - auto type = GetIRContext()->get_type_mgr()->GetType(inst->type_id()); - // Get the vector width of |inst|, which is 1 if |inst| is a scalar and is - // otherwise derived from its vector type. - uint32_t other_vector_width = - type->AsVector() ? type->AsVector()->element_count() : 1; - // Keep |inst| if the vector widths match. - if (vector_width == other_vector_width) { - result.push_back(inst); - } - } - return result; -} - -std::vector -FuzzerPassAddEquationInstructions::RestrictToElementBitWidth( - const std::vector& instructions, - uint32_t bit_width) const { - std::vector result; - for (auto& inst : instructions) { - const opt::analysis::Type* type = - GetIRContext()->get_type_mgr()->GetType(inst->type_id()); - if (type->AsVector()) { - type = type->AsVector()->element_type(); - } - assert((type->AsInteger() || type->AsFloat()) && - "Precondition: all input instructions must " - "have integer or float scalar or vector type."); - if ((type->AsInteger() && type->AsInteger()->width() == bit_width) || - (type->AsFloat() && type->AsFloat()->width() == bit_width)) { - result.push_back(inst); - } - } - return result; -} - -std::vector -FuzzerPassAddEquationInstructions::GetNumericalInstructions( - const std::vector& instructions) const { - std::vector result; - - for (auto* inst : instructions) { - const auto* type = GetIRContext()->get_type_mgr()->GetType(inst->type_id()); - assert(type && "Instruction has invalid type"); - - if (const auto* vector_type = type->AsVector()) { - type = vector_type->element_type(); - } - - if (!type->AsInteger() && !type->AsFloat()) { - // Only numerical scalars or vectors of numerical components are - // supported. - continue; - } - - if (!IsBitWidthSupported(GetIRContext(), type->AsInteger() - ? type->AsInteger()->width() - : type->AsFloat()->width())) { - continue; - } - - result.push_back(inst); - } - - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.h deleted file mode 100644 index 9ce581eb3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_equation_instructions.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_EQUATION_INSTRUCTIONS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_EQUATION_INSTRUCTIONS_H_ - -#include - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that sprinkles instructions through the module that define -// equations using various arithmetic and logical operators. -class FuzzerPassAddEquationInstructions : public FuzzerPass { - public: - FuzzerPassAddEquationInstructions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddEquationInstructions(); - - void Apply() override; - - private: - // Yields those instructions in |instructions| that have integer scalar or - // vector result type. - std::vector GetIntegerInstructions( - const std::vector& instructions) const; - - // Returns only instructions, that have either a scalar floating-point or a - // vector type. - std::vector GetFloatInstructions( - const std::vector& instructions) const; - - // Yields those instructions in |instructions| that have boolean scalar or - // vector result type. - std::vector GetBooleanInstructions( - const std::vector& instructions) const; - - // Yields those instructions in |instructions| that have a scalar numerical or - // a vector of numerical components type. Only 16, 32 and 64-bit numericals - // are supported if both OpTypeInt and OpTypeFloat instructions can be created - // with the specified width (e.g. for 16-bit types both Float16 and Int16 - // capabilities must be present). - std::vector GetNumericalInstructions( - const std::vector& instructions) const; - - // Requires that |instructions| are scalars or vectors of some type. Returns - // only those instructions whose width is |width|. If |width| is 1 this means - // the scalars. - std::vector RestrictToVectorWidth( - const std::vector& instructions, - uint32_t vector_width) const; - - // Requires that |instructions| are integer or float scalars or vectors. - // Returns only those instructions for which the bit-width of the underlying - // integer or floating-point type is |bit_width|. - std::vector RestrictToElementBitWidth( - const std::vector& instructions, - uint32_t bit_width) const; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_EQUATION_INSTRUCTIONS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.cpp deleted file mode 100644 index b6f4c85d0..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_function_calls.h" - -#include "source/fuzz/call_graph.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_global_variable.h" -#include "source/fuzz/transformation_add_local_variable.h" -#include "source/fuzz/transformation_function_call.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddFunctionCalls::FuzzerPassAddFunctionCalls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddFunctionCalls::~FuzzerPassAddFunctionCalls() = default; - -void FuzzerPassAddFunctionCalls::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - // Check whether it is legitimate to insert a function call before the - // instruction. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpFunctionCall, - inst_it)) { - return; - } - - // Randomly decide whether to try inserting a function call here. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfCallingFunction())) { - return; - } - - // Compute the module's call graph - we don't cache it since it may - // change each time we apply a transformation. If this proves to be - // a bottleneck the call graph data structure could be made updatable. - CallGraph call_graph(GetIRContext()); - - // Gather all the non-entry point functions different from this - // function. It is important to ignore entry points as a function - // cannot be an entry point and the target of an OpFunctionCall - // instruction. We ignore this function to avoid direct recursion. - std::vector candidate_functions; - for (auto& other_function : *GetIRContext()->module()) { - if (&other_function != function && - !fuzzerutil::FunctionIsEntryPoint(GetIRContext(), - other_function.result_id())) { - candidate_functions.push_back(&other_function); - } - } - - // Choose a function to call, at random, by considering candidate - // functions until a suitable one is found. - opt::Function* chosen_function = nullptr; - while (!candidate_functions.empty()) { - opt::Function* candidate_function = - GetFuzzerContext()->RemoveAtRandomIndex(&candidate_functions); - if (!GetTransformationContext()->GetFactManager()->BlockIsDead( - block->id()) && - !GetTransformationContext()->GetFactManager()->FunctionIsLivesafe( - candidate_function->result_id())) { - // Unless in a dead block, only livesafe functions can be invoked - continue; - } - if (call_graph.GetIndirectCallees(candidate_function->result_id()) - .count(function->result_id())) { - // Calling this function could lead to indirect recursion - continue; - } - chosen_function = candidate_function; - break; - } - - if (!chosen_function) { - // No suitable function was found to call. (This can happen, for - // instance, if the current function is the only function in the - // module.) - return; - } - - ApplyTransformation(TransformationFunctionCall( - GetFuzzerContext()->GetFreshId(), chosen_function->result_id(), - ChooseFunctionCallArguments(*chosen_function, function, block, - inst_it), - instruction_descriptor)); - }); -} - -std::vector FuzzerPassAddFunctionCalls::ChooseFunctionCallArguments( - const opt::Function& callee, opt::Function* caller_function, - opt::BasicBlock* caller_block, - const opt::BasicBlock::iterator& caller_inst_it) { - auto available_pointers = FindAvailableInstructions( - caller_function, caller_block, caller_inst_it, - [this, caller_block](opt::IRContext* /*unused*/, opt::Instruction* inst) { - if (inst->opcode() != SpvOpVariable || - inst->opcode() != SpvOpFunctionParameter) { - // Function parameters and variables are the only - // kinds of pointer that can be used as actual - // parameters. - return false; - } - - return GetTransformationContext()->GetFactManager()->BlockIsDead( - caller_block->id()) || - GetTransformationContext() - ->GetFactManager() - ->PointeeValueIsIrrelevant(inst->result_id()); - }); - - std::unordered_map> type_id_to_result_id; - for (const auto* inst : available_pointers) { - type_id_to_result_id[inst->type_id()].push_back(inst->result_id()); - } - - std::vector result; - for (const auto* param : - fuzzerutil::GetParameters(GetIRContext(), callee.result_id())) { - const auto* param_type = - GetIRContext()->get_type_mgr()->GetType(param->type_id()); - assert(param_type && "Parameter has invalid type"); - - if (!param_type->AsPointer()) { - // We mark the constant as irrelevant so that we can replace it with a - // more interesting value later. - result.push_back(FindOrCreateZeroConstant(param->type_id(), true)); - continue; - } - - if (type_id_to_result_id.count(param->type_id())) { - // Use an existing pointer if there are any. - const auto& candidates = type_id_to_result_id[param->type_id()]; - result.push_back(candidates[GetFuzzerContext()->RandomIndex(candidates)]); - continue; - } - - // Make a new variable, at function or global scope depending on the storage - // class of the pointer. - - // Get a fresh id for the new variable. - uint32_t fresh_variable_id = GetFuzzerContext()->GetFreshId(); - - // The id of this variable is what we pass as the parameter to - // the call. - result.push_back(fresh_variable_id); - type_id_to_result_id[param->type_id()].push_back(fresh_variable_id); - - // Now bring the variable into existence. - auto storage_class = param_type->AsPointer()->storage_class(); - auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType( - GetIRContext(), param->type_id()); - if (storage_class == SpvStorageClassFunction) { - // Add a new zero-initialized local variable to the current - // function, noting that its pointee value is irrelevant. - ApplyTransformation(TransformationAddLocalVariable( - fresh_variable_id, param->type_id(), caller_function->result_id(), - FindOrCreateZeroConstant(pointee_type_id, false), true)); - } else { - assert((storage_class == SpvStorageClassPrivate || - storage_class == SpvStorageClassWorkgroup) && - "Only Function, Private and Workgroup storage classes are " - "supported at present."); - // Add a new global variable to the module, zero-initializing it if - // it has Private storage class, and noting that its pointee value is - // irrelevant. - ApplyTransformation(TransformationAddGlobalVariable( - fresh_variable_id, param->type_id(), storage_class, - storage_class == SpvStorageClassPrivate - ? FindOrCreateZeroConstant(pointee_type_id, false) - : 0, - true)); - } - } - - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.h deleted file mode 100644 index 4ed879116..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_function_calls.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_FUNCTION_CALLS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_FUNCTION_CALLS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that adds calls at random to (a) livesafe functions, from -// 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(); - - void Apply() override; - - private: - // Randomly chooses suitable arguments to invoke |callee| right before - // instruction |caller_inst_it| of block |caller_block| in |caller_function|, - // based on both existing available instructions and the addition of new - // instructions to the module. - std::vector ChooseFunctionCallArguments( - const opt::Function& callee, opt::Function* caller_function, - opt::BasicBlock* caller_block, - const opt::BasicBlock::iterator& caller_inst_it); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_FUNCTION_CALLS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp deleted file mode 100644 index 9a45a374d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_global_variables.h" - -#include "source/fuzz/transformation_add_global_variable.h" -#include "source/fuzz/transformation_add_type_pointer.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default; - -void FuzzerPassAddGlobalVariables::Apply() { - SpvStorageClass variable_storage_class = SpvStorageClassPrivate; - for (auto& entry_point : GetIRContext()->module()->entry_points()) { - // If the execution model of some entry point is GLCompute, - // then the variable storage class may be Workgroup. - if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelGLCompute) { - variable_storage_class = - GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfChoosingWorkgroupStorageClass()) - ? SpvStorageClassWorkgroup - : SpvStorageClassPrivate; - break; - } - } - - auto basic_type_ids_and_pointers = - GetAvailableBasicTypesAndPointers(variable_storage_class); - - // These are the basic types that are available to this fuzzer pass. - auto& basic_types = basic_type_ids_and_pointers.first; - - // 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 - // none are available for a given basic type. - auto& basic_type_to_pointers = basic_type_ids_and_pointers.second; - - // Probabilistically keep adding global variables. - while (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingGlobalVariable())) { - // Choose a random basic type; the new variable's type will be a pointer to - // this basic type. - uint32_t basic_type = - basic_types[GetFuzzerContext()->RandomIndex(basic_types)]; - uint32_t pointer_type_id; - std::vector& available_pointers_to_basic_type = - basic_type_to_pointers.at(basic_type); - // Determine whether there is at least one pointer to this basic type. - if (available_pointers_to_basic_type.empty()) { - // There is not. Make one, to use here, and add it to the available - // pointers for the basic type so that future variables can potentially - // use it. - pointer_type_id = GetFuzzerContext()->GetFreshId(); - available_pointers_to_basic_type.push_back(pointer_type_id); - ApplyTransformation(TransformationAddTypePointer( - pointer_type_id, variable_storage_class, basic_type)); - } else { - // There is - grab one. - pointer_type_id = - available_pointers_to_basic_type[GetFuzzerContext()->RandomIndex( - available_pointers_to_basic_type)]; - } - - ApplyTransformation(TransformationAddGlobalVariable( - GetFuzzerContext()->GetFreshId(), pointer_type_id, - variable_storage_class, - variable_storage_class == SpvStorageClassPrivate - ? FindOrCreateZeroConstant(basic_type, false) - : 0, - true)); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.h deleted file mode 100644 index a907d360c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_GLOBAL_VARIABLES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_GLOBAL_VARIABLES_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that randomly adds global variables, with Private storage class, -// to the module. -class FuzzerPassAddGlobalVariables : public FuzzerPass { - public: - FuzzerPassAddGlobalVariables( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddGlobalVariables(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_GLOBAL_VARIABLES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp deleted file mode 100644 index 313bb0d1f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_add_image_sample_unused_components.h" -#include "source/fuzz/transformation_composite_construct.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddImageSampleUnusedComponents:: - FuzzerPassAddImageSampleUnusedComponents( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddImageSampleUnusedComponents:: - ~FuzzerPassAddImageSampleUnusedComponents() = default; - -void FuzzerPassAddImageSampleUnusedComponents::Apply() { - // SPIR-V module to help understand the transformation. - // - // OpCapability Shader - // %1 = OpExtInstImport "GLSL.std.450" - // OpMemoryModel Logical GLSL450 - // OpEntryPoint Fragment %15 "main" %12 %14 - // OpExecutionMode %15 OriginUpperLeft - // - // ; Decorations - // OpDecorate %12 Location 0 ; Input color variable location - // OpDecorate %13 DescriptorSet 0 ; Image coordinate variable - // descriptor set OpDecorate %13 Binding 0 ; Image coordinate - // variable binding OpDecorate %14 Location 0 ; Fragment color - // variable location - // - // ; Types - // %2 = OpTypeVoid - // %3 = OpTypeFunction %2 - // %4 = OpTypeFloat 32 - // %5 = OpTypeVector %4 2 - // %6 = OpTypeVector %4 4 - // %7 = OpTypeImage %4 2D 0 0 0 1 Rgba32f - // %8 = OpTypeSampledImage %7 - // %9 = OpTypePointer Input %5 - // %10 = OpTypePointer UniformConstant %8 - // %11 = OpTypePointer Output %6 - // - // ; Variables - // %12 = OpVariable %9 Input ; Input image coordinate variable - // %13 = OpVariable %10 UniformConstant ; Image variable - // %14 = OpVariable %11 Output ; Fragment color variable - // - // ; main function - // %15 = OpFunction %2 None %3 - // %16 = OpLabel - // %17 = OpLoad %5 %12 - // %18 = OpLoad %8 %13 - // %19 = OpImageSampleImplicitLod %6 %18 %17 - // OpStore %14 %19 - // OpReturn - // OpFunctionEnd - - GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { - // |instruction| %19 = OpImageSampleImplicitLod %6 %18 %17 - if (!spvOpcodeIsImageSample(instruction->opcode())) { - return; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfAddingImageSampleUnusedComponents())) { - return; - } - - // Gets image sample coordinate information. - // |coordinate_instruction| %17 = OpLoad %5 %12 - uint32_t coordinate_id = instruction->GetSingleWordInOperand(1); - auto coordinate_instruction = - GetIRContext()->get_def_use_mgr()->GetDef(coordinate_id); - auto coordinate_type = GetIRContext()->get_type_mgr()->GetType( - coordinate_instruction->type_id()); - - // If the coordinate is a 4-dimensional vector, then no unused components - // may be added. - if (coordinate_type->AsVector() && - coordinate_type->AsVector()->element_count() == 4) { - return; - } - - // If the coordinate is a scalar, then at most 3 unused components may be - // added. If the coordinate is a vector, then the maximum number of unused - // components depends on the vector size. - // For the sample module, the coordinate type instruction is %5 = - // OpTypeVector %4 2, thus |max_unused_component_count| = 4 - 2 = 2. - uint32_t max_unused_component_count = - coordinate_type->AsInteger() || coordinate_type->AsFloat() - ? 3 - : 4 - coordinate_type->AsVector()->element_count(); - - // |unused_component_count| may be 1 or 2. - uint32_t unused_component_count = - GetFuzzerContext()->GetRandomUnusedComponentCountForImageSample( - max_unused_component_count); - - // Gets a type for the zero-unused components. - uint32_t zero_constant_type_id; - switch (unused_component_count) { - case 1: - // If the coordinate is an integer or float, then the unused components - // type is the same as the coordinate. If the coordinate is a vector, - // then the unused components type is the same as the vector components - // type. - zero_constant_type_id = - coordinate_type->AsInteger() || coordinate_type->AsFloat() - ? coordinate_instruction->type_id() - : GetIRContext()->get_type_mgr()->GetId( - coordinate_type->AsVector()->element_type()); - break; - case 2: - case 3: - // If the coordinate is an integer or float, then the unused components - // type is the same as the coordinate. If the coordinate is a vector, - // then the unused components type is the same as the coordinate - // components type. - // |zero_constant_type_id| %5 = OpTypeVector %4 2 - zero_constant_type_id = - coordinate_type->AsInteger() || coordinate_type->AsFloat() - ? FindOrCreateVectorType(coordinate_instruction->type_id(), - unused_component_count) - : FindOrCreateVectorType( - GetIRContext()->get_type_mgr()->GetId( - coordinate_type->AsVector()->element_type()), - unused_component_count); - break; - default: - assert(false && "Should be unreachable."); - zero_constant_type_id = 0; - break; - } - - // Gets |coordinate_type| again because the module may have changed due to - // the use of FindOrCreateVectorType above. - coordinate_type = GetIRContext()->get_type_mgr()->GetType( - coordinate_instruction->type_id()); - - // If the new vector type with unused components does not exist, then create - // it. |coordinate_with_unused_components_type_id| %6 = OpTypeVector %4 4 - uint32_t coordinate_with_unused_components_type_id = - coordinate_type->AsInteger() || coordinate_type->AsFloat() - ? FindOrCreateVectorType(coordinate_instruction->type_id(), - 1 + unused_component_count) - : FindOrCreateVectorType( - GetIRContext()->get_type_mgr()->GetId( - coordinate_type->AsVector()->element_type()), - coordinate_type->AsVector()->element_count() + - unused_component_count); - - // Inserts an OpCompositeConstruct instruction which - // represents the coordinate with unused components. - // |coordinate_with_unused_components_id| - // %22 = OpCompositeConstruct %6 %17 %21 - uint32_t coordinate_with_unused_components_id = - GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationCompositeConstruct( - coordinate_with_unused_components_type_id, - {coordinate_instruction->result_id(), - // FindOrCreateZeroConstant - // %20 = OpConstant %4 0 - // %21 = OpConstantComposite %5 %20 %20 - FindOrCreateZeroConstant(zero_constant_type_id, false)}, - MakeInstructionDescriptor(GetIRContext(), instruction), - coordinate_with_unused_components_id)); - - // Tries to add unused components to the image sample coordinate. - // %19 = OpImageSampleImplicitLod %6 %18 %22 - ApplyTransformation(TransformationAddImageSampleUnusedComponents( - coordinate_with_unused_components_id, - MakeInstructionDescriptor(GetIRContext(), instruction))); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h deleted file mode 100644 index 26374c326..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// This fuzzer pass searches for image sample instructions in the module and -// randomly applies the transformation to add unused components to the image -// sample coordinate. -class FuzzerPassAddImageSampleUnusedComponents : public FuzzerPass { - public: - FuzzerPassAddImageSampleUnusedComponents( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddImageSampleUnusedComponents(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loads.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loads.cpp deleted file mode 100644 index 256255bcd..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loads.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_loads.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_load.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddLoads::FuzzerPassAddLoads( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddLoads::~FuzzerPassAddLoads() = default; - -void FuzzerPassAddLoads::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - assert(inst_it->opcode() == - instruction_descriptor.target_instruction_opcode() && - "The opcode of the instruction we might insert before must be " - "the same as the opcode in the descriptor for the instruction"); - - // Check whether it is legitimate to insert a 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; - } - - std::vector relevant_instructions = - FindAvailableInstructions( - function, block, inst_it, - [](opt::IRContext* context, - opt::Instruction* instruction) -> bool { - if (!instruction->result_id() || !instruction->type_id()) { - return false; - } - switch (instruction->opcode()) { - case SpvOpConstantNull: - case SpvOpUndef: - // Do not allow loading from a null or undefined pointer; - // this might be OK if the block is dead, but for now we - // conservatively avoid it. - return false; - default: - break; - } - return context->get_def_use_mgr() - ->GetDef(instruction->type_id()) - ->opcode() == SpvOpTypePointer; - }); - - // At this point, |relevant_instructions| contains all the pointers - // we might think of loading from. - if (relevant_instructions.empty()) { - return; - } - - // Choose a pointer at random, and create and apply a loading - // transformation based on it. - ApplyTransformation(TransformationLoad( - GetFuzzerContext()->GetFreshId(), - relevant_instructions[GetFuzzerContext()->RandomIndex( - relevant_instructions)] - ->result_id(), - instruction_descriptor)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loads.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loads.h deleted file mode 100644 index c4d5b27e2..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loads.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_LOADS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_LOADS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that adds stores, at random, from pointers in the module. -class FuzzerPassAddLoads : public FuzzerPass { - public: - FuzzerPassAddLoads(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddLoads(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_LOADS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.cpp deleted file mode 100644 index ef8b5d0e9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_local_variables.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_local_variable.h" -#include "source/fuzz/transformation_add_type_pointer.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddLocalVariables::FuzzerPassAddLocalVariables( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddLocalVariables::~FuzzerPassAddLocalVariables() = default; - -void FuzzerPassAddLocalVariables::Apply() { - auto basic_type_ids_and_pointers = - GetAvailableBasicTypesAndPointers(SpvStorageClassFunction); - - // These are the basic types that are available to this fuzzer pass. - auto& basic_types = basic_type_ids_and_pointers.first; - - // 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 - // none are available for a given basic type. - auto& basic_type_to_pointers = basic_type_ids_and_pointers.second; - - // Consider every function in the module. - for (auto& function : *GetIRContext()->module()) { - // Probabilistically keep adding random variables to this function. - while (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingLocalVariable())) { - // Choose a random basic type; the new variable's type will be a pointer - // to this basic type. - uint32_t basic_type = - basic_types[GetFuzzerContext()->RandomIndex(basic_types)]; - uint32_t pointer_type; - std::vector& available_pointers_to_basic_type = - basic_type_to_pointers.at(basic_type); - // Determine whether there is at least one pointer to this basic type. - if (available_pointers_to_basic_type.empty()) { - // There is not. Make one, to use here, and add it to the available - // pointers for the basic type so that future variables can potentially - // use it. - pointer_type = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypePointer( - pointer_type, SpvStorageClassFunction, basic_type)); - available_pointers_to_basic_type.push_back(pointer_type); - } else { - // There is - grab one. - pointer_type = - available_pointers_to_basic_type[GetFuzzerContext()->RandomIndex( - available_pointers_to_basic_type)]; - } - ApplyTransformation(TransformationAddLocalVariable( - GetFuzzerContext()->GetFreshId(), pointer_type, function.result_id(), - FindOrCreateZeroConstant(basic_type, false), true)); - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.h deleted file mode 100644 index 08d26d8c3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_local_variables.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_LOCAL_VARIABLES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_LOCAL_VARIABLES_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that randomly adds local variables, with Function storage class, -// to the module. -class FuzzerPassAddLocalVariables : public FuzzerPass { - public: - FuzzerPassAddLocalVariables( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddLocalVariables(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_LOCAL_VARIABLES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp deleted file mode 100644 index bdc315136..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_loop_preheaders.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_loop_preheader.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddLoopPreheaders::FuzzerPassAddLoopPreheaders( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddLoopPreheaders::~FuzzerPassAddLoopPreheaders() = default; - -void FuzzerPassAddLoopPreheaders::Apply() { - for (auto& function : *GetIRContext()->module()) { - // Keep track of all the loop headers we want to add a preheader to. - std::vector loop_header_ids_to_consider; - for (auto& block : function) { - // We only care about loop headers. - if (!block.IsLoopHeader()) { - continue; - } - - // Randomly decide whether to consider this header. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingLoopPreheader())) { - continue; - } - - // We exclude loop headers with just one predecessor (the back-edge block) - // because they are unreachable. - if (GetIRContext()->cfg()->preds(block.id()).size() < 2) { - continue; - } - - loop_header_ids_to_consider.push_back(block.id()); - } - - for (uint32_t header_id : loop_header_ids_to_consider) { - // If not already present, add a preheader which is not also a loop - // header. - GetOrCreateSimpleLoopPreheader(header_id); - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.h deleted file mode 100644 index a8350567a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_loop_preheaders.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_LOOP_PREHEADERS_H -#define SOURCE_FUZZ_FUZZER_PASS_ADD_LOOP_PREHEADERS_H - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass that randomly adds simple loop preheaders to loops that do not -// have one. A simple loop preheader is a block that: -// - is the only out-of-loop predecessor of the header -// - branches unconditionally to the header -// - is not a loop header itself -class FuzzerPassAddLoopPreheaders : public FuzzerPass { - public: - FuzzerPassAddLoopPreheaders( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddLoopPreheaders(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_LOOP_PREHEADERS_H diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp deleted file mode 100644 index 09627d098..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h" - -#include "source/fuzz/transformation_add_no_contraction_decoration.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddNoContractionDecorations::FuzzerPassAddNoContractionDecorations( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddNoContractionDecorations:: - ~FuzzerPassAddNoContractionDecorations() = default; - -void FuzzerPassAddNoContractionDecorations::Apply() { - // Consider every instruction in every block in every function. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - for (auto& inst : block) { - // Restrict attention to arithmetic instructions (as defined in the - // SPIR-V specification). - if (TransformationAddNoContractionDecoration::IsArithmetic( - inst.opcode())) { - // Randomly choose whether to apply the NoContraction decoration to - // this arithmetic instruction. - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfAddingNoContractionDecoration())) { - TransformationAddNoContractionDecoration transformation( - inst.result_id()); - ApplyTransformation(transformation); - } - } - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h deleted file mode 100644 index f32e5bc61..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A pass that applies the NoContraction decoration to arithmetic instructions. -class FuzzerPassAddNoContractionDecorations : public FuzzerPass { - public: - FuzzerPassAddNoContractionDecorations( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddNoContractionDecorations() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp deleted file mode 100644 index 97adfb240..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_opphi_synonyms.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_opphi_synonym.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddOpPhiSynonyms::FuzzerPassAddOpPhiSynonyms( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddOpPhiSynonyms::~FuzzerPassAddOpPhiSynonyms() = default; - -void FuzzerPassAddOpPhiSynonyms::Apply() { - // Get a list of synonymous ids with the same type that can be used in the - // same OpPhi instruction. - auto equivalence_classes = GetIdEquivalenceClasses(); - - // Make a list of references, to avoid copying sets unnecessarily. - std::vector*> equivalence_class_pointers; - for (auto& set : equivalence_classes) { - equivalence_class_pointers.push_back(&set); - } - - // Keep a list of transformations to apply at the end. - std::vector transformations_to_apply; - - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // Randomly decide whether to consider this block. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingOpPhiSynonym())) { - continue; - } - - // The block must have at least one predecessor. - size_t num_preds = GetIRContext()->cfg()->preds(block.id()).size(); - if (num_preds == 0) { - continue; - } - - std::set* chosen_equivalence_class = nullptr; - - if (num_preds > 1) { - // If the block has more than one predecessor, prioritise sets with at - // least 2 ids available at some predecessor. - chosen_equivalence_class = MaybeFindSuitableEquivalenceClassRandomly( - equivalence_class_pointers, block.id(), 2); - } - - // If a set was not already chosen, choose one with at least one available - // id. - if (!chosen_equivalence_class) { - chosen_equivalence_class = MaybeFindSuitableEquivalenceClassRandomly( - equivalence_class_pointers, block.id(), 1); - } - - // If no suitable set was found, we cannot apply the transformation to - // this block. - if (!chosen_equivalence_class) { - continue; - } - - // Initialise the map from predecessor labels to ids. - std::map preds_to_ids; - - // Keep track of the ids used and of the id of a predecessor with at least - // two ids to choose from. This is to ensure that, if possible, at least - // two distinct ids will be used. - std::set ids_chosen; - uint32_t pred_with_alternatives = 0; - - // Choose an id for each predecessor. - for (uint32_t pred_id : GetIRContext()->cfg()->preds(block.id())) { - auto suitable_ids = GetSuitableIds(*chosen_equivalence_class, pred_id); - assert(!suitable_ids.empty() && - "We must be able to find at least one suitable id because the " - "equivalence class was chosen among suitable ones."); - - // If this predecessor has more than one id to choose from and it is the - // first one of this kind that we found, remember its id. - if (suitable_ids.size() > 1 && !pred_with_alternatives) { - pred_with_alternatives = pred_id; - } - - uint32_t chosen_id = - suitable_ids[GetFuzzerContext()->RandomIndex(suitable_ids)]; - - // Add this id to the set of ids chosen. - ids_chosen.emplace(chosen_id); - - // Add the pair (predecessor, chosen id) to the map. - preds_to_ids[pred_id] = chosen_id; - } - - // If: - // - the block has more than one predecessor - // - at least one predecessor has more than one alternative - // - the same id has been chosen by all the predecessors - // then choose another one for the predecessor with more than one - // alternative. - if (num_preds > 1 && pred_with_alternatives != 0 && - ids_chosen.size() == 1) { - auto suitable_ids = - GetSuitableIds(*chosen_equivalence_class, pred_with_alternatives); - uint32_t chosen_id = - GetFuzzerContext()->RemoveAtRandomIndex(&suitable_ids); - if (chosen_id == preds_to_ids[pred_with_alternatives]) { - chosen_id = GetFuzzerContext()->RemoveAtRandomIndex(&suitable_ids); - } - - preds_to_ids[pred_with_alternatives] = chosen_id; - } - - // Add the transformation to the list of transformations to apply. - transformations_to_apply.emplace_back(block.id(), preds_to_ids, - GetFuzzerContext()->GetFreshId()); - } - } - - // Apply the transformations. - for (const auto& transformation : transformations_to_apply) { - ApplyTransformation(transformation); - } -} - -std::vector> -FuzzerPassAddOpPhiSynonyms::GetIdEquivalenceClasses() { - std::vector> id_equivalence_classes; - - // Keep track of all the ids that have already be assigned to a class. - std::set already_in_a_class; - - for (const auto& pair : GetIRContext()->get_def_use_mgr()->id_to_defs()) { - // Exclude ids that have already been assigned to a class. - if (already_in_a_class.count(pair.first)) { - continue; - } - - // Exclude irrelevant ids. - if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant( - pair.first)) { - continue; - } - - // Exclude ids having a type that is not allowed by the transformation. - if (!TransformationAddOpPhiSynonym::CheckTypeIsAllowed( - GetIRContext(), pair.second->type_id())) { - continue; - } - - // We need a new equivalence class for this id. - std::set new_equivalence_class; - - // Add this id to the class. - new_equivalence_class.emplace(pair.first); - already_in_a_class.emplace(pair.first); - - // Add all the synonyms with the same type to this class. - for (auto synonym : - GetTransformationContext()->GetFactManager()->GetSynonymsForId( - pair.first)) { - // The synonym must be a plain id - it cannot be an indexed access into a - // composite. - if (synonym->index_size() > 0) { - continue; - } - - // The synonym must not be irrelevant. - if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant( - synonym->object())) { - continue; - } - - auto synonym_def = - GetIRContext()->get_def_use_mgr()->GetDef(synonym->object()); - // The synonym must exist and have the same type as the id we are - // considering. - if (!synonym_def || synonym_def->type_id() != pair.second->type_id()) { - continue; - } - - // We can add this synonym to the new equivalence class. - new_equivalence_class.emplace(synonym->object()); - already_in_a_class.emplace(synonym->object()); - } - - // Add the new equivalence class to the list of equivalence classes. - id_equivalence_classes.emplace_back(std::move(new_equivalence_class)); - } - - return id_equivalence_classes; -} - -bool FuzzerPassAddOpPhiSynonyms::EquivalenceClassIsSuitableForBlock( - const std::set& equivalence_class, uint32_t block_id, - uint32_t distinct_ids_required) { - bool at_least_one_id_for_each_pred = true; - - // Keep a set of the suitable ids found. - std::set suitable_ids_found; - - // Loop through all the predecessors of the block. - for (auto pred_id : GetIRContext()->cfg()->preds(block_id)) { - // Find the last instruction in the predecessor block. - auto last_instruction = - GetIRContext()->get_instr_block(pred_id)->terminator(); - - // Initially assume that there is not a suitable id for this predecessor. - bool at_least_one_suitable_id_found = false; - for (uint32_t id : equivalence_class) { - if (fuzzerutil::IdIsAvailableBeforeInstruction(GetIRContext(), - last_instruction, id)) { - // We have found a suitable id. - at_least_one_suitable_id_found = true; - suitable_ids_found.emplace(id); - - // If we have already found enough distinct suitable ids, we don't need - // to check the remaining ones for this predecessor. - if (suitable_ids_found.size() >= distinct_ids_required) { - break; - } - } - } - // If no suitable id was found for this predecessor, this equivalence class - // is not suitable and we don't need to check the other predecessors. - if (!at_least_one_suitable_id_found) { - at_least_one_id_for_each_pred = false; - break; - } - } - - // The equivalence class is suitable if at least one suitable id was found for - // each predecessor and we have found at least |distinct_ids_required| - // distinct suitable ids in general. - return at_least_one_id_for_each_pred && - suitable_ids_found.size() >= distinct_ids_required; -} - -std::vector FuzzerPassAddOpPhiSynonyms::GetSuitableIds( - const std::set& ids, uint32_t pred_id) { - // Initialise an empty vector of suitable ids. - std::vector suitable_ids; - - // Get the predecessor block. - auto predecessor = fuzzerutil::MaybeFindBlock(GetIRContext(), pred_id); - - // Loop through the ids to find the suitable ones. - for (uint32_t id : ids) { - if (fuzzerutil::IdIsAvailableBeforeInstruction( - GetIRContext(), predecessor->terminator(), id)) { - suitable_ids.push_back(id); - } - } - - return suitable_ids; -} - -std::set* -FuzzerPassAddOpPhiSynonyms::MaybeFindSuitableEquivalenceClassRandomly( - const std::vector*>& candidates, uint32_t block_id, - uint32_t distinct_ids_required) { - auto remaining_candidates = candidates; - while (!remaining_candidates.empty()) { - // Choose one set randomly and return it if it is suitable. - auto chosen = - GetFuzzerContext()->RemoveAtRandomIndex(&remaining_candidates); - if (EquivalenceClassIsSuitableForBlock(*chosen, block_id, - distinct_ids_required)) { - return chosen; - } - } - - // No suitable sets were found. - return nullptr; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.h deleted file mode 100644 index ed61c020b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_opphi_synonyms.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_OPPHI_SYNONYMS_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_OPPHI_SYNONYMS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass to add OpPhi instructions which can take the values of ids that -// have been marked as synonymous. This instruction will itself be marked as -// synonymous with the others. -class FuzzerPassAddOpPhiSynonyms : public FuzzerPass { - public: - FuzzerPassAddOpPhiSynonyms( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddOpPhiSynonyms() override; - - void Apply() override; - - // Computes the equivalence classes for the non-pointer and non-irrelevant ids - // in the module, where two ids are considered equivalent iff they have been - // declared synonymous and they have the same type. - std::vector> GetIdEquivalenceClasses(); - - // Returns true iff |equivalence_class| contains at least - // |distinct_ids_required| ids so that all of these ids are available at the - // end of at least one predecessor of the block with label |block_id|. - // Assumes that the block has at least one predecessor. - bool EquivalenceClassIsSuitableForBlock( - const std::set& equivalence_class, uint32_t block_id, - uint32_t distinct_ids_required); - - // Returns a vector with the ids that are available to use at the end of the - // block with id |pred_id|, selected among the given |ids|. Assumes that - // |pred_id| is the label of a block and all ids in |ids| exist in the module. - std::vector GetSuitableIds(const std::set& ids, - uint32_t pred_id); - - private: - // Randomly chooses one of the equivalence classes in |candidates|, so that it - // satisfies all of the following conditions: - // - For each of the predecessors of the |block_id| block, there is at least - // one id in the chosen equivalence class that is available at the end of - // it. - // - There are at least |distinct_ids_required| ids available at the end of - // some predecessor. - // Returns nullptr if no equivalence class in |candidates| satisfies the - // requirements. - std::set* MaybeFindSuitableEquivalenceClassRandomly( - const std::vector*>& candidates, uint32_t block_id, - uint32_t distinct_ids_required); -}; -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_OPPHI_SYNONYMS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.cpp deleted file mode 100644 index 3600a0f67..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_parameters.h" - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_add_parameter.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddParameters::FuzzerPassAddParameters( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddParameters::~FuzzerPassAddParameters() = default; - -void FuzzerPassAddParameters::Apply() { - // Compute type candidates for the new parameter. - std::vector type_candidates; - for (const auto& type_inst : GetIRContext()->module()->GetTypes()) { - const auto* type = - GetIRContext()->get_type_mgr()->GetType(type_inst->result_id()); - assert(type && "Type instruction is not registered in the type manager"); - if (TransformationAddParameter::IsParameterTypeSupported(*type)) { - type_candidates.push_back(type_inst->result_id()); - } - } - - if (type_candidates.empty()) { - // The module contains no suitable types to use in new parameters. - return; - } - - // Iterate over all functions in the module. - for (const auto& function : *GetIRContext()->module()) { - // Skip all entry-point functions - we don't want to change those. - if (fuzzerutil::FunctionIsEntryPoint(GetIRContext(), - function.result_id())) { - continue; - } - - if (GetNumberOfParameters(function) >= - GetFuzzerContext()->GetMaximumNumberOfFunctionParameters()) { - continue; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingParameters())) { - continue; - } - - auto num_new_parameters = - GetFuzzerContext()->GetRandomNumberOfNewParameters( - GetNumberOfParameters(function)); - - for (uint32_t i = 0; i < num_new_parameters; ++i) { - auto current_type_id = - type_candidates[GetFuzzerContext()->RandomIndex(type_candidates)]; - auto current_type = - GetIRContext()->get_type_mgr()->GetType(current_type_id); - std::map call_parameter_ids; - - // Consider the case when a pointer type was selected. - if (current_type->kind() == opt::analysis::Type::kPointer) { - auto storage_class = fuzzerutil::GetStorageClassFromPointerType( - GetIRContext(), current_type_id); - switch (storage_class) { - case SpvStorageClassFunction: { - // In every caller find or create a local variable that has the - // selected type. - for (auto* instr : - fuzzerutil::GetCallers(GetIRContext(), function.result_id())) { - auto block = GetIRContext()->get_instr_block(instr); - auto function_id = block->GetParent()->result_id(); - uint32_t variable_id = - FindOrCreateLocalVariable(current_type_id, function_id, true); - call_parameter_ids[instr->result_id()] = variable_id; - } - } break; - case SpvStorageClassPrivate: - case SpvStorageClassWorkgroup: { - // If there exists at least one caller, find or create a global - // variable that has the selected type. - std::vector callers = - fuzzerutil::GetCallers(GetIRContext(), function.result_id()); - if (!callers.empty()) { - uint32_t variable_id = - FindOrCreateGlobalVariable(current_type_id, true); - for (auto* instr : callers) { - call_parameter_ids[instr->result_id()] = variable_id; - } - } - } break; - default: - break; - } - } else { - // If there exists at least one caller, find or create a zero constant - // that has the selected type. - std::vector callers = - fuzzerutil::GetCallers(GetIRContext(), function.result_id()); - if (!callers.empty()) { - uint32_t constant_id = - FindOrCreateZeroConstant(current_type_id, true); - for (auto* instr : - fuzzerutil::GetCallers(GetIRContext(), function.result_id())) { - call_parameter_ids[instr->result_id()] = constant_id; - } - } - } - - ApplyTransformation(TransformationAddParameter( - function.result_id(), GetFuzzerContext()->GetFreshId(), - current_type_id, std::move(call_parameter_ids), - GetFuzzerContext()->GetFreshId())); - } - } -} - -uint32_t FuzzerPassAddParameters::GetNumberOfParameters( - const opt::Function& function) const { - const auto* type = GetIRContext()->get_type_mgr()->GetType( - function.DefInst().GetSingleWordInOperand(1)); - assert(type && type->AsFunction()); - - return static_cast(type->AsFunction()->param_types().size()); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.h deleted file mode 100644 index f1261ae51..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_parameters.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_PARAMETERS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_PARAMETERS_H_ - -#include - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Randomly decides for each non-entry-point function in the module whether to -// add new parameters to it. If so, randomly determines the number of parameters -// to add, their type and creates constants used to initialize them. -class FuzzerPassAddParameters : public FuzzerPass { - public: - FuzzerPassAddParameters(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddParameters() override; - - void Apply() override; - - private: - // Returns number of parameters of |function|. - uint32_t GetNumberOfParameters(const opt::Function& function) const; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_PARAMETERS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp deleted file mode 100644 index a2497df78..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_relaxed_decorations.h" - -#include "source/fuzz/transformation_add_relaxed_decoration.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddRelaxedDecorations::FuzzerPassAddRelaxedDecorations( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddRelaxedDecorations::~FuzzerPassAddRelaxedDecorations() = default; - -void FuzzerPassAddRelaxedDecorations::Apply() { - // Consider every instruction in every block in every function. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - for (auto& inst : block) { - // Randomly choose whether to apply the RelaxedPrecision decoration - // to this instruction. - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingRelaxedDecoration())) { - TransformationAddRelaxedDecoration transformation(inst.result_id()); - // Restrict attention to numeric instructions (returning 32-bit - // floats or ints according to SPIR-V documentation) in dead blocks. - if (transformation.IsApplicable(GetIRContext(), - *GetTransformationContext())) { - transformation.Apply(GetIRContext(), GetTransformationContext()); - *GetTransformations()->add_transformation() = - transformation.ToMessage(); - } - } - } - } - } -} -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.h deleted file mode 100644 index dad5dfc9a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_relaxed_decorations.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_FUZZER_PASS_ADD_RELAXED_DECORATIONS_H -#define SPIRV_TOOLS_FUZZER_PASS_ADD_RELAXED_DECORATIONS_H - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A pass that applies the Relaxed decoration to numeric instructions. -class FuzzerPassAddRelaxedDecorations : public FuzzerPass { - public: - FuzzerPassAddRelaxedDecorations( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddRelaxedDecorations() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_FUZZER_PASS_ADD_RELAXED_DECORATIONS_H diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp deleted file mode 100644 index 46efc6431..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_stores.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_store.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddStores::FuzzerPassAddStores( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddStores::~FuzzerPassAddStores() = default; - -void FuzzerPassAddStores::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - assert(inst_it->opcode() == - instruction_descriptor.target_instruction_opcode() && - "The opcode of the instruction we might insert before must be " - "the same as the opcode in the descriptor for the instruction"); - - // Check whether it is legitimate to insert a 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())) { - return; - } - - // Look for pointers we might consider storing to. - std::vector relevant_pointers = - FindAvailableInstructions( - function, block, inst_it, - [this, block](opt::IRContext* context, - opt::Instruction* instruction) -> bool { - if (!instruction->result_id() || !instruction->type_id()) { - return false; - } - auto type_inst = context->get_def_use_mgr()->GetDef( - instruction->type_id()); - if (type_inst->opcode() != SpvOpTypePointer) { - // Not a pointer. - return false; - } - if (instruction->IsReadOnlyPointer()) { - // Read only: cannot store to it. - return false; - } - switch (instruction->opcode()) { - case SpvOpConstantNull: - case SpvOpUndef: - // Do not allow storing to a null or undefined pointer; - // this might be OK if the block is dead, but for now we - // conservatively avoid it. - return false; - default: - break; - } - return GetTransformationContext() - ->GetFactManager() - ->BlockIsDead(block->id()) || - GetTransformationContext() - ->GetFactManager() - ->PointeeValueIsIrrelevant( - instruction->result_id()); - }); - - // At this point, |relevant_pointers| contains all the pointers we might - // think of storing to. - if (relevant_pointers.empty()) { - return; - } - - auto pointer = relevant_pointers[GetFuzzerContext()->RandomIndex( - relevant_pointers)]; - - std::vector relevant_values = - FindAvailableInstructions( - function, block, inst_it, - [pointer](opt::IRContext* context, - opt::Instruction* instruction) -> bool { - if (!instruction->result_id() || !instruction->type_id()) { - return false; - } - return instruction->type_id() == - context->get_def_use_mgr() - ->GetDef(pointer->type_id()) - ->GetSingleWordInOperand(1); - }); - - if (relevant_values.empty()) { - return; - } - - // Choose a value at random, and create and apply a storing - // transformation based on it and the pointer. - ApplyTransformation(TransformationStore( - pointer->result_id(), - relevant_values[GetFuzzerContext()->RandomIndex(relevant_values)] - ->result_id(), - instruction_descriptor)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.h deleted file mode 100644 index 55ec67f2b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_stores.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_STORES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_STORES_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that adds stores, at random, through pointers in the module, -// either (a) from dead blocks, or (b) through pointers whose pointee values -// are known not to affect the module's overall behaviour. -class FuzzerPassAddStores : public FuzzerPass { - public: - FuzzerPassAddStores(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddStores(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_STORES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.cpp deleted file mode 100644 index f1091740b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_synonyms.h" - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_add_synonym.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddSynonyms::FuzzerPassAddSynonyms( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddSynonyms::~FuzzerPassAddSynonyms() = default; - -void FuzzerPassAddSynonyms::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) { - // Skip |inst_it| if we can't insert anything above it. OpIAdd is just - // a representative of some instruction that might be produced by the - // transformation. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) { - return; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingSynonyms())) { - return; - } - - auto synonym_type = GetFuzzerContext()->GetRandomSynonymType(); - - // Select all instructions that can be used to create a synonym to. - auto available_instructions = FindAvailableInstructions( - function, block, inst_it, - [synonym_type, this](opt::IRContext* ir_context, - opt::Instruction* inst) { - // Check that we can create a synonym to |inst| as described by - // the |synonym_type| and insert it before |inst_it|. - return TransformationAddSynonym::IsInstructionValid( - ir_context, *GetTransformationContext(), inst, synonym_type); - }); - - if (available_instructions.empty()) { - return; - } - - const auto* existing_synonym = - available_instructions[GetFuzzerContext()->RandomIndex( - available_instructions)]; - - // Make sure the module contains all instructions required to apply the - // transformation. - switch (synonym_type) { - case protobufs::TransformationAddSynonym::ADD_ZERO: - case protobufs::TransformationAddSynonym::SUB_ZERO: - case protobufs::TransformationAddSynonym::LOGICAL_OR: - // Create a zero constant to be used as an operand of the synonymous - // instruction. - FindOrCreateZeroConstant(existing_synonym->type_id(), false); - break; - case protobufs::TransformationAddSynonym::MUL_ONE: - case protobufs::TransformationAddSynonym::LOGICAL_AND: { - const auto* existing_synonym_type = - GetIRContext()->get_type_mgr()->GetType( - existing_synonym->type_id()); - assert(existing_synonym_type && "Instruction has invalid type"); - - if (const auto* vector = existing_synonym_type->AsVector()) { - auto element_type_id = - GetIRContext()->get_type_mgr()->GetId(vector->element_type()); - assert(element_type_id && "Vector's element type is invalid"); - - auto one_word = vector->element_type()->AsFloat() - ? fuzzerutil::FloatToWord(1) - : 1u; - FindOrCreateCompositeConstant( - std::vector( - vector->element_count(), - FindOrCreateConstant({one_word}, element_type_id, false)), - existing_synonym->type_id(), false); - } else { - FindOrCreateConstant( - {existing_synonym_type->AsFloat() ? fuzzerutil::FloatToWord(1) - : 1u}, - existing_synonym->type_id(), false); - } - } break; - default: - // This assertion will fail if some SynonymType is missing from the - // switch statement. - assert( - !TransformationAddSynonym::IsAdditionalConstantRequired( - synonym_type) && - "|synonym_type| requires an additional constant to be present " - "in the module"); - break; - } - - ApplyTransformation(TransformationAddSynonym( - existing_synonym->result_id(), synonym_type, - GetFuzzerContext()->GetFreshId(), instruction_descriptor)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.h deleted file mode 100644 index dcfb93898..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_synonyms.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_SYNONYMS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_SYNONYMS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Sprinkles instructions through the module that produce ids, synonymous to -// some other instructions. -class FuzzerPassAddSynonyms : public FuzzerPass { - public: - FuzzerPassAddSynonyms(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddSynonyms() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_SYNONYMS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp deleted file mode 100644 index 453448ba2..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_vector_shuffle.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAddVectorShuffleInstructions::FuzzerPassAddVectorShuffleInstructions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAddVectorShuffleInstructions:: - ~FuzzerPassAddVectorShuffleInstructions() = default; - -void FuzzerPassAddVectorShuffleInstructions::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator instruction_iterator, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - assert(instruction_iterator->opcode() == - instruction_descriptor.target_instruction_opcode() && - "The opcode of the instruction we might insert before must be " - "the same as the opcode in the descriptor for the instruction"); - - // Randomly decide whether to try adding an OpVectorShuffle instruction. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAddingVectorShuffle())) { - return; - } - - // It must be valid to insert an OpVectorShuffle instruction - // before |instruction_iterator|. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpVectorShuffle, instruction_iterator)) { - return; - } - - // Looks for vectors that we might consider to use as OpVectorShuffle - // operands. - std::vector vector_instructions = - FindAvailableInstructions( - function, block, instruction_iterator, - [this, instruction_descriptor]( - opt::IRContext* ir_context, - opt::Instruction* instruction) -> bool { - if (!instruction->result_id() || !instruction->type_id()) { - return false; - } - - if (!ir_context->get_type_mgr() - ->GetType(instruction->type_id()) - ->AsVector()) { - return false; - } - - if (!GetTransformationContext() - ->GetFactManager() - ->IdIsIrrelevant(instruction->result_id()) && - !fuzzerutil::CanMakeSynonymOf(ir_context, - *GetTransformationContext(), - 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. - return false; - } - - return fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, - FindInstruction(instruction_descriptor, ir_context), - instruction->result_id()); - }); - - // If there are no vector instructions, then return. - if (vector_instructions.empty()) { - return; - } - - auto vector_1_instruction = - vector_instructions[GetFuzzerContext()->RandomIndex( - vector_instructions)]; - auto vector_1_type = GetIRContext() - ->get_type_mgr() - ->GetType(vector_1_instruction->type_id()) - ->AsVector(); - - auto vector_2_instruction = - GetFuzzerContext()->RemoveAtRandomIndex(&vector_instructions); - auto vector_2_type = GetIRContext() - ->get_type_mgr() - ->GetType(vector_2_instruction->type_id()) - ->AsVector(); - - // |vector_1| and |vector_2| must have the same element type as each - // other. The loop is guaranteed to terminate because each iteration - // removes on possible choice for |vector_2|, and there is at least one - // choice that will cause the loop to exit - namely |vector_1|. - while (vector_1_type->element_type() != vector_2_type->element_type()) { - vector_2_instruction = - GetFuzzerContext()->RemoveAtRandomIndex(&vector_instructions); - vector_2_type = GetIRContext() - ->get_type_mgr() - ->GetType(vector_2_instruction->type_id()) - ->AsVector(); - } - - // Gets components and creates the appropriate result vector type. - std::vector components = - GetFuzzerContext()->GetRandomComponentsForVectorShuffle( - vector_1_type->element_count() + - vector_2_type->element_count()); - FindOrCreateVectorType(GetIRContext()->get_type_mgr()->GetId( - vector_1_type->element_type()), - static_cast(components.size())); - - // Applies the vector shuffle transformation. - ApplyTransformation(TransformationVectorShuffle( - instruction_descriptor, GetFuzzerContext()->GetFreshId(), - vector_1_instruction->result_id(), - vector_2_instruction->result_id(), components)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h deleted file mode 100644 index 99b9f244c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_VECTOR_SHUFFLE_INSTRUCTIONS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADD_VECTOR_SHUFFLE_INSTRUCTIONS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Adds OpVectorShuffle instructions to the module. -class FuzzerPassAddVectorShuffleInstructions : public FuzzerPass { - public: - FuzzerPassAddVectorShuffleInstructions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAddVectorShuffleInstructions(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_VECTOR_SHUFFLE_INSTRUCTIONS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp deleted file mode 100644 index 1d6d4347f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_adjust_branch_weights.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_adjust_branch_weights.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAdjustBranchWeights::FuzzerPassAdjustBranchWeights( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAdjustBranchWeights::~FuzzerPassAdjustBranchWeights() = default; - -void FuzzerPassAdjustBranchWeights::Apply() { - // For all OpBranchConditional instructions, - // randomly applies the transformation. - GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { - if (instruction->opcode() == SpvOpBranchConditional && - GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAdjustingBranchWeights())) { - ApplyTransformation(TransformationAdjustBranchWeights( - MakeInstructionDescriptor(GetIRContext(), instruction), - GetFuzzerContext()->GetRandomBranchWeights())); - } - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.h deleted file mode 100644 index 5b2b33f1c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_branch_weights.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_BRANCH_WEIGHTS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_BRANCH_WEIGHTS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// This fuzzer pass searches for branch conditional instructions -// and randomly chooses which of these instructions will have their weights -// adjusted. -class FuzzerPassAdjustBranchWeights : public FuzzerPass { - public: - FuzzerPassAdjustBranchWeights( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAdjustBranchWeights(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_BRANCH_WEIGHTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp deleted file mode 100644 index aa62d2f89..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_adjust_function_controls.h" - -#include "source/fuzz/transformation_set_function_control.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAdjustFunctionControls::~FuzzerPassAdjustFunctionControls() = default; - -void FuzzerPassAdjustFunctionControls::Apply() { - // Consider every function in the module. - for (auto& function : *GetIRContext()->module()) { - // Randomly decide whether to adjust this function's controls. - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAdjustingFunctionControl())) { - // Grab the function control mask for the function in its present form. - uint32_t existing_function_control_mask = - function.DefInst().GetSingleWordInOperand(0); - - // For the new mask, we first randomly select one of three basic masks: - // None, Inline or DontInline. These are always valid (and are mutually - // exclusive). - std::vector basic_function_control_masks = { - SpvFunctionControlMaskNone, SpvFunctionControlInlineMask, - SpvFunctionControlDontInlineMask}; - uint32_t new_function_control_mask = - basic_function_control_masks[GetFuzzerContext()->RandomIndex( - basic_function_control_masks)]; - - // We now consider the Pure and Const mask bits. If these are already - // set on the function then it's OK to keep them, but also interesting - // to consider dropping them, so we decide randomly in each case. - for (auto mask_bit : - {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) { - if ((existing_function_control_mask & mask_bit) && - GetFuzzerContext()->ChooseEven()) { - new_function_control_mask |= mask_bit; - } - } - - // Create and add a transformation. - TransformationSetFunctionControl transformation( - function.DefInst().result_id(), new_function_control_mask); - ApplyTransformation(transformation); - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h deleted file mode 100644 index e20541b19..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_ -#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A pass that adjusts the function controls on OpFunction instructions. -class FuzzerPassAdjustFunctionControls : public FuzzerPass { - public: - FuzzerPassAdjustFunctionControls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAdjustFunctionControls() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp deleted file mode 100644 index f7addffe1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h" - -#include "source/fuzz/transformation_set_loop_control.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAdjustLoopControls::~FuzzerPassAdjustLoopControls() = default; - -void FuzzerPassAdjustLoopControls::Apply() { - // Consider every merge instruction in the module (via looking through all - // functions and blocks). - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - if (auto merge_inst = block.GetMergeInst()) { - // Ignore the instruction if it is not a loop merge. - if (merge_inst->opcode() != SpvOpLoopMerge) { - continue; - } - - // Decide randomly whether to adjust this loop merge. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAdjustingLoopControl())) { - continue; - } - - uint32_t existing_mask = merge_inst->GetSingleWordOperand( - TransformationSetLoopControl::kLoopControlMaskInOperandIndex); - - // First, set the new mask to one of None, Unroll or DontUnroll. - std::vector basic_masks = {SpvLoopControlMaskNone, - SpvLoopControlUnrollMask, - SpvLoopControlDontUnrollMask}; - uint32_t new_mask = - basic_masks[GetFuzzerContext()->RandomIndex(basic_masks)]; - - // For the loop controls that depend on guarantees about what the loop - // does, check which of these were present in the existing mask and - // randomly decide whether to keep them. They are just hints, so - // removing them should not change the semantics of the module. - for (auto mask_bit : - {SpvLoopControlDependencyInfiniteMask, - SpvLoopControlDependencyLengthMask, - SpvLoopControlMinIterationsMask, SpvLoopControlMaxIterationsMask, - SpvLoopControlIterationMultipleMask}) { - if ((existing_mask & mask_bit) && GetFuzzerContext()->ChooseEven()) { - // The mask bits we are considering are not available in all SPIR-V - // versions. However, we only include a mask bit if it was present - // in the original loop control mask, and we work under the - // assumption that we are transforming a valid module, thus we don't - // need to actually check whether the SPIR-V version being used - // supports these loop control mask bits. - new_mask |= mask_bit; - } - } - - // We use 0 for peel count and partial count in the case that we choose - // not to set these controls. - uint32_t peel_count = 0; - uint32_t partial_count = 0; - - // PeelCount and PartialCount are not compatible with DontUnroll, so - // we check whether DontUnroll is set. - if (!(new_mask & SpvLoopControlDontUnrollMask)) { - // If PeelCount is supported by this SPIR-V version, randomly choose - // whether to set it. If it was set in the original mask and is not - // selected for setting here, that amounts to dropping it. - if (TransformationSetLoopControl::PeelCountIsSupported( - GetIRContext()) && - GetFuzzerContext()->ChooseEven()) { - new_mask |= SpvLoopControlPeelCountMask; - // The peel count is chosen randomly - if PeelCount was already set - // this will overwrite whatever peel count was previously used. - peel_count = GetFuzzerContext()->GetRandomLoopControlPeelCount(); - } - // Similar, but for PartialCount. - if (TransformationSetLoopControl::PartialCountIsSupported( - GetIRContext()) && - GetFuzzerContext()->ChooseEven()) { - new_mask |= SpvLoopControlPartialCountMask; - partial_count = - GetFuzzerContext()->GetRandomLoopControlPartialCount(); - } - } - - // Apply the transformation and add it to the output transformation - // sequence. - TransformationSetLoopControl transformation(block.id(), new_mask, - peel_count, partial_count); - ApplyTransformation(transformation); - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h deleted file mode 100644 index ee5cd4830..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_ -#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A pass that adjusts the loop controls on OpLoopMerge instructions. -class FuzzerPassAdjustLoopControls : public FuzzerPass { - public: - FuzzerPassAdjustLoopControls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAdjustLoopControls() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp deleted file mode 100644 index 68f0ca7e4..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h" - -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_set_memory_operands_mask.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAdjustMemoryOperandsMasks::~FuzzerPassAdjustMemoryOperandsMasks() = - default; - -void FuzzerPassAdjustMemoryOperandsMasks::Apply() { - // Consider every block in every function. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // Consider every instruction in this block, using an explicit iterator so - // that when we find an instruction of interest we can search backwards to - // create an id descriptor for it. - for (auto inst_it = block.cbegin(); inst_it != block.cend(); ++inst_it) { - if (!TransformationSetMemoryOperandsMask::IsMemoryAccess(*inst_it)) { - // We are only interested in memory access instructions. - continue; - } - - std::vector indices_of_available_masks_to_adjust; - // All memory instructions have at least one memory operands mask. - indices_of_available_masks_to_adjust.push_back(0); - // From SPIR-V 1.4 onwards, OpCopyMemory and OpCopyMemorySized have a - // second mask. - switch (inst_it->opcode()) { - case SpvOpCopyMemory: - case SpvOpCopyMemorySized: - if (TransformationSetMemoryOperandsMask:: - MultipleMemoryOperandMasksAreSupported(GetIRContext())) { - indices_of_available_masks_to_adjust.push_back(1); - } - break; - default: - break; - } - - // Consider the available masks - for (auto mask_index : indices_of_available_masks_to_adjust) { - // Randomly decide whether to adjust this mask. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfAdjustingMemoryOperandsMask())) { - continue; - } - // Get the existing mask, using None if there was no mask present at - // all. - auto existing_mask_in_operand_index = - TransformationSetMemoryOperandsMask::GetInOperandIndexForMask( - *inst_it, mask_index); - auto existing_mask = - existing_mask_in_operand_index < inst_it->NumInOperands() - ? inst_it->GetSingleWordInOperand( - existing_mask_in_operand_index) - : static_cast(SpvMemoryAccessMaskNone); - - // There are two things we can do to a mask: - // - add Volatile if not already present - // - toggle Nontemporal - // The following ensures that we do at least one of these - bool add_volatile = !(existing_mask & SpvMemoryAccessVolatileMask) && - GetFuzzerContext()->ChooseEven(); - bool toggle_nontemporal = - !add_volatile || GetFuzzerContext()->ChooseEven(); - - // These bitwise operations use '|' to add Volatile if desired, and - // '^' to toggle Nontemporal if desired. - uint32_t new_mask = - (existing_mask | (add_volatile ? SpvMemoryAccessVolatileMask - : SpvMemoryAccessMaskNone)) ^ - (toggle_nontemporal ? SpvMemoryAccessNontemporalMask - : SpvMemoryAccessMaskNone); - - TransformationSetMemoryOperandsMask transformation( - MakeInstructionDescriptor(block, inst_it), new_mask, mask_index); - ApplyTransformation(transformation); - } - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h deleted file mode 100644 index 699dcb5a1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass to adjust the memory operand masks in memory access -// instructions. -class FuzzerPassAdjustMemoryOperandsMasks : public FuzzerPass { - public: - FuzzerPassAdjustMemoryOperandsMasks( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAdjustMemoryOperandsMasks(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp deleted file mode 100644 index 83b1854e1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h" - -#include "source/fuzz/transformation_set_selection_control.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassAdjustSelectionControls::~FuzzerPassAdjustSelectionControls() = - default; - -void FuzzerPassAdjustSelectionControls::Apply() { - // Consider every merge instruction in the module (via looking through all - // functions and blocks). - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - if (auto merge_inst = block.GetMergeInst()) { - // Ignore the instruction if it is not a selection merge. - if (merge_inst->opcode() != SpvOpSelectionMerge) { - continue; - } - - // Choose randomly whether to change the selection control for this - // instruction. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfAdjustingSelectionControl())) { - continue; - } - - // The choices to change the selection control to are the set of valid - // controls, minus the current control. - std::vector choices; - for (auto control : - {SpvSelectionControlMaskNone, SpvSelectionControlFlattenMask, - SpvSelectionControlDontFlattenMask}) { - if (control == merge_inst->GetSingleWordOperand(1)) { - continue; - } - choices.push_back(control); - } - - // Apply the transformation and add it to the output transformation - // sequence. - TransformationSetSelectionControl transformation( - block.id(), choices[GetFuzzerContext()->RandomIndex(choices)]); - ApplyTransformation(transformation); - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h deleted file mode 100644 index 820b30d43..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_ -#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A pass that adjusts the selection controls on OpSelectionMerge instructions. -class FuzzerPassAdjustSelectionControls : public FuzzerPass { - public: - FuzzerPassAdjustSelectionControls( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassAdjustSelectionControls() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp deleted file mode 100644 index bb676e896..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h" - -#include "source/fuzz/data_descriptor.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/id_use_descriptor.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_composite_extract.h" -#include "source/fuzz/transformation_compute_data_synonym_fact_closure.h" -#include "source/fuzz/transformation_replace_id_with_synonym.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassApplyIdSynonyms::~FuzzerPassApplyIdSynonyms() = default; - -void FuzzerPassApplyIdSynonyms::Apply() { - // Compute a closure of data synonym facts, to enrich the pool of synonyms - // that are available. - ApplyTransformation(TransformationComputeDataSynonymFactClosure( - GetFuzzerContext() - ->GetMaximumEquivalenceClassSizeForDataSynonymFactClosure())); - - for (auto id_with_known_synonyms : GetTransformationContext() - ->GetFactManager() - ->GetIdsForWhichSynonymsAreKnown()) { - // Gather up all uses of |id_with_known_synonym| as a regular id, and - // subsequently iterate over these uses. We use this separation because, - // when considering a given use, we might apply a transformation that will - // invalidate the def-use manager. - std::vector> uses; - GetIRContext()->get_def_use_mgr()->ForEachUse( - id_with_known_synonyms, - [&uses](opt::Instruction* use_inst, uint32_t use_index) -> void { - // We only gather up regular id uses; e.g. we do not include a use of - // the id as the scope for an atomic operation. - if (use_inst->GetOperand(use_index).type == SPV_OPERAND_TYPE_ID) { - uses.emplace_back( - std::pair(use_inst, use_index)); - } - }); - - for (const auto& use : uses) { - auto use_inst = use.first; - auto use_index = use.second; - auto block_containing_use = GetIRContext()->get_instr_block(use_inst); - // The use might not be in a block; e.g. it could be a decoration. - if (!block_containing_use) { - continue; - } - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfReplacingIdWithSynonym())) { - continue; - } - // |use_index| is the absolute index of the operand. We require - // the index of the operand restricted to input operands only. - uint32_t use_in_operand_index = - fuzzerutil::InOperandIndexFromOperandIndex(*use_inst, use_index); - if (!TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym( - GetIRContext(), use_inst, use_in_operand_index)) { - continue; - } - - std::vector synonyms_to_try; - for (const auto* data_descriptor : - GetTransformationContext()->GetFactManager()->GetSynonymsForId( - id_with_known_synonyms)) { - protobufs::DataDescriptor descriptor_for_this_id = - MakeDataDescriptor(id_with_known_synonyms, {}); - if (DataDescriptorEquals()(data_descriptor, &descriptor_for_this_id)) { - // Exclude the fact that the id is synonymous with itself. - continue; - } - - if (DataDescriptorsHaveCompatibleTypes( - use_inst->opcode(), use_in_operand_index, - descriptor_for_this_id, *data_descriptor)) { - synonyms_to_try.push_back(data_descriptor); - } - } - while (!synonyms_to_try.empty()) { - auto synonym_to_try = - GetFuzzerContext()->RemoveAtRandomIndex(&synonyms_to_try); - - // If the synonym's |index_size| is zero, the synonym represents an id. - // Otherwise it represents some element of a composite structure, in - // which case we need to be able to add an extract instruction to get - // that element out. - if (synonym_to_try->index_size() > 0 && - !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract, - use_inst) && - use_inst->opcode() != SpvOpPhi) { - // We cannot insert an extract before this instruction, so this - // synonym is no good. - continue; - } - - if (!fuzzerutil::IdIsAvailableAtUse(GetIRContext(), use_inst, - use_in_operand_index, - synonym_to_try->object())) { - continue; - } - - // We either replace the use with an id known to be synonymous (when - // the synonym's |index_size| is 0), or an id that will hold the result - // of extracting a synonym from a composite (when the synonym's - // |index_size| is > 0). - uint32_t id_with_which_to_replace_use; - if (synonym_to_try->index_size() == 0) { - id_with_which_to_replace_use = synonym_to_try->object(); - } else { - id_with_which_to_replace_use = GetFuzzerContext()->GetFreshId(); - opt::Instruction* instruction_to_insert_before = nullptr; - - if (use_inst->opcode() != SpvOpPhi) { - instruction_to_insert_before = use_inst; - } else { - auto parent_block_id = - use_inst->GetSingleWordInOperand(use_in_operand_index + 1); - auto parent_block_instruction = - GetIRContext()->get_def_use_mgr()->GetDef(parent_block_id); - auto parent_block = - GetIRContext()->get_instr_block(parent_block_instruction); - - instruction_to_insert_before = parent_block->GetMergeInst() - ? parent_block->GetMergeInst() - : parent_block->terminator(); - } - - assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant( - synonym_to_try->object()) && - "Irrelevant ids can't participate in DataSynonym facts"); - ApplyTransformation(TransformationCompositeExtract( - MakeInstructionDescriptor(GetIRContext(), - instruction_to_insert_before), - id_with_which_to_replace_use, synonym_to_try->object(), - fuzzerutil::RepeatedFieldToVector(synonym_to_try->index()))); - } - - ApplyTransformation(TransformationReplaceIdWithSynonym( - MakeIdUseDescriptorFromUse(GetIRContext(), use_inst, - use_in_operand_index), - id_with_which_to_replace_use)); - break; - } - } - } -} - -bool FuzzerPassApplyIdSynonyms::DataDescriptorsHaveCompatibleTypes( - SpvOp opcode, uint32_t use_in_operand_index, - const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2) { - auto base_object_type_id_1 = - fuzzerutil::GetTypeId(GetIRContext(), dd1.object()); - auto base_object_type_id_2 = - fuzzerutil::GetTypeId(GetIRContext(), dd2.object()); - assert(base_object_type_id_1 && base_object_type_id_2 && - "Data descriptors are invalid"); - - auto type_id_1 = fuzzerutil::WalkCompositeTypeIndices( - GetIRContext(), base_object_type_id_1, dd1.index()); - auto type_id_2 = fuzzerutil::WalkCompositeTypeIndices( - GetIRContext(), base_object_type_id_2, dd2.index()); - assert(type_id_1 && type_id_2 && "Data descriptors have invalid types"); - - return TransformationReplaceIdWithSynonym::TypesAreCompatible( - GetIRContext(), opcode, use_in_operand_index, type_id_1, type_id_2); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h deleted file mode 100644 index 2feb65c20..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_ -#define SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_ - -#include "source/fuzz/fuzzer_pass.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// A pass that replaces ids with other ids, or accesses into structures, that -// are known to hold the same values. -class FuzzerPassApplyIdSynonyms : public FuzzerPass { - public: - FuzzerPassApplyIdSynonyms(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassApplyIdSynonyms() override; - - void Apply() override; - - private: - // Returns true if uses of |dd1| can be replaced with |dd2| and vice-versa - // with respect to the type. Concretely, returns true if |dd1| and |dd2| have - // the same type or both |dd1| and |dd2| are either a numerical or a vector - // type of integral components with possibly different signedness. - bool DataDescriptorsHaveCompatibleTypes(SpvOp opcode, - uint32_t use_in_operand_index, - const protobufs::DataDescriptor& dd1, - const protobufs::DataDescriptor& dd2); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp deleted file mode 100644 index 6443e896f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_construct_composites.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_composite_construct.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassConstructComposites::FuzzerPassConstructComposites( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassConstructComposites::~FuzzerPassConstructComposites() = default; - -void FuzzerPassConstructComposites::Apply() { - // Gather up the ids of all composite types. - std::vector composite_type_ids; - for (auto& inst : GetIRContext()->types_values()) { - if (fuzzerutil::IsCompositeType( - GetIRContext()->get_type_mgr()->GetType(inst.result_id()))) { - composite_type_ids.push_back(inst.result_id()); - } - } - - ForEachInstructionWithInstructionDescriptor( - [this, &composite_type_ids]( - opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - // Check whether it is legitimate to insert a composite construction - // before the instruction. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpCompositeConstruct, inst_it)) { - return; - } - - // Randomly decide whether to try inserting an object copy here. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfConstructingComposite())) { - return; - } - - // For each instruction that is available at this program point (i.e. an - // instruction that is global or whose definition strictly dominates the - // program point) and suitable for making a synonym of, associate it - // with the id of its result type. - TypeIdToInstructions type_id_to_available_instructions; - auto available_instructions = FindAvailableInstructions( - function, block, inst_it, - [this](opt::IRContext* ir_context, opt::Instruction* inst) { - if (!inst->result_id() || !inst->type_id()) { - return false; - } - - // 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. - return GetTransformationContext() - ->GetFactManager() - ->IdIsIrrelevant(inst->result_id()) || - fuzzerutil::CanMakeSynonymOf( - ir_context, *GetTransformationContext(), inst); - }); - for (auto instruction : available_instructions) { - RecordAvailableInstruction(instruction, - &type_id_to_available_instructions); - } - - // At this point, |composite_type_ids| captures all the composite types - // we could try to create, while |type_id_to_available_instructions| - // captures all the available result ids we might use, organized by - // type. - - // Now we try to find a composite that we can construct. We might not - // manage, if there is a paucity of available ingredients in the module - // (e.g. if our only available composite was a boolean vector and we had - // no instructions generating boolean result types available). - // - // If we succeed, |chosen_composite_type| will end up being non-zero, - // and |constructor_arguments| will end up giving us result ids suitable - // for constructing a composite of that type. Otherwise these variables - // will remain 0 and null respectively. - uint32_t chosen_composite_type = 0; - std::vector constructor_arguments; - - // Initially, all composite type ids are available for us to try. Keep - // trying until we run out of options. - auto composites_to_try_constructing = composite_type_ids; - while (!composites_to_try_constructing.empty()) { - // Remove a composite type from the composite types left for us to - // try. - auto next_composite_to_try_constructing = - GetFuzzerContext()->RemoveAtRandomIndex( - &composites_to_try_constructing); - - // Now try to construct a composite of this type, using an appropriate - // helper method depending on the kind of composite type. - auto composite_type_inst = GetIRContext()->get_def_use_mgr()->GetDef( - next_composite_to_try_constructing); - switch (composite_type_inst->opcode()) { - case SpvOpTypeArray: - constructor_arguments = FindComponentsToConstructArray( - *composite_type_inst, type_id_to_available_instructions); - break; - case SpvOpTypeMatrix: - constructor_arguments = FindComponentsToConstructMatrix( - *composite_type_inst, type_id_to_available_instructions); - break; - case SpvOpTypeStruct: - constructor_arguments = FindComponentsToConstructStruct( - *composite_type_inst, type_id_to_available_instructions); - break; - case SpvOpTypeVector: - constructor_arguments = FindComponentsToConstructVector( - *composite_type_inst, type_id_to_available_instructions); - break; - default: - assert(false && - "The space of possible composite types should be covered " - "by the above cases."); - break; - } - if (!constructor_arguments.empty()) { - // We succeeded! Note the composite type we finally settled on, and - // exit from the loop. - chosen_composite_type = next_composite_to_try_constructing; - break; - } - } - - if (!chosen_composite_type) { - // We did not manage to make a composite; return 0 to indicate that no - // instructions were added. - assert(constructor_arguments.empty()); - return; - } - assert(!constructor_arguments.empty()); - - // Make and apply a transformation. - ApplyTransformation(TransformationCompositeConstruct( - chosen_composite_type, constructor_arguments, - instruction_descriptor, GetFuzzerContext()->GetFreshId())); - }); -} - -void FuzzerPassConstructComposites::RecordAvailableInstruction( - opt::Instruction* inst, - TypeIdToInstructions* type_id_to_available_instructions) { - if (type_id_to_available_instructions->count(inst->type_id()) == 0) { - (*type_id_to_available_instructions)[inst->type_id()] = {}; - } - type_id_to_available_instructions->at(inst->type_id()).push_back(inst); -} - -std::vector -FuzzerPassConstructComposites::FindComponentsToConstructArray( - const opt::Instruction& array_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions) { - assert(array_type_instruction.opcode() == SpvOpTypeArray && - "Precondition: instruction must be an array type."); - - // Get the element type for the array. - auto element_type_id = array_type_instruction.GetSingleWordInOperand(0); - - // Get all instructions at our disposal that compute something of this element - // type. - auto available_instructions = - type_id_to_available_instructions.find(element_type_id); - - if (available_instructions == type_id_to_available_instructions.cend()) { - // If there are not any instructions available that compute the element type - // of the array then we are not in a position to construct a composite with - // this array type. - return {}; - } - - uint32_t array_length = - GetIRContext() - ->get_def_use_mgr() - ->GetDef(array_type_instruction.GetSingleWordInOperand(1)) - ->GetSingleWordInOperand(0); - - std::vector result; - for (uint32_t index = 0; index < array_length; index++) { - result.push_back(available_instructions - ->second[GetFuzzerContext()->RandomIndex( - available_instructions->second)] - ->result_id()); - } - return result; -} - -std::vector -FuzzerPassConstructComposites::FindComponentsToConstructMatrix( - const opt::Instruction& matrix_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions) { - assert(matrix_type_instruction.opcode() == SpvOpTypeMatrix && - "Precondition: instruction must be a matrix type."); - - // Get the element type for the matrix. - auto element_type_id = matrix_type_instruction.GetSingleWordInOperand(0); - - // Get all instructions at our disposal that compute something of this element - // type. - auto available_instructions = - type_id_to_available_instructions.find(element_type_id); - - if (available_instructions == type_id_to_available_instructions.cend()) { - // If there are not any instructions available that compute the element type - // of the matrix then we are not in a position to construct a composite with - // this matrix type. - return {}; - } - std::vector result; - for (uint32_t index = 0; - index < matrix_type_instruction.GetSingleWordInOperand(1); index++) { - result.push_back(available_instructions - ->second[GetFuzzerContext()->RandomIndex( - available_instructions->second)] - ->result_id()); - } - return result; -} - -std::vector -FuzzerPassConstructComposites::FindComponentsToConstructStruct( - const opt::Instruction& struct_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions) { - assert(struct_type_instruction.opcode() == SpvOpTypeStruct && - "Precondition: instruction must be a struct type."); - std::vector result; - // Consider the type of each field of the struct. - for (uint32_t in_operand_index = 0; - in_operand_index < struct_type_instruction.NumInOperands(); - in_operand_index++) { - auto element_type_id = - struct_type_instruction.GetSingleWordInOperand(in_operand_index); - // Find the instructions at our disposal that compute something of the field - // type. - auto available_instructions = - type_id_to_available_instructions.find(element_type_id); - if (available_instructions == type_id_to_available_instructions.cend()) { - // If there are no such instructions, we cannot construct a composite of - // this struct type. - return {}; - } - result.push_back(available_instructions - ->second[GetFuzzerContext()->RandomIndex( - available_instructions->second)] - ->result_id()); - } - return result; -} - -std::vector -FuzzerPassConstructComposites::FindComponentsToConstructVector( - const opt::Instruction& vector_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions) { - assert(vector_type_instruction.opcode() == SpvOpTypeVector && - "Precondition: instruction must be a vector type."); - - // Get details of the type underlying the vector, and the width of the vector, - // for convenience. - auto element_type_id = vector_type_instruction.GetSingleWordInOperand(0); - auto element_type = GetIRContext()->get_type_mgr()->GetType(element_type_id); - auto element_count = vector_type_instruction.GetSingleWordInOperand(1); - - // Collect a mapping, from type id to width, for scalar/vector types that are - // smaller in width than |vector_type|, but that have the same underlying - // type. For example, if |vector_type| is vec4, the mapping will be: - // { float -> 1, vec2 -> 2, vec3 -> 3 } - // The mapping will have missing entries if some of these types do not exist. - - std::map smaller_vector_type_id_to_width; - // Add the underlying type. This id must exist, in order for |vector_type| to - // exist. - smaller_vector_type_id_to_width[element_type_id] = 1; - - // Now add every vector type with width at least 2, and less than the width of - // |vector_type|. - for (uint32_t width = 2; width < element_count; width++) { - opt::analysis::Vector smaller_vector_type(element_type, width); - auto smaller_vector_type_id = - GetIRContext()->get_type_mgr()->GetId(&smaller_vector_type); - // We might find that there is no declared type of this smaller width. - // For example, a module can declare vec4 without having declared vec2 or - // vec3. - if (smaller_vector_type_id) { - smaller_vector_type_id_to_width[smaller_vector_type_id] = width; - } - } - - // Now we know the types that are available to us, we set about populating a - // vector of the right length. We do this by deciding, with no order in mind, - // which instructions we will use to populate the vector, and subsequently - // randomly choosing an order. This is to avoid biasing construction of - // vectors with smaller vectors to the left and scalars to the right. That is - // a concern because, e.g. in the case of populating a vec4, if we populate - // the constructor instructions left-to-right, we can always choose a vec3 to - // construct the first three elements, but can only choose a vec3 to construct - // the last three elements if we chose a float to construct the first element - // (otherwise there will not be space left for a vec3). - - uint32_t vector_slots_used = 0; - // The instructions we will use to construct the vector, in no particular - // order at this stage. - std::vector instructions_to_use; - - while (vector_slots_used < element_count) { - std::vector instructions_to_choose_from; - for (auto& entry : smaller_vector_type_id_to_width) { - if (entry.second > - std::min(element_count - 1, element_count - vector_slots_used)) { - continue; - } - auto available_instructions = - type_id_to_available_instructions.find(entry.first); - if (available_instructions == type_id_to_available_instructions.cend()) { - continue; - } - instructions_to_choose_from.insert(instructions_to_choose_from.end(), - available_instructions->second.begin(), - available_instructions->second.end()); - } - if (instructions_to_choose_from.empty()) { - // We may get unlucky and find that there are not any instructions to - // choose from. In this case we give up constructing a composite of this - // vector type. It might be that we could construct the composite in - // another manner, so we could opt to retry a few times here, but it is - // simpler to just give up on the basis that this will not happen - // frequently. - return {}; - } - auto instruction_to_use = - instructions_to_choose_from[GetFuzzerContext()->RandomIndex( - instructions_to_choose_from)]; - instructions_to_use.push_back(instruction_to_use); - auto chosen_type = - GetIRContext()->get_type_mgr()->GetType(instruction_to_use->type_id()); - if (chosen_type->AsVector()) { - assert(chosen_type->AsVector()->element_type() == element_type); - assert(chosen_type->AsVector()->element_count() < element_count); - assert(chosen_type->AsVector()->element_count() <= - element_count - vector_slots_used); - vector_slots_used += chosen_type->AsVector()->element_count(); - } else { - assert(chosen_type == element_type); - vector_slots_used += 1; - } - } - assert(vector_slots_used == element_count); - - std::vector result; - std::vector operands; - while (!instructions_to_use.empty()) { - auto index = GetFuzzerContext()->RandomIndex(instructions_to_use); - result.push_back(instructions_to_use[index]->result_id()); - instructions_to_use.erase(instructions_to_use.begin() + index); - } - assert(result.size() > 1); - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h deleted file mode 100644 index 9853fadf0..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ - -#include "source/fuzz/fuzzer_pass.h" - -#include -#include - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for constructing composite objects from smaller objects. -class FuzzerPassConstructComposites : public FuzzerPass { - public: - FuzzerPassConstructComposites( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassConstructComposites(); - - void Apply() override; - - private: - // Used to map a type id to relevant instructions whose result type matches - // the type id. - typedef std::map> - TypeIdToInstructions; - - // Considers all instructions that are available at |inst| - instructions - // whose results could be packed into a composite - and updates - // |type_id_to_available_instructions| so that each such instruction is - // associated with its the id of its result type. - void RecordAvailableInstruction( - opt::Instruction* inst, - TypeIdToInstructions* type_id_to_available_instructions); - - // Requires that |array_type_instruction| has opcode OpTypeArray. - // Attempts to find suitable instruction result ids from the values of - // |type_id_to_available_instructions| that would allow a composite of type - // |array_type_instruction| to be constructed. Returns said ids if they can - // be found and an empty vector otherwise. - std::vector FindComponentsToConstructArray( - const opt::Instruction& array_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions); - - // Similar to FindComponentsToConstructArray, but for matrices. - std::vector FindComponentsToConstructMatrix( - const opt::Instruction& matrix_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions); - - // Similar to FindComponentsToConstructArray, but for structs. - std::vector FindComponentsToConstructStruct( - const opt::Instruction& struct_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions); - - // Similar to FindComponentsToConstructArray, but for vectors. - std::vector FindComponentsToConstructVector( - const opt::Instruction& vector_type_instruction, - const TypeIdToInstructions& type_id_to_available_instructions); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp deleted file mode 100644 index 4cc4044fe..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_copy_objects.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/transformation_add_synonym.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassCopyObjects::FuzzerPassCopyObjects( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default; - -void FuzzerPassCopyObjects::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - assert(inst_it->opcode() == - instruction_descriptor.target_instruction_opcode() && - "The opcode of the instruction we might insert before must be " - "the same as the opcode in the descriptor for the instruction"); - - // Check whether it is legitimate to insert a copy before this - // instruction. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject, - inst_it)) { - return; - } - - // Randomly decide whether to try inserting an object copy here. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfCopyingObject())) { - return; - } - - const auto relevant_instructions = FindAvailableInstructions( - function, block, inst_it, - [this](opt::IRContext* ir_context, opt::Instruction* inst) { - return TransformationAddSynonym::IsInstructionValid( - ir_context, *GetTransformationContext(), inst, - protobufs::TransformationAddSynonym::COPY_OBJECT); - }); - - // At this point, |relevant_instructions| contains all the instructions - // we might think of copying. - if (relevant_instructions.empty()) { - return; - } - - // Choose a copyable instruction at random, and create and apply an - // object copying transformation based on it. - ApplyTransformation(TransformationAddSynonym( - relevant_instructions[GetFuzzerContext()->RandomIndex( - relevant_instructions)] - ->result_id(), - protobufs::TransformationAddSynonym::COPY_OBJECT, - GetFuzzerContext()->GetFreshId(), instruction_descriptor)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h deleted file mode 100644 index 8de382e7f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for adding adding copies of objects to the module. -class FuzzerPassCopyObjects : public FuzzerPass { - public: - FuzzerPassCopyObjects(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassCopyObjects(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp deleted file mode 100644 index f54d3e4ec..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp +++ /dev/null @@ -1,1258 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_donate_modules.h" - -#include -#include -#include - -#include "source/fuzz/call_graph.h" -#include "source/fuzz/instruction_message.h" -#include "source/fuzz/transformation_add_constant_boolean.h" -#include "source/fuzz/transformation_add_constant_composite.h" -#include "source/fuzz/transformation_add_constant_null.h" -#include "source/fuzz/transformation_add_constant_scalar.h" -#include "source/fuzz/transformation_add_function.h" -#include "source/fuzz/transformation_add_global_undef.h" -#include "source/fuzz/transformation_add_global_variable.h" -#include "source/fuzz/transformation_add_spec_constant_op.h" -#include "source/fuzz/transformation_add_type_array.h" -#include "source/fuzz/transformation_add_type_boolean.h" -#include "source/fuzz/transformation_add_type_float.h" -#include "source/fuzz/transformation_add_type_function.h" -#include "source/fuzz/transformation_add_type_int.h" -#include "source/fuzz/transformation_add_type_matrix.h" -#include "source/fuzz/transformation_add_type_pointer.h" -#include "source/fuzz/transformation_add_type_struct.h" -#include "source/fuzz/transformation_add_type_vector.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassDonateModules::FuzzerPassDonateModules( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations, - const std::vector& donor_suppliers) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations), - donor_suppliers_(donor_suppliers) {} - -FuzzerPassDonateModules::~FuzzerPassDonateModules() = default; - -void FuzzerPassDonateModules::Apply() { - // If there are no donor suppliers, this fuzzer pass is a no-op. - if (donor_suppliers_.empty()) { - return; - } - - // Donate at least one module, and probabilistically decide when to stop - // donating modules. - do { - // Choose a donor supplier at random, and get the module that it provides. - std::unique_ptr donor_ir_context = donor_suppliers_.at( - GetFuzzerContext()->RandomIndex(donor_suppliers_))(); - assert(donor_ir_context != nullptr && "Supplying of donor failed"); - assert(fuzzerutil::IsValid( - donor_ir_context.get(), - GetTransformationContext()->GetValidatorOptions()) && - "The donor module must be valid"); - // Donate the supplied module. - // - // Randomly decide whether to make the module livesafe (see - // FactFunctionIsLivesafe); doing so allows it to be used for live code - // injection but restricts its behaviour to allow this, and means that its - // functions cannot be transformed as if they were arbitrary dead code. - bool make_livesafe = GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->ChanceOfMakingDonorLivesafe()); - DonateSingleModule(donor_ir_context.get(), make_livesafe); - } while (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfDonatingAdditionalModule())); -} - -void FuzzerPassDonateModules::DonateSingleModule( - opt::IRContext* donor_ir_context, bool make_livesafe) { - // Check that the donated module has capabilities, supported by the recipient - // module. - for (const auto& capability_inst : donor_ir_context->capabilities()) { - auto capability = - static_cast(capability_inst.GetSingleWordInOperand(0)); - if (!GetIRContext()->get_feature_mgr()->HasCapability(capability)) { - return; - } - } - - // The ids used by the donor module may very well clash with ids defined in - // the recipient module. Furthermore, some instructions defined in the donor - // module will be equivalent to instructions defined in the recipient module, - // and it is not always legal to re-declare equivalent instructions. For - // example, OpTypeVoid cannot be declared twice. - // - // To handle this, we maintain a mapping from an id used in the donor module - // to the corresponding id that will be used by the donated code when it - // appears in the recipient module. - // - // This mapping is populated in two ways: - // (1) by mapping a donor instruction's result id to the id of some equivalent - // existing instruction in the recipient (e.g. this has to be done for - // OpTypeVoid) - // (2) by mapping a donor instruction's result id to a freshly chosen id that - // is guaranteed to be different from any id already used by the recipient - // (or from any id already chosen to handle a previous donor id) - std::map original_id_to_donated_id; - - HandleExternalInstructionImports(donor_ir_context, - &original_id_to_donated_id); - HandleTypesAndValues(donor_ir_context, &original_id_to_donated_id); - HandleFunctions(donor_ir_context, &original_id_to_donated_id, make_livesafe); - - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3115) Handle some - // kinds of decoration. -} - -SpvStorageClass FuzzerPassDonateModules::AdaptStorageClass( - SpvStorageClass donor_storage_class) { - switch (donor_storage_class) { - case SpvStorageClassFunction: - case SpvStorageClassPrivate: - case SpvStorageClassWorkgroup: - // We leave these alone - return donor_storage_class; - case SpvStorageClassInput: - case SpvStorageClassOutput: - case SpvStorageClassUniform: - case SpvStorageClassUniformConstant: - case SpvStorageClassPushConstant: - case SpvStorageClassImage: - case SpvStorageClassStorageBuffer: - // We change these to Private - return SpvStorageClassPrivate; - default: - // Handle other cases on demand. - assert(false && "Currently unsupported storage class."); - return SpvStorageClassMax; - } -} - -void FuzzerPassDonateModules::HandleExternalInstructionImports( - opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id) { - // Consider every external instruction set import in the donor module. - for (auto& donor_import : donor_ir_context->module()->ext_inst_imports()) { - const auto& donor_import_name_words = donor_import.GetInOperand(0).words; - // Look for an identical import in the recipient module. - for (auto& existing_import : GetIRContext()->module()->ext_inst_imports()) { - const auto& existing_import_name_words = - existing_import.GetInOperand(0).words; - if (donor_import_name_words == existing_import_name_words) { - // A matching import has found. Map the result id for the donor import - // to the id of the existing import, so that when donor instructions - // rely on the import they will be rewritten to use the existing import. - original_id_to_donated_id->insert( - {donor_import.result_id(), existing_import.result_id()}); - break; - } - } - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3116): At present - // we do not handle donation of instruction imports, i.e. we do not allow - // the donor to import instruction sets that the recipient did not already - // import. It might be a good idea to allow this, but it requires some - // thought. - assert(original_id_to_donated_id->count(donor_import.result_id()) && - "Donation of imports is not yet supported."); - } -} - -void FuzzerPassDonateModules::HandleTypesAndValues( - opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id) { - // Consider every type/global/constant/undef in the module. - for (auto& type_or_value : donor_ir_context->module()->types_values()) { - HandleTypeOrValue(type_or_value, original_id_to_donated_id); - } -} - -void FuzzerPassDonateModules::HandleTypeOrValue( - const opt::Instruction& type_or_value, - std::map* original_id_to_donated_id) { - // The type/value instruction generates a result id, and we need to associate - // the donor's result id with a new result id. That new result id will either - // be the id of some existing instruction, or a fresh id. This variable - // captures it. - uint32_t new_result_id; - - // Decide how to handle each kind of instruction on a case-by-case basis. - // - // Because the donor module is required to be valid, when we encounter a - // type comprised of component types (e.g. an aggregate or pointer), we know - // that its component types will have been considered previously, and that - // |original_id_to_donated_id| will already contain an entry for them. - switch (type_or_value.opcode()) { - case SpvOpTypeImage: - case SpvOpTypeSampledImage: - case SpvOpTypeSampler: - // We do not donate types and variables that relate to images and - // samplers, so we skip these types and subsequently skip anything that - // depends on them. - return; - case SpvOpTypeVoid: { - // Void has to exist already in order for us to have an entry point. - // Get the existing id of void. - opt::analysis::Void void_type; - new_result_id = GetIRContext()->get_type_mgr()->GetId(&void_type); - assert(new_result_id && - "The module being transformed will always have 'void' type " - "declared."); - } break; - case SpvOpTypeBool: { - // Bool cannot be declared multiple times, so use its existing id if - // present, or add a declaration of Bool with a fresh id if not. - opt::analysis::Bool bool_type; - auto bool_type_id = GetIRContext()->get_type_mgr()->GetId(&bool_type); - if (bool_type_id) { - new_result_id = bool_type_id; - } else { - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeBoolean(new_result_id)); - } - } break; - case SpvOpTypeInt: { - // Int cannot be declared multiple times with the same width and - // signedness, so check whether an existing identical Int type is - // present and use its id if so. Otherwise add a declaration of the - // Int type used by the donor, with a fresh id. - const uint32_t width = type_or_value.GetSingleWordInOperand(0); - const bool is_signed = - static_cast(type_or_value.GetSingleWordInOperand(1)); - opt::analysis::Integer int_type(width, is_signed); - auto int_type_id = GetIRContext()->get_type_mgr()->GetId(&int_type); - if (int_type_id) { - new_result_id = int_type_id; - } else { - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation( - TransformationAddTypeInt(new_result_id, width, is_signed)); - } - } break; - case SpvOpTypeFloat: { - // Similar to SpvOpTypeInt. - const uint32_t width = type_or_value.GetSingleWordInOperand(0); - opt::analysis::Float float_type(width); - auto float_type_id = GetIRContext()->get_type_mgr()->GetId(&float_type); - if (float_type_id) { - new_result_id = float_type_id; - } else { - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeFloat(new_result_id, width)); - } - } break; - case SpvOpTypeVector: { - // It is not legal to have two Vector type declarations with identical - // element types and element counts, so check whether an existing - // identical Vector type is present and use its id if so. Otherwise add - // a declaration of the Vector type used by the donor, with a fresh id. - - // When considering the vector's component type id, we look up the id - // use in the donor to find the id to which this has been remapped. - uint32_t component_type_id = original_id_to_donated_id->at( - type_or_value.GetSingleWordInOperand(0)); - auto component_type = - GetIRContext()->get_type_mgr()->GetType(component_type_id); - assert(component_type && "The base type should be registered."); - auto component_count = type_or_value.GetSingleWordInOperand(1); - opt::analysis::Vector vector_type(component_type, component_count); - auto vector_type_id = GetIRContext()->get_type_mgr()->GetId(&vector_type); - if (vector_type_id) { - new_result_id = vector_type_id; - } else { - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeVector( - new_result_id, component_type_id, component_count)); - } - } break; - case SpvOpTypeMatrix: { - // Similar to SpvOpTypeVector. - uint32_t column_type_id = original_id_to_donated_id->at( - type_or_value.GetSingleWordInOperand(0)); - auto column_type = - GetIRContext()->get_type_mgr()->GetType(column_type_id); - assert(column_type && column_type->AsVector() && - "The column type should be a registered vector type."); - auto column_count = type_or_value.GetSingleWordInOperand(1); - opt::analysis::Matrix matrix_type(column_type, column_count); - auto matrix_type_id = GetIRContext()->get_type_mgr()->GetId(&matrix_type); - if (matrix_type_id) { - new_result_id = matrix_type_id; - } else { - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeMatrix( - new_result_id, column_type_id, column_count)); - } - - } break; - case SpvOpTypeArray: { - // It is OK to have multiple structurally identical array types, so - // we go ahead and add a remapped version of the type declared by the - // donor. - uint32_t component_type_id = type_or_value.GetSingleWordInOperand(0); - if (!original_id_to_donated_id->count(component_type_id)) { - // We did not donate the component type of this array type, so we - // cannot donate the array type. - return; - } - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeArray( - new_result_id, original_id_to_donated_id->at(component_type_id), - original_id_to_donated_id->at( - type_or_value.GetSingleWordInOperand(1)))); - } break; - case SpvOpTypeRuntimeArray: { - // A runtime array is allowed as the final member of an SSBO. During - // donation we turn runtime arrays into fixed-size arrays. For dead - // code donations this is OK because the array is never indexed into at - // runtime, so it does not matter what its size is. For live-safe code, - // all accesses are made in-bounds, so this is also OK. - // - // The special OpArrayLength instruction, which works on runtime arrays, - // is rewritten to yield the fixed length that is used for the array. - - uint32_t component_type_id = type_or_value.GetSingleWordInOperand(0); - if (!original_id_to_donated_id->count(component_type_id)) { - // We did not donate the component type of this runtime array type, so - // we cannot donate it as a fixed-size array. - return; - } - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypeArray( - new_result_id, original_id_to_donated_id->at(component_type_id), - FindOrCreateIntegerConstant( - {GetFuzzerContext()->GetRandomSizeForNewArray()}, 32, false, - false))); - } break; - case SpvOpTypeStruct: { - // Similar to SpvOpTypeArray. - std::vector member_type_ids; - for (uint32_t i = 0; i < type_or_value.NumInOperands(); i++) { - auto component_type_id = type_or_value.GetSingleWordInOperand(i); - if (!original_id_to_donated_id->count(component_type_id)) { - // We did not donate every member type for this struct type, so we - // cannot donate the struct type. - return; - } - member_type_ids.push_back( - original_id_to_donated_id->at(component_type_id)); - } - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation( - TransformationAddTypeStruct(new_result_id, member_type_ids)); - } break; - case SpvOpTypePointer: { - // Similar to SpvOpTypeArray. - uint32_t pointee_type_id = type_or_value.GetSingleWordInOperand(1); - if (!original_id_to_donated_id->count(pointee_type_id)) { - // We did not donate the pointee type for this pointer type, so we - // cannot donate the pointer type. - return; - } - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddTypePointer( - new_result_id, - AdaptStorageClass(static_cast( - type_or_value.GetSingleWordInOperand(0))), - original_id_to_donated_id->at(pointee_type_id))); - } break; - case SpvOpTypeFunction: { - // It is not OK to have multiple function types that use identical ids - // for their return and parameter types. We thus go through all - // existing function types to look for a match. We do not use the - // type manager here because we want to regard two function types that - // are structurally identical but that differ with respect to the - // actual ids used for pointer types as different. - // - // Example: - // - // %1 = OpTypeVoid - // %2 = OpTypeInt 32 0 - // %3 = OpTypePointer Function %2 - // %4 = OpTypePointer Function %2 - // %5 = OpTypeFunction %1 %3 - // %6 = OpTypeFunction %1 %4 - // - // We regard %5 and %6 as distinct function types here, even though - // they both have the form "uint32* -> void" - - std::vector return_and_parameter_types; - for (uint32_t i = 0; i < type_or_value.NumInOperands(); i++) { - uint32_t return_or_parameter_type = - type_or_value.GetSingleWordInOperand(i); - if (!original_id_to_donated_id->count(return_or_parameter_type)) { - // We did not donate every return/parameter type for this function - // type, so we cannot donate the function type. - return; - } - return_and_parameter_types.push_back( - original_id_to_donated_id->at(return_or_parameter_type)); - } - uint32_t existing_function_id = fuzzerutil::FindFunctionType( - GetIRContext(), return_and_parameter_types); - if (existing_function_id) { - new_result_id = existing_function_id; - } else { - // No match was found, so add a remapped version of the function type - // to the module, with a fresh id. - new_result_id = GetFuzzerContext()->GetFreshId(); - std::vector argument_type_ids; - for (uint32_t i = 1; i < type_or_value.NumInOperands(); i++) { - argument_type_ids.push_back(original_id_to_donated_id->at( - type_or_value.GetSingleWordInOperand(i))); - } - ApplyTransformation(TransformationAddTypeFunction( - new_result_id, - original_id_to_donated_id->at( - type_or_value.GetSingleWordInOperand(0)), - argument_type_ids)); - } - } break; - case SpvOpSpecConstantOp: { - new_result_id = GetFuzzerContext()->GetFreshId(); - auto type_id = original_id_to_donated_id->at(type_or_value.type_id()); - auto opcode = static_cast(type_or_value.GetSingleWordInOperand(0)); - - // Make sure we take into account |original_id_to_donated_id| when - // computing operands for OpSpecConstantOp. - opt::Instruction::OperandList operands; - for (uint32_t i = 1; i < type_or_value.NumInOperands(); ++i) { - const auto& operand = type_or_value.GetInOperand(i); - auto data = - operand.type == SPV_OPERAND_TYPE_ID - ? opt::Operand::OperandData{original_id_to_donated_id->at( - operand.words[0])} - : operand.words; - - operands.push_back({operand.type, std::move(data)}); - } - - ApplyTransformation(TransformationAddSpecConstantOp( - new_result_id, type_id, opcode, std::move(operands))); - } break; - case SpvOpSpecConstantTrue: - case SpvOpSpecConstantFalse: - case SpvOpConstantTrue: - case SpvOpConstantFalse: { - // It is OK to have duplicate definitions of True and False, so add - // these to the module, using a remapped Bool type. - new_result_id = GetFuzzerContext()->GetFreshId(); - auto value = type_or_value.opcode() == SpvOpConstantTrue || - type_or_value.opcode() == SpvOpSpecConstantTrue; - ApplyTransformation( - TransformationAddConstantBoolean(new_result_id, value, false)); - } break; - case SpvOpSpecConstant: - case SpvOpConstant: { - // It is OK to have duplicate constant definitions, so add this to the - // module using a remapped result type. - new_result_id = GetFuzzerContext()->GetFreshId(); - std::vector data_words; - type_or_value.ForEachInOperand([&data_words](const uint32_t* in_operand) { - data_words.push_back(*in_operand); - }); - ApplyTransformation(TransformationAddConstantScalar( - new_result_id, original_id_to_donated_id->at(type_or_value.type_id()), - data_words, false)); - } break; - case SpvOpSpecConstantComposite: - case SpvOpConstantComposite: { - assert(original_id_to_donated_id->count(type_or_value.type_id()) && - "Composite types for which it is possible to create a constant " - "should have been donated."); - - // It is OK to have duplicate constant composite definitions, so add - // this to the module using remapped versions of all consituent ids and - // the result type. - new_result_id = GetFuzzerContext()->GetFreshId(); - std::vector constituent_ids; - type_or_value.ForEachInId([&constituent_ids, &original_id_to_donated_id]( - const uint32_t* constituent_id) { - assert(original_id_to_donated_id->count(*constituent_id) && - "The constants used to construct this composite should " - "have been donated."); - constituent_ids.push_back( - original_id_to_donated_id->at(*constituent_id)); - }); - ApplyTransformation(TransformationAddConstantComposite( - new_result_id, original_id_to_donated_id->at(type_or_value.type_id()), - constituent_ids, false)); - } break; - case SpvOpConstantNull: { - if (!original_id_to_donated_id->count(type_or_value.type_id())) { - // We did not donate the type associated with this null constant, so - // we cannot donate the null constant. - return; - } - - // It is fine to have multiple OpConstantNull instructions of the same - // type, so we just add this to the recipient module. - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddConstantNull( - new_result_id, - original_id_to_donated_id->at(type_or_value.type_id()))); - } break; - case SpvOpVariable: { - if (!original_id_to_donated_id->count(type_or_value.type_id())) { - // We did not donate the pointer type associated with this variable, - // so we cannot donate the variable. - return; - } - - // This is a global variable that could have one of various storage - // classes. However, we change all global variable pointer storage - // classes (such as Uniform, Input and Output) to private when donating - // pointer types, with the exception of the Workgroup storage class. - // - // Thus this variable's pointer type is guaranteed to have storage class - // Private or Workgroup. - // - // We add a global variable with either Private or Workgroup storage - // class, using remapped versions of the result type and initializer ids - // for the global variable in the donor. - // - // We regard the added variable as having an irrelevant value. This - // means that future passes can add stores to the variable in any - // way they wish, and pass them as pointer parameters to functions - // without worrying about whether their data might get modified. - new_result_id = GetFuzzerContext()->GetFreshId(); - uint32_t remapped_pointer_type = - original_id_to_donated_id->at(type_or_value.type_id()); - uint32_t initializer_id; - SpvStorageClass storage_class = - static_cast(type_or_value.GetSingleWordInOperand( - 0)) == SpvStorageClassWorkgroup - ? SpvStorageClassWorkgroup - : SpvStorageClassPrivate; - if (type_or_value.NumInOperands() == 1) { - // The variable did not have an initializer. Initialize it to zero - // if it has Private storage class (to limit problems associated with - // uninitialized data), and leave it uninitialized if it has Workgroup - // storage class (as Workgroup variables cannot have initializers). - - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3275): we - // could initialize Workgroup variables at the start of an entry - // point, and should do so if their uninitialized nature proves - // problematic. - initializer_id = storage_class == SpvStorageClassWorkgroup - ? 0 - : FindOrCreateZeroConstant( - fuzzerutil::GetPointeeTypeIdFromPointerType( - GetIRContext(), remapped_pointer_type), - false); - } else { - // The variable already had an initializer; use its remapped id. - initializer_id = original_id_to_donated_id->at( - type_or_value.GetSingleWordInOperand(1)); - } - ApplyTransformation( - TransformationAddGlobalVariable(new_result_id, remapped_pointer_type, - storage_class, initializer_id, true)); - } break; - case SpvOpUndef: { - if (!original_id_to_donated_id->count(type_or_value.type_id())) { - // We did not donate the type associated with this undef, so we cannot - // donate the undef. - return; - } - - // It is fine to have multiple Undef instructions of the same type, so - // we just add this to the recipient module. - new_result_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationAddGlobalUndef( - new_result_id, - original_id_to_donated_id->at(type_or_value.type_id()))); - } break; - default: { - assert(0 && "Unknown type/value."); - new_result_id = 0; - } break; - } - - // Update the id mapping to associate the instruction's result id with its - // corresponding id in the recipient. - original_id_to_donated_id->insert({type_or_value.result_id(), new_result_id}); -} - -void FuzzerPassDonateModules::HandleFunctions( - opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id, - bool make_livesafe) { - // Get the ids of functions in the donor module, topologically sorted - // according to the donor's call graph. - auto topological_order = - GetFunctionsInCallGraphTopologicalOrder(donor_ir_context); - - // Donate the functions in reverse topological order. This ensures that a - // function gets donated before any function that depends on it. This allows - // donation of the functions to be separated into a number of transformations, - // each adding one function, such that every prefix of transformations leaves - // the module valid. - for (auto function_id = topological_order.rbegin(); - function_id != topological_order.rend(); ++function_id) { - // Find the function to be donated. - opt::Function* function_to_donate = nullptr; - for (auto& function : *donor_ir_context->module()) { - if (function.result_id() == *function_id) { - function_to_donate = &function; - break; - } - } - assert(function_to_donate && "Function to be donated was not found."); - - if (!original_id_to_donated_id->count( - function_to_donate->DefInst().GetSingleWordInOperand(1))) { - // We were not able to donate this function's type, so we cannot donate - // the function. - continue; - } - - // We will collect up protobuf messages representing the donor function's - // instructions here, and use them to create an AddFunction transformation. - std::vector donated_instructions; - - // This set tracks the ids of those instructions for which donation was - // completely skipped: neither the instruction nor a substitute for it was - // donated. - std::set skipped_instructions; - - // Consider every instruction of the donor function. - function_to_donate->ForEachInst( - [this, &donated_instructions, donor_ir_context, - &original_id_to_donated_id, - &skipped_instructions](const opt::Instruction* instruction) { - if (instruction->opcode() == SpvOpArrayLength) { - // We treat OpArrayLength specially. - HandleOpArrayLength(*instruction, original_id_to_donated_id, - &donated_instructions); - } else if (!CanDonateInstruction(donor_ir_context, *instruction, - *original_id_to_donated_id, - skipped_instructions)) { - // This is an instruction that we cannot directly donate. - HandleDifficultInstruction(*instruction, original_id_to_donated_id, - &donated_instructions, - &skipped_instructions); - } else { - PrepareInstructionForDonation(*instruction, donor_ir_context, - original_id_to_donated_id, - &donated_instructions); - } - }); - - // If |make_livesafe| is true, try to add the function in a livesafe manner. - // Otherwise (if |make_lifesafe| is false or an attempt to make the function - // livesafe has failed), add the function in a non-livesafe manner. - if (!make_livesafe || - !MaybeAddLivesafeFunction(*function_to_donate, donor_ir_context, - *original_id_to_donated_id, - donated_instructions)) { - ApplyTransformation(TransformationAddFunction(donated_instructions)); - } - } -} - -bool FuzzerPassDonateModules::CanDonateInstruction( - opt::IRContext* donor_ir_context, const opt::Instruction& instruction, - const std::map& original_id_to_donated_id, - const std::set& skipped_instructions) const { - if (instruction.type_id() && - !original_id_to_donated_id.count(instruction.type_id())) { - // We could not donate the result type of this instruction, so we cannot - // donate the instruction. - return false; - } - - // Now consider instructions we specifically want to skip because we do not - // yet support them. - switch (instruction.opcode()) { - case SpvOpAtomicLoad: - case SpvOpAtomicStore: - case SpvOpAtomicExchange: - case SpvOpAtomicCompareExchange: - case SpvOpAtomicCompareExchangeWeak: - case SpvOpAtomicIIncrement: - case SpvOpAtomicIDecrement: - case SpvOpAtomicIAdd: - case SpvOpAtomicISub: - case SpvOpAtomicSMin: - case SpvOpAtomicUMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMax: - case SpvOpAtomicAnd: - case SpvOpAtomicOr: - case SpvOpAtomicXor: - // We conservatively ignore all atomic instructions at present. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3276): Consider - // being less conservative here. - case SpvOpImageSampleImplicitLod: - case SpvOpImageSampleExplicitLod: - case SpvOpImageSampleDrefImplicitLod: - case SpvOpImageSampleDrefExplicitLod: - case SpvOpImageSampleProjImplicitLod: - case SpvOpImageSampleProjExplicitLod: - case SpvOpImageSampleProjDrefImplicitLod: - case SpvOpImageSampleProjDrefExplicitLod: - case SpvOpImageFetch: - case SpvOpImageGather: - case SpvOpImageDrefGather: - case SpvOpImageRead: - case SpvOpImageWrite: - case SpvOpImageSparseSampleImplicitLod: - case SpvOpImageSparseSampleExplicitLod: - case SpvOpImageSparseSampleDrefImplicitLod: - case SpvOpImageSparseSampleDrefExplicitLod: - case SpvOpImageSparseSampleProjImplicitLod: - case SpvOpImageSparseSampleProjExplicitLod: - case SpvOpImageSparseSampleProjDrefImplicitLod: - case SpvOpImageSparseSampleProjDrefExplicitLod: - case SpvOpImageSparseFetch: - case SpvOpImageSparseGather: - case SpvOpImageSparseDrefGather: - case SpvOpImageSparseRead: - case SpvOpImageSampleFootprintNV: - case SpvOpImage: - case SpvOpImageQueryFormat: - case SpvOpImageQueryLevels: - case SpvOpImageQueryLod: - case SpvOpImageQueryOrder: - case SpvOpImageQuerySamples: - case SpvOpImageQuerySize: - case SpvOpImageQuerySizeLod: - case SpvOpSampledImage: - // We ignore all instructions related to accessing images, since we do not - // donate images. - return false; - case SpvOpLoad: - switch (donor_ir_context->get_def_use_mgr() - ->GetDef(instruction.type_id()) - ->opcode()) { - case SpvOpTypeImage: - case SpvOpTypeSampledImage: - case SpvOpTypeSampler: - // Again, we ignore instructions that relate to accessing images. - return false; - default: - break; - } - default: - break; - } - - // Examine each id input operand to the instruction. If it turns out that we - // have skipped any of these operands then we cannot donate the instruction. - bool result = true; - instruction.WhileEachInId( - [donor_ir_context, &original_id_to_donated_id, &result, - &skipped_instructions](const uint32_t* in_id) -> bool { - if (!original_id_to_donated_id.count(*in_id)) { - // We do not have a mapped result id for this id operand. That either - // means that it is a forward reference (which is OK), that we skipped - // the instruction that generated it (which is not OK), or that it is - // the id of a function or global value that we did not donate (which - // is not OK). We check for the latter two cases. - if (skipped_instructions.count(*in_id) || - // A function or global value does not have an associated basic - // block. - !donor_ir_context->get_instr_block(*in_id)) { - result = false; - return false; - } - } - return true; - }); - return result; -} - -bool FuzzerPassDonateModules::IsBasicType( - const opt::Instruction& instruction) const { - switch (instruction.opcode()) { - case SpvOpTypeArray: - case SpvOpTypeBool: - case SpvOpTypeFloat: - case SpvOpTypeInt: - case SpvOpTypeMatrix: - case SpvOpTypeStruct: - case SpvOpTypeVector: - return true; - default: - return false; - } -} - -std::vector -FuzzerPassDonateModules::GetFunctionsInCallGraphTopologicalOrder( - opt::IRContext* context) { - CallGraph call_graph(context); - - // This is an implementation of Kahn’s algorithm for topological sorting. - - // This is the sorted order of function ids that we will eventually return. - std::vector result; - - // Get a copy of the initial in-degrees of all functions. The algorithm - // involves decrementing these values, hence why we work on a copy. - std::map function_in_degree = - call_graph.GetFunctionInDegree(); - - // Populate a queue with all those function ids with in-degree zero. - std::queue queue; - for (auto& entry : function_in_degree) { - if (entry.second == 0) { - queue.push(entry.first); - } - } - - // Pop ids from the queue, adding them to the sorted order and decreasing the - // in-degrees of their successors. A successor who's in-degree becomes zero - // gets added to the queue. - while (!queue.empty()) { - auto next = queue.front(); - queue.pop(); - result.push_back(next); - for (auto successor : call_graph.GetDirectCallees(next)) { - assert(function_in_degree.at(successor) > 0 && - "The in-degree cannot be zero if the function is a successor."); - function_in_degree[successor] = function_in_degree.at(successor) - 1; - if (function_in_degree.at(successor) == 0) { - queue.push(successor); - } - } - } - - assert(result.size() == function_in_degree.size() && - "Every function should appear in the sort."); - - return result; -} - -void FuzzerPassDonateModules::HandleOpArrayLength( - const opt::Instruction& instruction, - std::map* original_id_to_donated_id, - std::vector* donated_instructions) const { - assert(instruction.opcode() == SpvOpArrayLength && - "Precondition: instruction must be OpArrayLength."); - uint32_t donated_variable_id = - original_id_to_donated_id->at(instruction.GetSingleWordInOperand(0)); - auto donated_variable_instruction = - GetIRContext()->get_def_use_mgr()->GetDef(donated_variable_id); - auto pointer_to_struct_instruction = - GetIRContext()->get_def_use_mgr()->GetDef( - donated_variable_instruction->type_id()); - assert(pointer_to_struct_instruction->opcode() == SpvOpTypePointer && - "Type of variable must be pointer."); - auto donated_struct_type_instruction = - GetIRContext()->get_def_use_mgr()->GetDef( - pointer_to_struct_instruction->GetSingleWordInOperand(1)); - assert(donated_struct_type_instruction->opcode() == SpvOpTypeStruct && - "Pointee type of pointer used by OpArrayLength must be struct."); - assert(donated_struct_type_instruction->NumInOperands() == - instruction.GetSingleWordInOperand(1) + 1 && - "OpArrayLength must refer to the final member of the given " - "struct."); - uint32_t fixed_size_array_type_id = - donated_struct_type_instruction->GetSingleWordInOperand( - donated_struct_type_instruction->NumInOperands() - 1); - auto fixed_size_array_type_instruction = - GetIRContext()->get_def_use_mgr()->GetDef(fixed_size_array_type_id); - assert(fixed_size_array_type_instruction->opcode() == SpvOpTypeArray && - "The donated array type must be fixed-size."); - auto array_size_id = - fixed_size_array_type_instruction->GetSingleWordInOperand(1); - - if (instruction.result_id() && - !original_id_to_donated_id->count(instruction.result_id())) { - original_id_to_donated_id->insert( - {instruction.result_id(), GetFuzzerContext()->GetFreshId()}); - } - - donated_instructions->push_back(MakeInstructionMessage( - SpvOpCopyObject, original_id_to_donated_id->at(instruction.type_id()), - original_id_to_donated_id->at(instruction.result_id()), - opt::Instruction::OperandList({{SPV_OPERAND_TYPE_ID, {array_size_id}}}))); -} - -void FuzzerPassDonateModules::HandleDifficultInstruction( - const opt::Instruction& instruction, - std::map* original_id_to_donated_id, - std::vector* donated_instructions, - std::set* skipped_instructions) { - if (!instruction.result_id()) { - // It does not generate a result id, so it can be ignored. - return; - } - if (!original_id_to_donated_id->count(instruction.type_id())) { - // We cannot handle this instruction's result type, so we need to skip it - // all together. - skipped_instructions->insert(instruction.result_id()); - return; - } - - // We now attempt to replace the instruction with an OpCopyObject. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3278): We could do - // something more refined here - we could check which operands to the - // instruction could not be donated and replace those operands with - // references to other ids (such as constants), so that we still get an - // instruction with the opcode and easy-to-handle operands of the donor - // instruction. - auto remapped_type_id = original_id_to_donated_id->at(instruction.type_id()); - if (!IsBasicType( - *GetIRContext()->get_def_use_mgr()->GetDef(remapped_type_id))) { - // The instruction has a non-basic result type, so we cannot replace it with - // an object copy of a constant. We thus skip it completely. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3279): We could - // instead look for an available id of the right type and generate an - // OpCopyObject of that id. - skipped_instructions->insert(instruction.result_id()); - return; - } - - // We are going to add an OpCopyObject instruction. Add a mapping for the - // result id of the original instruction if does not already exist (it may - // exist in the case that it has been forward-referenced). - if (!original_id_to_donated_id->count(instruction.result_id())) { - original_id_to_donated_id->insert( - {instruction.result_id(), GetFuzzerContext()->GetFreshId()}); - } - - // We find or add a zero constant to the receiving module for the type in - // question, and add an OpCopyObject instruction that copies this zero. - // - // We mark the constant as irrelevant so that we can replace it with a - // more interesting value later. - auto zero_constant = FindOrCreateZeroConstant(remapped_type_id, true); - donated_instructions->push_back(MakeInstructionMessage( - SpvOpCopyObject, remapped_type_id, - original_id_to_donated_id->at(instruction.result_id()), - opt::Instruction::OperandList({{SPV_OPERAND_TYPE_ID, {zero_constant}}}))); -} - -void FuzzerPassDonateModules::PrepareInstructionForDonation( - const opt::Instruction& instruction, opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id, - std::vector* donated_instructions) { - // Get the instruction's input operands into donation-ready form, - // remapping any id uses in the process. - opt::Instruction::OperandList input_operands; - - // Consider each input operand in turn. - for (uint32_t in_operand_index = 0; - in_operand_index < instruction.NumInOperands(); in_operand_index++) { - std::vector operand_data; - const opt::Operand& in_operand = instruction.GetInOperand(in_operand_index); - // Check whether this operand is an id. - if (spvIsIdType(in_operand.type)) { - // This is an id operand - it consists of a single word of data, - // which needs to be remapped so that it is replaced with the - // donated form of the id. - auto operand_id = in_operand.words[0]; - if (!original_id_to_donated_id->count(operand_id)) { - // This is a forward reference. We will choose a corresponding - // donor id for the referenced id and update the mapping to - // reflect it. - - // Keep release compilers happy because |donor_ir_context| is only used - // in this assertion. - (void)(donor_ir_context); - assert((donor_ir_context->get_def_use_mgr() - ->GetDef(operand_id) - ->opcode() == SpvOpLabel || - instruction.opcode() == SpvOpPhi) && - "Unsupported forward reference."); - original_id_to_donated_id->insert( - {operand_id, GetFuzzerContext()->GetFreshId()}); - } - operand_data.push_back(original_id_to_donated_id->at(operand_id)); - } else { - // For non-id operands, we just add each of the data words. - for (auto word : in_operand.words) { - operand_data.push_back(word); - } - } - input_operands.push_back({in_operand.type, operand_data}); - } - - if (instruction.opcode() == SpvOpVariable && - instruction.NumInOperands() == 1) { - // This is an uninitialized local variable. Initialize it to zero. - input_operands.push_back( - {SPV_OPERAND_TYPE_ID, - {FindOrCreateZeroConstant( - fuzzerutil::GetPointeeTypeIdFromPointerType( - GetIRContext(), - original_id_to_donated_id->at(instruction.type_id())), - false)}}); - } - - if (instruction.result_id() && - !original_id_to_donated_id->count(instruction.result_id())) { - original_id_to_donated_id->insert( - {instruction.result_id(), GetFuzzerContext()->GetFreshId()}); - } - - // Remap the result type and result id (if present) of the - // instruction, and turn it into a protobuf message. - donated_instructions->push_back(MakeInstructionMessage( - instruction.opcode(), - instruction.type_id() - ? original_id_to_donated_id->at(instruction.type_id()) - : 0, - instruction.result_id() - ? original_id_to_donated_id->at(instruction.result_id()) - : 0, - input_operands)); -} - -bool FuzzerPassDonateModules::CreateLoopLimiterInfo( - opt::IRContext* donor_ir_context, const opt::BasicBlock& loop_header, - const std::map& original_id_to_donated_id, - protobufs::LoopLimiterInfo* out) { - assert(loop_header.IsLoopHeader() && "|loop_header| is not a loop header"); - - // Grab the loop header's id, mapped to its donated value. - out->set_loop_header_id(original_id_to_donated_id.at(loop_header.id())); - - // Get fresh ids that will be used to load the loop limiter, increment - // it, compare it with the loop limit, and an id for a new block that - // will contain the loop's original terminator. - out->set_load_id(GetFuzzerContext()->GetFreshId()); - out->set_increment_id(GetFuzzerContext()->GetFreshId()); - out->set_compare_id(GetFuzzerContext()->GetFreshId()); - out->set_logical_op_id(GetFuzzerContext()->GetFreshId()); - - // We are creating a branch from the back-edge block to the merge block. Thus, - // if merge block has any OpPhi instructions, we might need to adjust - // them. - - // Note that the loop might have an unreachable back-edge block. This means - // that the loop can't iterate, so we don't need to adjust anything. - const auto back_edge_block_id = TransformationAddFunction::GetBackEdgeBlockId( - donor_ir_context, loop_header.id()); - if (!back_edge_block_id) { - return true; - } - - auto* back_edge_block = donor_ir_context->cfg()->block(back_edge_block_id); - assert(back_edge_block && "|back_edge_block_id| is invalid"); - - const auto* merge_block = - donor_ir_context->cfg()->block(loop_header.MergeBlockId()); - assert(merge_block && "Loop header has invalid merge block id"); - - // We don't need to adjust anything if there is already a branch from - // the back-edge block to the merge block. - if (back_edge_block->IsSuccessor(merge_block)) { - return true; - } - - // Adjust OpPhi instructions in the |merge_block|. - for (const auto& inst : *merge_block) { - if (inst.opcode() != SpvOpPhi) { - break; - } - - // There is no simple way to ensure that a chosen operand for the OpPhi - // instruction will never cause any problems (e.g. if we choose an - // integer id, it might have a zero value when we branch from the back - // edge block. This might cause a division by 0 later in the function.). - // Thus, we ignore possible problems and proceed as follows: - // - if any of the existing OpPhi operands dominates the back-edge - // block - use it - // - if OpPhi has a basic type (see IsBasicType method) - create - // a zero constant - // - otherwise, we can't add a livesafe function. - uint32_t suitable_operand_id = 0; - for (uint32_t i = 0; i < inst.NumInOperands(); i += 2) { - auto dependency_inst_id = inst.GetSingleWordInOperand(i); - - if (fuzzerutil::IdIsAvailableBeforeInstruction( - donor_ir_context, back_edge_block->terminator(), - dependency_inst_id)) { - suitable_operand_id = original_id_to_donated_id.at(dependency_inst_id); - break; - } - } - - if (suitable_operand_id == 0 && - IsBasicType( - *donor_ir_context->get_def_use_mgr()->GetDef(inst.type_id()))) { - // We mark this constant as irrelevant so that we can replace it - // with more interesting value later. - suitable_operand_id = FindOrCreateZeroConstant( - original_id_to_donated_id.at(inst.type_id()), true); - } - - if (suitable_operand_id == 0) { - return false; - } - - out->add_phi_id(suitable_operand_id); - } - - return true; -} - -bool FuzzerPassDonateModules::MaybeAddLivesafeFunction( - const opt::Function& function_to_donate, opt::IRContext* donor_ir_context, - const std::map& original_id_to_donated_id, - const std::vector& donated_instructions) { - // Various types and constants must be in place for a function to be made - // live-safe. Add them if not already present. - FindOrCreateBoolType(); // Needed for comparisons - FindOrCreatePointerToIntegerType( - 32, false, SpvStorageClassFunction); // Needed for adding loop limiters - FindOrCreateIntegerConstant({0}, 32, false, - false); // Needed for initializing loop limiters - FindOrCreateIntegerConstant({1}, 32, false, - false); // Needed for incrementing loop limiters - - // Get a fresh id for the variable that will be used as a loop limiter. - const uint32_t loop_limiter_variable_id = GetFuzzerContext()->GetFreshId(); - // Choose a random loop limit, and add the required constant to the - // module if not already there. - const uint32_t loop_limit = FindOrCreateIntegerConstant( - {GetFuzzerContext()->GetRandomLoopLimit()}, 32, false, false); - - // Consider every loop header in the function to donate, and create a - // structure capturing the ids to be used for manipulating the loop - // limiter each time the loop is iterated. - std::vector loop_limiters; - for (auto& block : function_to_donate) { - if (block.IsLoopHeader()) { - protobufs::LoopLimiterInfo loop_limiter; - - if (!CreateLoopLimiterInfo(donor_ir_context, block, - original_id_to_donated_id, &loop_limiter)) { - return false; - } - - loop_limiters.emplace_back(std::move(loop_limiter)); - } - } - - // Consider every access chain in the function to donate, and create a - // structure containing the ids necessary to clamp the access chain - // indices to be in-bounds. - std::vector access_chain_clamping_info; - for (auto& block : function_to_donate) { - for (auto& inst : block) { - switch (inst.opcode()) { - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: { - protobufs::AccessChainClampingInfo clamping_info; - clamping_info.set_access_chain_id( - original_id_to_donated_id.at(inst.result_id())); - - auto base_object = donor_ir_context->get_def_use_mgr()->GetDef( - inst.GetSingleWordInOperand(0)); - assert(base_object && "The base object must exist."); - auto pointer_type = donor_ir_context->get_def_use_mgr()->GetDef( - base_object->type_id()); - assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer && - "The base object must have pointer type."); - - auto should_be_composite_type = - donor_ir_context->get_def_use_mgr()->GetDef( - pointer_type->GetSingleWordInOperand(1)); - - // Walk the access chain, creating fresh ids to facilitate - // clamping each index. For simplicity we do this for every - // index, even though constant indices will not end up being - // clamped. - for (uint32_t index = 1; index < inst.NumInOperands(); index++) { - auto compare_and_select_ids = - clamping_info.add_compare_and_select_ids(); - compare_and_select_ids->set_first(GetFuzzerContext()->GetFreshId()); - compare_and_select_ids->set_second( - GetFuzzerContext()->GetFreshId()); - - // Get the bound for the component being indexed into. - uint32_t bound; - if (should_be_composite_type->opcode() == SpvOpTypeRuntimeArray) { - // The donor is indexing into a runtime array. We do not - // donate runtime arrays. Instead, we donate a corresponding - // fixed-size array for every runtime array. We should thus - // find that donor composite type's result id maps to a fixed- - // size array. - auto fixed_size_array_type = - GetIRContext()->get_def_use_mgr()->GetDef( - original_id_to_donated_id.at( - should_be_composite_type->result_id())); - assert(fixed_size_array_type->opcode() == SpvOpTypeArray && - "A runtime array type in the donor should have been " - "replaced by a fixed-sized array in the recipient."); - // The size of this fixed-size array is a suitable bound. - bound = fuzzerutil::GetBoundForCompositeIndex( - *fixed_size_array_type, GetIRContext()); - } else { - bound = fuzzerutil::GetBoundForCompositeIndex( - *should_be_composite_type, donor_ir_context); - } - const uint32_t index_id = inst.GetSingleWordInOperand(index); - auto index_inst = - donor_ir_context->get_def_use_mgr()->GetDef(index_id); - auto index_type_inst = donor_ir_context->get_def_use_mgr()->GetDef( - index_inst->type_id()); - assert(index_type_inst->opcode() == SpvOpTypeInt); - opt::analysis::Integer* index_int_type = - donor_ir_context->get_type_mgr() - ->GetType(index_type_inst->result_id()) - ->AsInteger(); - if (index_inst->opcode() != SpvOpConstant) { - // We will have to clamp this index, so we need a constant - // whose value is one less than the bound, to compare - // against and to use as the clamped value. - FindOrCreateIntegerConstant({bound - 1}, 32, - index_int_type->IsSigned(), false); - } - should_be_composite_type = - TransformationAddFunction::FollowCompositeIndex( - donor_ir_context, *should_be_composite_type, index_id); - } - access_chain_clamping_info.push_back(clamping_info); - break; - } - default: - break; - } - } - } - - // If |function_to_donate| has non-void return type and contains an - // OpKill/OpUnreachable instruction, then a value is needed in order to turn - // these into instructions of the form OpReturnValue %value_id. - uint32_t kill_unreachable_return_value_id = 0; - auto function_return_type_inst = - donor_ir_context->get_def_use_mgr()->GetDef(function_to_donate.type_id()); - if (function_return_type_inst->opcode() != SpvOpTypeVoid && - fuzzerutil::FunctionContainsOpKillOrUnreachable(function_to_donate)) { - kill_unreachable_return_value_id = FindOrCreateZeroConstant( - original_id_to_donated_id.at(function_return_type_inst->result_id()), - false); - } - - // Add the function in a livesafe manner. - ApplyTransformation(TransformationAddFunction( - donated_instructions, loop_limiter_variable_id, loop_limit, loop_limiters, - kill_unreachable_return_value_id, access_chain_clamping_info)); - return true; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h deleted file mode 100644 index 89858e440..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_DONATE_MODULES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_DONATE_MODULES_H_ - -#include - -#include "source/fuzz/fuzzer_pass.h" -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass that randomly adds code from other SPIR-V modules to the module -// being transformed. -class FuzzerPassDonateModules : public FuzzerPass { - public: - FuzzerPassDonateModules( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations, - const std::vector& donor_suppliers); - - ~FuzzerPassDonateModules(); - - void Apply() override; - - // Donates the global declarations and functions of |donor_ir_context| into - // the fuzzer pass's IR context. |make_livesafe| dictates whether the - // functions of the donated module will be made livesafe (see - // FactFunctionIsLivesafe). - void DonateSingleModule(opt::IRContext* donor_ir_context, bool make_livesafe); - - private: - // Adapts a storage class coming from a donor module so that it will work - // in a recipient module, e.g. by changing Uniform to Private. - static SpvStorageClass AdaptStorageClass(SpvStorageClass donor_storage_class); - - // Identifies all external instruction set imports in |donor_ir_context| and - // populates |original_id_to_donated_id| with a mapping from the donor's id - // for such an import to a corresponding import in the recipient. Aborts if - // no such corresponding import is available. - void HandleExternalInstructionImports( - opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id); - - // Considers all types, globals, constants and undefs in |donor_ir_context|. - // For each instruction, uses |original_to_donated_id| to map its result id to - // either (1) the id of an existing identical instruction in the recipient, or - // (2) to a fresh id, in which case the instruction is also added to the - // recipient (with any operand ids that it uses being remapped via - // |original_id_to_donated_id|). - void HandleTypesAndValues( - opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id); - - // Helper method for HandleTypesAndValues, to handle a single type/value. - void HandleTypeOrValue( - const opt::Instruction& type_or_value, - std::map* original_id_to_donated_id); - - // Assumes that |donor_ir_context| does not exhibit recursion. Considers the - // functions in |donor_ir_context|'s call graph in a reverse-topologically- - // sorted order (leaves-to-root), adding each function to the recipient - // module, rewritten to use fresh ids and using |original_id_to_donated_id| to - // remap ids. The |make_livesafe| argument captures whether the functions in - // the module are required to be made livesafe before being added to the - // recipient. - void HandleFunctions(opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id, - bool make_livesafe); - - // During donation we will have to ignore some instructions, e.g. because they - // use opcodes that we cannot support or because they reference the ids of - // instructions that have not been donated. This function encapsulates the - // logic for deciding which whether instruction |instruction| from - // |donor_ir_context| can be donated. - bool CanDonateInstruction( - opt::IRContext* donor_ir_context, const opt::Instruction& instruction, - const std::map& original_id_to_donated_id, - const std::set& skipped_instructions) const; - - // We treat the OpArrayLength instruction specially. In the donor shader this - // instruction yields the length of a runtime array that is the final member - // of a struct. During donation, we will have converted the runtime array - // type, and the associated struct field, into a fixed-size array. - // - // Instead of donating this instruction, we turn it into an OpCopyObject - // instruction that copies the size of the fixed-size array. - void HandleOpArrayLength( - const opt::Instruction& instruction, - std::map* original_id_to_donated_id, - std::vector* donated_instructions) const; - - // The instruction |instruction| is required to be an instruction that cannot - // be easily donated, either because it uses an unsupported opcode, has an - // unsupported result type, or uses id operands that could not be donated. - // - // If |instruction| generates a result id, the function attempts to add a - // substitute for |instruction| to |donated_instructions| that has the correct - // result type. If this cannot be done, the instruction's result id is added - // to |skipped_instructions|. The mapping from donor ids to recipient ids is - // managed by |original_id_to_donated_id|. - void HandleDifficultInstruction( - const opt::Instruction& instruction, - std::map* original_id_to_donated_id, - std::vector* donated_instructions, - std::set* skipped_instructions); - - // Adds an instruction based in |instruction| to |donated_instructions| in a - // form ready for donation. The original instruction comes from - // |donor_ir_context|, and |original_id_to_donated_id| maps ids from - // |donor_ir_context| to corresponding ids in the recipient module. - void PrepareInstructionForDonation( - const opt::Instruction& instruction, opt::IRContext* donor_ir_context, - std::map* original_id_to_donated_id, - std::vector* donated_instructions); - - // Tries to create a protobufs::LoopLimiterInfo given a loop header basic - // block. Returns true if successful and outputs loop limiter into the |out| - // variable. Otherwise, returns false. |out| contains an undefined value when - // this function returns false. - bool CreateLoopLimiterInfo( - opt::IRContext* donor_ir_context, const opt::BasicBlock& loop_header, - const std::map& original_id_to_donated_id, - protobufs::LoopLimiterInfo* out); - - // Requires that |donated_instructions| represents a prepared version of the - // instructions of |function_to_donate| (which comes from |donor_ir_context|) - // ready for donation, and |original_id_to_donated_id| maps ids from - // |donor_ir_context| to their corresponding ids in the recipient module. - // - // Attempts to add a livesafe version of the function, based on - // |donated_instructions|, to the recipient module. Returns true if the - // donation was successful, false otherwise. - bool MaybeAddLivesafeFunction( - const opt::Function& function_to_donate, opt::IRContext* donor_ir_context, - const std::map& original_id_to_donated_id, - const std::vector& donated_instructions); - - // Returns true if and only if |instruction| is a scalar, vector, matrix, - // array or struct; i.e. it is not an opaque type. - bool IsBasicType(const opt::Instruction& instruction) const; - - // Returns the ids of all functions in |context| in a topological order in - // relation to the call graph of |context|, which is assumed to be recursion- - // free. - static std::vector GetFunctionsInCallGraphTopologicalOrder( - opt::IRContext* context); - - // Functions that supply SPIR-V modules - std::vector donor_suppliers_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_DONATE_MODULES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.cpp deleted file mode 100644 index 90160d83a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_inline_functions.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_inline_function.h" -#include "source/fuzz/transformation_split_block.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassInlineFunctions::FuzzerPassInlineFunctions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassInlineFunctions::~FuzzerPassInlineFunctions() = default; - -void FuzzerPassInlineFunctions::Apply() { - // |function_call_instructions| are the instructions that will be inlined. - // First, they will be collected and then do the inlining in another loop. - // This avoids changing the module while it is being inspected. - std::vector function_call_instructions; - - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - for (auto& instruction : block) { - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfInliningFunction())) { - continue; - } - - // |instruction| must be suitable for inlining. - if (!TransformationInlineFunction::IsSuitableForInlining( - GetIRContext(), &instruction)) { - continue; - } - - function_call_instructions.push_back(&instruction); - } - } - } - - // Once the function calls have been collected, it's time to actually create - // and apply the inlining transformations. - for (auto& function_call_instruction : function_call_instructions) { - // If |function_call_instruction| is not the penultimate instruction in its - // block or its block termination instruction is not OpBranch, then try to - // split |function_call_block| such that the conditions are met. - auto* function_call_block = - GetIRContext()->get_instr_block(function_call_instruction); - if ((function_call_instruction != &*--function_call_block->tail() || - function_call_block->terminator()->opcode() != SpvOpBranch) && - !MaybeApplyTransformation(TransformationSplitBlock( - MakeInstructionDescriptor(GetIRContext(), - function_call_instruction->NextNode()), - GetFuzzerContext()->GetFreshId()))) { - continue; - } - - auto* called_function = fuzzerutil::FindFunction( - GetIRContext(), function_call_instruction->GetSingleWordInOperand(0)); - - // Mapping the called function instructions. - std::map result_id_map; - for (auto& called_function_block : *called_function) { - // The called function entry block label will not be inlined. - if (&called_function_block != &*called_function->entry()) { - result_id_map[called_function_block.GetLabelInst()->result_id()] = - GetFuzzerContext()->GetFreshId(); - } - - for (auto& instruction_to_inline : called_function_block) { - // The instructions are mapped to fresh ids. - if (instruction_to_inline.HasResultId()) { - result_id_map[instruction_to_inline.result_id()] = - GetFuzzerContext()->GetFreshId(); - } - } - } - - // Applies the inline function transformation. - ApplyTransformation(TransformationInlineFunction( - function_call_instruction->result_id(), result_id_map)); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.h deleted file mode 100644 index 37295d1c2..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_inline_functions.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_INLINE_FUNCTIONS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_INLINE_FUNCTIONS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Looks for OpFunctionCall instructions and randomly decides which ones to -// inline. If the instructions of the called function are going to be inlined, -// then a mapping, between their result ids and suitable ids, is done. -class FuzzerPassInlineFunctions : public FuzzerPass { - public: - FuzzerPassInlineFunctions(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassInlineFunctions() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_INLINE_FUNCTIONS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp deleted file mode 100644 index 0e40b4963..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2020 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 "fuzzer_pass_interchange_signedness_of_integer_operands.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/id_use_descriptor.h" -#include "source/fuzz/transformation_record_synonymous_constants.h" -#include "source/fuzz/transformation_replace_id_with_synonym.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassInterchangeSignednessOfIntegerOperands:: - FuzzerPassInterchangeSignednessOfIntegerOperands( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassInterchangeSignednessOfIntegerOperands:: - ~FuzzerPassInterchangeSignednessOfIntegerOperands() = default; - -void FuzzerPassInterchangeSignednessOfIntegerOperands::Apply() { - // Make vector keeping track of all the uses we want to replace. - // This is a vector of pairs, where the first element is an id use descriptor - // identifying the use of a constant id and the second is the id that should - // be used to replace it. - std::vector> uses_to_replace; - - for (auto constant : GetIRContext()->GetConstants()) { - uint32_t constant_id = constant->result_id(); - - // We want to record the synonymity of an integer constant with another - // constant with opposite signedness, and this can only be done if they are - // not irrelevant. - if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant( - constant_id)) { - continue; - } - - uint32_t toggled_id = - FindOrCreateToggledIntegerConstant(constant->result_id()); - if (!toggled_id) { - // Not an integer constant - continue; - } - - assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant( - toggled_id) && - "FindOrCreateToggledConstant can't produce an irrelevant id"); - - // Record synonymous constants - ApplyTransformation( - TransformationRecordSynonymousConstants(constant_id, toggled_id)); - - // Find all the uses of the constant and, for each, probabilistically - // decide whether to replace it. - GetIRContext()->get_def_use_mgr()->ForEachUse( - constant_id, - [this, toggled_id, &uses_to_replace](opt::Instruction* use_inst, - uint32_t use_index) -> void { - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfInterchangingSignednessOfIntegerOperands())) { - MaybeAddUseToReplace(use_inst, use_index, toggled_id, - &uses_to_replace); - } - }); - } - - // Replace the ids if it is allowed. - for (auto use_to_replace : uses_to_replace) { - MaybeApplyTransformation(TransformationReplaceIdWithSynonym( - use_to_replace.first, use_to_replace.second)); - } -} - -uint32_t FuzzerPassInterchangeSignednessOfIntegerOperands:: - FindOrCreateToggledIntegerConstant(uint32_t id) { - // |id| must not be a specialization constant because we do not know the value - // of specialization constants. - if (opt::IsSpecConstantInst( - GetIRContext()->get_def_use_mgr()->GetDef(id)->opcode())) { - return 0; - } - - auto constant = GetIRContext()->get_constant_mgr()->FindDeclaredConstant(id); - - // This pass only toggles integer constants. - if (!constant->AsIntConstant() && - (!constant->AsVectorConstant() || - !constant->AsVectorConstant()->component_type()->AsInteger())) { - return 0; - } - - if (auto integer = constant->AsIntConstant()) { - auto type = integer->type()->AsInteger(); - - // Find or create and return the toggled constant. - return FindOrCreateIntegerConstant(std::vector(integer->words()), - type->width(), !type->IsSigned(), false); - } - - // The constant is an integer vector. - - // Find the component type. - auto component_type = - constant->AsVectorConstant()->component_type()->AsInteger(); - - // Find or create the toggled component type. - uint32_t toggled_component_type = FindOrCreateIntegerType( - component_type->width(), !component_type->IsSigned()); - - // Get the information about the toggled components. We need to extract this - // information now because the analyses might be invalidated, which would make - // the constant and component_type variables invalid. - std::vector> component_words; - - for (auto component : constant->AsVectorConstant()->GetComponents()) { - component_words.push_back(component->AsIntConstant()->words()); - } - uint32_t width = component_type->width(); - bool is_signed = !component_type->IsSigned(); - - std::vector toggled_components; - - // Find or create the toggled components. - for (auto words : component_words) { - toggled_components.push_back( - FindOrCreateIntegerConstant(words, width, is_signed, false)); - } - - // Find or create the required toggled vector type. - uint32_t toggled_type = FindOrCreateVectorType( - toggled_component_type, (uint32_t)toggled_components.size()); - - // Find or create and return the toggled vector constant. - return FindOrCreateCompositeConstant(toggled_components, toggled_type, false); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h deleted file mode 100644 index 48242189d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_INTERCHANGE_SIGNEDNESS_OF_INTEGER_OPERANDS_ -#define SOURCE_FUZZ_FUZZER_PASS_INTERCHANGE_SIGNEDNESS_OF_INTEGER_OPERANDS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A pass that: -// - Finds all the integer constant (scalar and vector) definitions in the -// module and adds the definitions of the integer with the same data words but -// opposite signedness. If the synonym is already in the module, it does not -// add a new one. -// - For each use of an integer constant where its signedness does not matter, -// decides whether to change it to the id of the toggled constant. -class FuzzerPassInterchangeSignednessOfIntegerOperands : public FuzzerPass { - public: - FuzzerPassInterchangeSignednessOfIntegerOperands( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassInterchangeSignednessOfIntegerOperands() override; - - void Apply() override; - - private: - // Given the id of an integer constant (scalar or vector), it finds or creates - // the corresponding toggled constant (the integer with the same data words - // but opposite signedness). Returns the id of the toggled instruction if the - // constant is an integer scalar or vector, 0 otherwise. - uint32_t FindOrCreateToggledIntegerConstant(uint32_t id); -}; -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_INTERCHANGE_SIGNEDNESS_OF_INTEGER_OPERANDS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp deleted file mode 100644 index 20575e115..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2020 Stefano Milizia -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/id_use_descriptor.h" -#include "source/fuzz/transformation_record_synonymous_constants.h" -#include "source/fuzz/transformation_replace_id_with_synonym.h" - -namespace spvtools { -namespace fuzz { -FuzzerPassInterchangeZeroLikeConstants::FuzzerPassInterchangeZeroLikeConstants( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassInterchangeZeroLikeConstants:: - ~FuzzerPassInterchangeZeroLikeConstants() = default; - -uint32_t FuzzerPassInterchangeZeroLikeConstants::FindOrCreateToggledConstant( - opt::Instruction* declaration) { - // |declaration| must not be a specialization constant because we do not know - // the value of specialization constants. - if (opt::IsSpecConstantInst(declaration->opcode())) { - return 0; - } - - auto constant = GetIRContext()->get_constant_mgr()->FindDeclaredConstant( - declaration->result_id()); - - // This pass only toggles zero-like constants - if (!constant->IsZero()) { - return 0; - } - - if (constant->AsScalarConstant()) { - return FindOrCreateNullConstant(declaration->type_id()); - } else if (constant->AsNullConstant()) { - // Add declaration of equivalent scalar constant - auto kind = constant->type()->kind(); - if (kind == opt::analysis::Type::kBool || - kind == opt::analysis::Type::kInteger || - kind == opt::analysis::Type::kFloat) { - return FindOrCreateZeroConstant(declaration->type_id(), false); - } - } - - return 0; -} - -void FuzzerPassInterchangeZeroLikeConstants::Apply() { - // Make vector keeping track of all the uses we want to replace. - // This is a vector of pairs, where the first element is an id use descriptor - // identifying the use of a constant id and the second is the id that should - // be used to replace it. - std::vector> uses_to_replace; - - for (auto constant : GetIRContext()->GetConstants()) { - uint32_t constant_id = constant->result_id(); - if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant( - constant_id)) { - continue; - } - - uint32_t toggled_id = FindOrCreateToggledConstant(constant); - if (!toggled_id) { - // Not a zero-like constant - continue; - } - - assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant( - toggled_id) && - "FindOrCreateToggledConstant can't produce an irrelevant id"); - - // Record synonymous constants - ApplyTransformation( - TransformationRecordSynonymousConstants(constant_id, toggled_id)); - - // Find all the uses of the constant and, for each, probabilistically - // decide whether to replace it. - GetIRContext()->get_def_use_mgr()->ForEachUse( - constant_id, - [this, toggled_id, &uses_to_replace](opt::Instruction* use_inst, - uint32_t use_index) -> void { - if (GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfInterchangingZeroLikeConstants())) { - MaybeAddUseToReplace(use_inst, use_index, toggled_id, - &uses_to_replace); - } - }); - } - - // Replace the ids if it is allowed. - for (auto use_to_replace : uses_to_replace) { - MaybeApplyTransformation(TransformationReplaceIdWithSynonym( - use_to_replace.first, use_to_replace.second)); - } -} -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h deleted file mode 100644 index 4ea990a40..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020 Stefano Milizia -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_INTERCHANGE_ZERO_LIKE_CONSTANTS_ -#define SOURCE_FUZZ_FUZZER_PASS_INTERCHANGE_ZERO_LIKE_CONSTANTS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A pass that: -// - Finds all the zero-like constant definitions in the module and adds the -// definitions of the corresponding synonym, recording the fact that they -// are synonymous. If the synonym is already in the module, it does not -// add a new one. -// - For each use of a zero-like constant, decides whether to change it to the -// id of the toggled constant. -class FuzzerPassInterchangeZeroLikeConstants : public FuzzerPass { - public: - FuzzerPassInterchangeZeroLikeConstants( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassInterchangeZeroLikeConstants() override; - - void Apply() override; - - private: - // Given the declaration of a zero-like constant, it finds or creates the - // corresponding toggled constant (a scalar constant of value 0 becomes a - // null constant of the same type and vice versa). - // Returns the id of the toggled instruction if the constant is zero-like, - // 0 otherwise. - uint32_t FindOrCreateToggledConstant(opt::Instruction* declaration); -}; - -} // namespace fuzz -} // namespace spvtools -#endif // SOURCE_FUZZ_FUZZER_PASS_INTERCHANGE_ZERO_LIKE_CONSTANTS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp deleted file mode 100644 index de4ff1de3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_invert_comparison_operators.h" - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_invert_comparison_operator.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassInvertComparisonOperators::FuzzerPassInvertComparisonOperators( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassInvertComparisonOperators::~FuzzerPassInvertComparisonOperators() = - default; - -void FuzzerPassInvertComparisonOperators::Apply() { - GetIRContext()->module()->ForEachInst([this](const opt::Instruction* inst) { - if (!TransformationInvertComparisonOperator::IsInversionSupported( - inst->opcode())) { - return; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfInvertingComparisonOperators())) { - return; - } - - ApplyTransformation(TransformationInvertComparisonOperator( - inst->result_id(), GetFuzzerContext()->GetFreshId())); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h deleted file mode 100644 index 9c80bbbb0..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_INVERT_COMPARISON_OPERATORS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_INVERT_COMPARISON_OPERATORS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Iterates over different comparison operators in the module (>=, <, > etc.) -// and randomly decides whether to invert each one or not. -class FuzzerPassInvertComparisonOperators : public FuzzerPass { - public: - FuzzerPassInvertComparisonOperators( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassInvertComparisonOperators() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_INVERT_COMPARISON_OPERATORS_H_ \ No newline at end of file diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp deleted file mode 100644 index f4f2a8026..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_make_vector_operations_dynamic.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_make_vector_operation_dynamic.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassMakeVectorOperationsDynamic::FuzzerPassMakeVectorOperationsDynamic( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassMakeVectorOperationsDynamic:: - ~FuzzerPassMakeVectorOperationsDynamic() = default; - -void FuzzerPassMakeVectorOperationsDynamic::Apply() { - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - for (auto& instruction : block) { - // Randomly decide whether to try applying the transformation. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfMakingVectorOperationDynamic())) { - continue; - } - - // |instruction| must be a vector operation. - if (!TransformationMakeVectorOperationDynamic::IsVectorOperation( - GetIRContext(), &instruction)) { - continue; - } - - // Make sure |instruction| has only one indexing operand. - assert(instruction.NumInOperands() == - (instruction.opcode() == SpvOpCompositeExtract ? 2 : 3) && - "FuzzerPassMakeVectorOperationsDynamic: the composite " - "instruction must have " - "only one indexing operand."); - - // Applies the make vector operation dynamic transformation. - ApplyTransformation(TransformationMakeVectorOperationDynamic( - instruction.result_id(), - FindOrCreateIntegerConstant( - {instruction.GetSingleWordInOperand( - instruction.opcode() == SpvOpCompositeExtract ? 1 : 2)}, - 32, GetFuzzerContext()->ChooseEven(), false))); - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h deleted file mode 100644 index dd51cde73..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_MAKE_VECTOR_OPERATIONS_DYNAMIC_H_ -#define SOURCE_FUZZ_FUZZER_PASS_MAKE_VECTOR_OPERATIONS_DYNAMIC_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Looks for OpCompositeExtract/Insert instructions on vectors, and replaces -// them with OpVectorExtract/InsertDynamic. -class FuzzerPassMakeVectorOperationsDynamic : public FuzzerPass { - public: - FuzzerPassMakeVectorOperationsDynamic( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassMakeVectorOperationsDynamic() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_MAKE_VECTOR_OPERATIONS_DYNAMIC_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp deleted file mode 100644 index e66fc4447..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_merge_blocks.h" - -#include - -#include "source/fuzz/transformation_merge_blocks.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassMergeBlocks::FuzzerPassMergeBlocks( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassMergeBlocks::~FuzzerPassMergeBlocks() = default; - -void FuzzerPassMergeBlocks::Apply() { - // First we populate a sequence of transformations that we might consider - // applying. - std::vector potential_transformations; - // We do this by considering every block of every function. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // We probabilistically decide to ignore some blocks. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfMergingBlocks())) { - continue; - } - // For other blocks, we add a transformation to merge the block into its - // predecessor if that transformation would be applicable. - TransformationMergeBlocks transformation(block.id()); - if (transformation.IsApplicable(GetIRContext(), - *GetTransformationContext())) { - potential_transformations.push_back(transformation); - } - } - } - - while (!potential_transformations.empty()) { - auto transformation = - GetFuzzerContext()->RemoveAtRandomIndex(&potential_transformations); - MaybeApplyTransformation(transformation); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h deleted file mode 100644 index 1a6c2c271..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_MERGE_BLOCKS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_MERGE_BLOCKS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for merging blocks in the module. -class FuzzerPassMergeBlocks : public FuzzerPass { - public: - FuzzerPassMergeBlocks(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassMergeBlocks(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_MERGE_BLOCKS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp deleted file mode 100644 index 2775bb8e1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_obfuscate_constants.h" - -#include -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" -#include "source/fuzz/transformation_replace_constant_with_uniform.h" -#include "source/fuzz/uniform_buffer_element_descriptor.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassObfuscateConstants::~FuzzerPassObfuscateConstants() = default; - -void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - const std::vector& greater_than_opcodes, - const std::vector& less_than_opcodes, uint32_t constant_id_1, - uint32_t constant_id_2, bool first_constant_is_larger) { - auto bool_constant_opcode = GetIRContext() - ->get_def_use_mgr() - ->GetDef(bool_constant_use.id_of_interest()) - ->opcode(); - assert((bool_constant_opcode == SpvOpConstantFalse || - bool_constant_opcode == SpvOpConstantTrue) && - "Precondition: this must be a usage of a boolean constant."); - - // Pick an opcode at random. First randomly decide whether to generate - // a 'greater than' or 'less than' kind of opcode, and then select a - // random opcode from the resulting subset. - SpvOp comparison_opcode; - if (GetFuzzerContext()->ChooseEven()) { - comparison_opcode = greater_than_opcodes[GetFuzzerContext()->RandomIndex( - greater_than_opcodes)]; - } else { - comparison_opcode = - less_than_opcodes[GetFuzzerContext()->RandomIndex(less_than_opcodes)]; - } - - // We now need to decide how to order constant_id_1 and constant_id_2 such - // that 'constant_id_1 comparison_opcode constant_id_2' evaluates to the - // boolean constant. - const bool is_greater_than_opcode = - std::find(greater_than_opcodes.begin(), greater_than_opcodes.end(), - comparison_opcode) != greater_than_opcodes.end(); - uint32_t lhs_id; - uint32_t rhs_id; - if ((bool_constant_opcode == SpvOpConstantTrue && - first_constant_is_larger == is_greater_than_opcode) || - (bool_constant_opcode == SpvOpConstantFalse && - first_constant_is_larger != is_greater_than_opcode)) { - lhs_id = constant_id_1; - rhs_id = constant_id_2; - } else { - lhs_id = constant_id_2; - rhs_id = constant_id_1; - } - - // We can now make a transformation that will replace |bool_constant_use| - // with an expression of the form (written using infix notation): - // |lhs_id| |comparison_opcode| |rhs_id| - auto transformation = TransformationReplaceBooleanConstantWithConstantBinary( - bool_constant_use, lhs_id, rhs_id, comparison_opcode, - GetFuzzerContext()->GetFreshId()); - // The transformation should be applicable by construction. - assert( - transformation.IsApplicable(GetIRContext(), *GetTransformationContext())); - - // Applying this transformation yields a pointer to the new instruction that - // computes the result of the binary expression. - auto binary_operator_instruction = transformation.ApplyWithResult( - GetIRContext(), GetTransformationContext()); - - // Add this transformation to the sequence of transformations that have been - // applied. - *GetTransformations()->add_transformation() = transformation.ToMessage(); - - // Having made a binary expression, there may now be opportunities to further - // obfuscate the constants used as the LHS and RHS of the expression (e.g. by - // replacing them with loads from known uniforms). - // - // We thus consider operands 0 and 1 (LHS and RHS in turn). - for (uint32_t index : {0u, 1u}) { - // We randomly decide, based on the current depth of obfuscation, whether - // to further obfuscate this operand. - if (GetFuzzerContext()->GoDeeperInConstantObfuscation(depth)) { - auto in_operand_use = MakeIdUseDescriptor( - binary_operator_instruction->GetSingleWordInOperand(index), - MakeInstructionDescriptor(binary_operator_instruction->result_id(), - binary_operator_instruction->opcode(), 0), - index); - ObfuscateConstant(depth + 1, in_operand_use); - } - } -} - -void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaFloatConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - uint32_t float_constant_id_1, uint32_t float_constant_id_2) { - auto float_constant_1 = GetIRContext() - ->get_constant_mgr() - ->FindDeclaredConstant(float_constant_id_1) - ->AsFloatConstant(); - auto float_constant_2 = GetIRContext() - ->get_constant_mgr() - ->FindDeclaredConstant(float_constant_id_2) - ->AsFloatConstant(); - assert(float_constant_1->words() != float_constant_2->words() && - "The constants should not be identical."); - assert(std::isfinite(float_constant_1->GetValueAsDouble()) && - "The constants must be finite numbers."); - assert(std::isfinite(float_constant_2->GetValueAsDouble()) && - "The constants must be finite numbers."); - bool first_constant_is_larger; - assert(float_constant_1->type()->AsFloat()->width() == - float_constant_2->type()->AsFloat()->width() && - "First and second floating-point constants must have the same width."); - if (float_constant_1->type()->AsFloat()->width() == 32) { - first_constant_is_larger = - float_constant_1->GetFloat() > float_constant_2->GetFloat(); - } else { - assert(float_constant_1->type()->AsFloat()->width() == 64 && - "Supported floating-point widths are 32 and 64."); - first_constant_is_larger = - float_constant_1->GetDouble() > float_constant_2->GetDouble(); - } - std::vector greater_than_opcodes{ - SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan, - SpvOpFUnordGreaterThanEqual}; - std::vector less_than_opcodes{ - SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan, - SpvOpFUnordGreaterThanEqual}; - - ObfuscateBoolConstantViaConstantPair( - depth, bool_constant_use, greater_than_opcodes, less_than_opcodes, - float_constant_id_1, float_constant_id_2, first_constant_is_larger); -} - -void FuzzerPassObfuscateConstants:: - ObfuscateBoolConstantViaSignedIntConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - uint32_t signed_int_constant_id_1, uint32_t signed_int_constant_id_2) { - auto signed_int_constant_1 = - GetIRContext() - ->get_constant_mgr() - ->FindDeclaredConstant(signed_int_constant_id_1) - ->AsIntConstant(); - auto signed_int_constant_2 = - GetIRContext() - ->get_constant_mgr() - ->FindDeclaredConstant(signed_int_constant_id_2) - ->AsIntConstant(); - assert(signed_int_constant_1->words() != signed_int_constant_2->words() && - "The constants should not be identical."); - bool first_constant_is_larger; - assert(signed_int_constant_1->type()->AsInteger()->width() == - signed_int_constant_2->type()->AsInteger()->width() && - "First and second floating-point constants must have the same width."); - assert(signed_int_constant_1->type()->AsInteger()->IsSigned()); - assert(signed_int_constant_2->type()->AsInteger()->IsSigned()); - if (signed_int_constant_1->type()->AsFloat()->width() == 32) { - first_constant_is_larger = - signed_int_constant_1->GetS32() > signed_int_constant_2->GetS32(); - } else { - assert(signed_int_constant_1->type()->AsFloat()->width() == 64 && - "Supported integer widths are 32 and 64."); - first_constant_is_larger = - signed_int_constant_1->GetS64() > signed_int_constant_2->GetS64(); - } - std::vector greater_than_opcodes{SpvOpSGreaterThan, - SpvOpSGreaterThanEqual}; - std::vector less_than_opcodes{SpvOpSLessThan, SpvOpSLessThanEqual}; - - ObfuscateBoolConstantViaConstantPair( - depth, bool_constant_use, greater_than_opcodes, less_than_opcodes, - signed_int_constant_id_1, signed_int_constant_id_2, - first_constant_is_larger); -} - -void FuzzerPassObfuscateConstants:: - ObfuscateBoolConstantViaUnsignedIntConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - uint32_t unsigned_int_constant_id_1, - uint32_t unsigned_int_constant_id_2) { - auto unsigned_int_constant_1 = - GetIRContext() - ->get_constant_mgr() - ->FindDeclaredConstant(unsigned_int_constant_id_1) - ->AsIntConstant(); - auto unsigned_int_constant_2 = - GetIRContext() - ->get_constant_mgr() - ->FindDeclaredConstant(unsigned_int_constant_id_2) - ->AsIntConstant(); - assert(unsigned_int_constant_1->words() != unsigned_int_constant_2->words() && - "The constants should not be identical."); - bool first_constant_is_larger; - assert(unsigned_int_constant_1->type()->AsInteger()->width() == - unsigned_int_constant_2->type()->AsInteger()->width() && - "First and second floating-point constants must have the same width."); - assert(!unsigned_int_constant_1->type()->AsInteger()->IsSigned()); - assert(!unsigned_int_constant_2->type()->AsInteger()->IsSigned()); - if (unsigned_int_constant_1->type()->AsFloat()->width() == 32) { - first_constant_is_larger = - unsigned_int_constant_1->GetU32() > unsigned_int_constant_2->GetU32(); - } else { - assert(unsigned_int_constant_1->type()->AsFloat()->width() == 64 && - "Supported integer widths are 32 and 64."); - first_constant_is_larger = - unsigned_int_constant_1->GetU64() > unsigned_int_constant_2->GetU64(); - } - std::vector greater_than_opcodes{SpvOpUGreaterThan, - SpvOpUGreaterThanEqual}; - std::vector less_than_opcodes{SpvOpULessThan, SpvOpULessThanEqual}; - - ObfuscateBoolConstantViaConstantPair( - depth, bool_constant_use, greater_than_opcodes, less_than_opcodes, - unsigned_int_constant_id_1, unsigned_int_constant_id_2, - first_constant_is_larger); -} - -std::vector> -FuzzerPassObfuscateConstants::GetConstantWordsFromUniformsForType( - uint32_t type_id) { - assert(type_id && "Type id can't be 0"); - std::vector> result; - - for (const auto& facts_and_types : GetTransformationContext() - ->GetFactManager() - ->GetConstantUniformFactsAndTypes()) { - if (facts_and_types.second != type_id) { - continue; - } - - std::vector words(facts_and_types.first.constant_word().begin(), - facts_and_types.first.constant_word().end()); - if (std::find(result.begin(), result.end(), words) == result.end()) { - result.push_back(std::move(words)); - } - } - - return result; -} - -void FuzzerPassObfuscateConstants::ObfuscateBoolConstant( - uint32_t depth, const protobufs::IdUseDescriptor& constant_use) { - // We want to replace the boolean constant use with a binary expression over - // scalar constants, but only if we can then potentially replace the constants - // with uniforms of the same value. - - auto available_types_with_uniforms = - GetTransformationContext() - ->GetFactManager() - ->GetTypesForWhichUniformValuesAreKnown(); - if (available_types_with_uniforms.empty()) { - // Do not try to obfuscate if we do not have access to any uniform - // elements with known values. - return; - } - auto chosen_type_id = - available_types_with_uniforms[GetFuzzerContext()->RandomIndex( - available_types_with_uniforms)]; - auto available_constant_words = - GetConstantWordsFromUniformsForType(chosen_type_id); - if (available_constant_words.size() == 1) { - // TODO(afd): for now we only obfuscate a boolean if there are at least - // two constants available from uniforms, so that we can do a - // comparison between them. It would be good to be able to do the - // obfuscation even if there is only one such constant, if there is - // also another regular constant available. - return; - } - - assert(!available_constant_words.empty() && - "There exists a fact but no constants - impossible"); - - // We know we have at least two known-to-be-constant uniforms of the chosen - // type. Pick one of them at random. - auto constant_index_1 = - GetFuzzerContext()->RandomIndex(available_constant_words); - uint32_t constant_index_2; - - // Now choose another one distinct from the first one. - do { - constant_index_2 = - GetFuzzerContext()->RandomIndex(available_constant_words); - } while (constant_index_1 == constant_index_2); - - auto constant_id_1 = FindOrCreateConstant( - available_constant_words[constant_index_1], chosen_type_id, false); - auto constant_id_2 = FindOrCreateConstant( - available_constant_words[constant_index_2], chosen_type_id, false); - - assert(constant_id_1 != 0 && constant_id_2 != 0 && - "We should not find an available constant with an id of 0."); - - // Now perform the obfuscation, according to whether the type of the constants - // is float, signed int, or unsigned int. - auto chosen_type = GetIRContext()->get_type_mgr()->GetType(chosen_type_id); - if (chosen_type->AsFloat()) { - ObfuscateBoolConstantViaFloatConstantPair(depth, constant_use, - constant_id_1, constant_id_2); - } else { - assert(chosen_type->AsInteger() && - "We should only have uniform facts about ints and floats."); - if (chosen_type->AsInteger()->IsSigned()) { - ObfuscateBoolConstantViaSignedIntConstantPair( - depth, constant_use, constant_id_1, constant_id_2); - } else { - ObfuscateBoolConstantViaUnsignedIntConstantPair( - depth, constant_use, constant_id_1, constant_id_2); - } - } -} - -void FuzzerPassObfuscateConstants::ObfuscateScalarConstant( - uint32_t /*depth*/, const protobufs::IdUseDescriptor& constant_use) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2670): consider - // additional ways to obfuscate scalar constants. - - // Check whether we know that any uniforms are guaranteed to be equal to the - // scalar constant associated with |constant_use|. - auto uniform_descriptors = - GetTransformationContext() - ->GetFactManager() - ->GetUniformDescriptorsForConstant(GetIRContext(), - constant_use.id_of_interest()); - if (uniform_descriptors.empty()) { - // No relevant uniforms, so do not obfuscate. - return; - } - - // Choose a random available uniform known to be equal to the constant. - const auto& uniform_descriptor = - uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)]; - - // Make sure the module has OpConstant instructions for each index used to - // access a uniform. - for (auto index : uniform_descriptor.index()) { - FindOrCreateIntegerConstant({index}, 32, true, false); - } - - // Make sure the module has OpTypePointer that points to the element type of - // the uniform. - const auto* uniform_variable_instr = - FindUniformVariable(uniform_descriptor, GetIRContext(), true); - assert(uniform_variable_instr && - "Uniform variable does not exist or not unique."); - - const auto* uniform_variable_type_intr = - GetIRContext()->get_def_use_mgr()->GetDef( - uniform_variable_instr->type_id()); - assert(uniform_variable_type_intr && "Uniform variable has invalid type"); - - auto element_type_id = fuzzerutil::WalkCompositeTypeIndices( - GetIRContext(), uniform_variable_type_intr->GetSingleWordInOperand(1), - uniform_descriptor.index()); - assert(element_type_id && "Type of uniform variable is invalid"); - - FindOrCreatePointerType(element_type_id, SpvStorageClassUniform); - - // Create, apply and record a transformation to replace the constant use with - // the result of a load from the chosen uniform. - ApplyTransformation(TransformationReplaceConstantWithUniform( - constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(), - GetFuzzerContext()->GetFreshId())); -} - -void FuzzerPassObfuscateConstants::ObfuscateConstant( - uint32_t depth, const protobufs::IdUseDescriptor& constant_use) { - switch (GetIRContext() - ->get_def_use_mgr() - ->GetDef(constant_use.id_of_interest()) - ->opcode()) { - case SpvOpConstantTrue: - case SpvOpConstantFalse: - ObfuscateBoolConstant(depth, constant_use); - break; - case SpvOpConstant: - ObfuscateScalarConstant(depth, constant_use); - break; - default: - assert(false && "The opcode should be one of the above."); - break; - } -} - -void FuzzerPassObfuscateConstants::MaybeAddConstantIdUse( - const opt::Instruction& inst, uint32_t in_operand_index, - uint32_t base_instruction_result_id, - const std::map& skipped_opcode_count, - std::vector* constant_uses) { - if (inst.GetInOperand(in_operand_index).type != SPV_OPERAND_TYPE_ID) { - // The operand is not an id, so it cannot be a constant id. - return; - } - auto operand_id = inst.GetSingleWordInOperand(in_operand_index); - auto operand_definition = - GetIRContext()->get_def_use_mgr()->GetDef(operand_id); - switch (operand_definition->opcode()) { - case SpvOpConstantFalse: - case SpvOpConstantTrue: - case SpvOpConstant: { - // The operand is a constant id, so make an id use descriptor and record - // it. - protobufs::IdUseDescriptor id_use_descriptor; - id_use_descriptor.set_id_of_interest(operand_id); - id_use_descriptor.mutable_enclosing_instruction() - ->set_target_instruction_opcode(inst.opcode()); - id_use_descriptor.mutable_enclosing_instruction() - ->set_base_instruction_result_id(base_instruction_result_id); - id_use_descriptor.mutable_enclosing_instruction() - ->set_num_opcodes_to_ignore( - skipped_opcode_count.find(inst.opcode()) == - skipped_opcode_count.end() - ? 0 - : skipped_opcode_count.at(inst.opcode())); - id_use_descriptor.set_in_operand_index(in_operand_index); - constant_uses->push_back(id_use_descriptor); - } break; - default: - break; - } -} - -void FuzzerPassObfuscateConstants::Apply() { - // First, gather up all the constant uses available in the module, by going - // through each block in each function. - std::vector constant_uses; - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // For each constant use we encounter we are going to make an id use - // descriptor. An id use is described with respect to a base instruction; - // if there are instructions at the start of the block without result ids, - // the base instruction will have to be the block's label. - uint32_t base_instruction_result_id = block.id(); - - // An id use descriptor also records how many instructions of a particular - // opcode need to be skipped in order to find the instruction of interest - // from the base instruction. We maintain a mapping that records a skip - // count for each relevant opcode. - std::map skipped_opcode_count; - - // Go through each instruction in the block. - for (auto& inst : block) { - if (inst.HasResultId()) { - // The instruction has a result id, so can be used as the base - // instruction from now on, until another instruction with a result id - // is encountered. - base_instruction_result_id = inst.result_id(); - // Opcode skip counts were with respect to the previous base - // instruction and are now irrelevant. - skipped_opcode_count.clear(); - } - - // The instruction must not be an OpVariable, the only id that an - // OpVariable uses is an initializer id, which has to remain - // constant. - if (inst.opcode() != SpvOpVariable) { - // Consider each operand of the instruction, and add a constant id - // use for the operand if relevant. - for (uint32_t in_operand_index = 0; - in_operand_index < inst.NumInOperands(); in_operand_index++) { - MaybeAddConstantIdUse(inst, in_operand_index, - base_instruction_result_id, - skipped_opcode_count, &constant_uses); - } - } - - if (!inst.HasResultId()) { - // The instruction has no result id, so in order to identify future id - // uses for instructions with this opcode from the existing base - // instruction, we need to increase the skip count for this opcode. - skipped_opcode_count[inst.opcode()] = - skipped_opcode_count.find(inst.opcode()) == - skipped_opcode_count.end() - ? 1 - : skipped_opcode_count[inst.opcode()] + 1; - } - } - } - } - - // Go through the constant uses in a random order by repeatedly pulling out a - // constant use at a random index. - while (!constant_uses.empty()) { - auto index = GetFuzzerContext()->RandomIndex(constant_uses); - auto constant_use = std::move(constant_uses[index]); - constant_uses.erase(constant_uses.begin() + index); - // Decide probabilistically whether to skip or obfuscate this constant use. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfObfuscatingConstant())) { - continue; - } - ObfuscateConstant(0, constant_use); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h deleted file mode 100644 index 52d8efe59..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_ -#define SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_ - -#include - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for turning uses of constants into more complex forms. -// Examples include replacing 'true' with '42 < 52', and replacing '42' with -// 'a.b.c' if 'a.b.c' is known to hold the value '42'. -class FuzzerPassObfuscateConstants : public FuzzerPass { - public: - FuzzerPassObfuscateConstants( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassObfuscateConstants() override; - - void Apply() override; - - private: - // Applies 0 or more transformations to potentially obfuscate the constant - // use represented by |constant_use|. The |depth| parameter controls how - // deeply obfuscation can recurse. - void ObfuscateConstant(uint32_t depth, - const protobufs::IdUseDescriptor& constant_use); - - // This method will try to turn |constant_use|, required to be a use of a - // boolean constant, into a binary expression on scalar constants, which may - // themselves be recursively obfuscated. - void ObfuscateBoolConstant(uint32_t depth, - const protobufs::IdUseDescriptor& constant_use); - - // This method will try to turn |constant_use|, required to be a use of a - // scalar constant, into the value loaded from a uniform known to have the - // same value as the constant (if one exists). - void ObfuscateScalarConstant(uint32_t depth, - const protobufs::IdUseDescriptor& constant_use); - - // Applies a transformation to replace the boolean constant usage represented - // by |bool_constant_use| with a binary expression involving - // |float_constant_id_1| and |float_constant_id_2|, which must not be equal - // to one another. Possibly further obfuscates the uses of these float - // constants. The |depth| parameter controls how deeply obfuscation can - // recurse. - void ObfuscateBoolConstantViaFloatConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - uint32_t float_constant_id_1, uint32_t float_constant_id_2); - - // Similar to the above, but for signed int constants. - void ObfuscateBoolConstantViaSignedIntConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - uint32_t signed_int_constant_id_1, uint32_t signed_int_constant_id_2); - - // Similar to the above, but for unsigned int constants. - void ObfuscateBoolConstantViaUnsignedIntConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - uint32_t unsigned_int_constant_id_1, uint32_t unsigned_int_constant_id_2); - - // A helper method to capture the common parts of the above methods. - // The method is used to obfuscate the boolean constant usage represented by - // |bool_constant_use| by replacing it with '|constant_id_1| OP - // |constant_id_2|', where 'OP' is chosen from either |greater_than_opcodes| - // or |less_than_opcodes|. - // - // The two constant ids must not represent the same value, and thus - // |greater_than_opcodes| may include 'greater than or equal' opcodes - // (similar for |less_than_opcodes|). - void ObfuscateBoolConstantViaConstantPair( - uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, - const std::vector& greater_than_opcodes, - const std::vector& less_than_opcodes, uint32_t constant_id_1, - uint32_t constant_id_2, bool first_constant_is_larger); - - // A helper method to determine whether input operand |in_operand_index| of - // |inst| is the id of a constant, and add an id use descriptor to - // |candidate_constant_uses| if so. The other parameters are used for id use - // descriptor construction. - void MaybeAddConstantIdUse( - const opt::Instruction& inst, uint32_t in_operand_index, - uint32_t base_instruction_result_id, - const std::map& skipped_opcode_count, - std::vector* constant_uses); - - // Returns a vector of unique words that denote constants. Every such constant - // is used in |FactConstantUniform| and has type with id equal to |type_id|. - std::vector> GetConstantWordsFromUniformsForType( - uint32_t type_id); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp deleted file mode 100644 index 3bd0a9f57..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_outline_functions.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_outline_function.h" -#include "source/fuzz/transformation_split_block.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassOutlineFunctions::FuzzerPassOutlineFunctions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassOutlineFunctions::~FuzzerPassOutlineFunctions() = default; - -void FuzzerPassOutlineFunctions::Apply() { - std::vector original_functions; - for (auto& function : *GetIRContext()->module()) { - original_functions.push_back(&function); - } - for (auto& function : original_functions) { - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfOutliningFunction())) { - continue; - } - std::vector blocks; - for (auto& block : *function) { - blocks.push_back(&block); - } - auto entry_block = MaybeGetEntryBlockSuitableForOutlining( - blocks[GetFuzzerContext()->RandomIndex(blocks)]); - - if (!entry_block) { - // The chosen block is not suitable to be the entry block of a region that - // will be outlined. - continue; - } - - auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(function); - auto postdominator_analysis = - GetIRContext()->GetPostDominatorAnalysis(function); - std::vector candidate_exit_blocks; - for (auto postdominates_entry_block = entry_block; - postdominates_entry_block != nullptr; - postdominates_entry_block = postdominator_analysis->ImmediateDominator( - postdominates_entry_block)) { - // Consider the block if it is dominated by the entry block, ignore it if - // it is a continue target. - if (dominator_analysis->Dominates(entry_block, - postdominates_entry_block) && - !GetIRContext()->GetStructuredCFGAnalysis()->IsContinueBlock( - postdominates_entry_block->id())) { - candidate_exit_blocks.push_back(postdominates_entry_block); - } - } - if (candidate_exit_blocks.empty()) { - continue; - } - auto exit_block = MaybeGetExitBlockSuitableForOutlining( - candidate_exit_blocks[GetFuzzerContext()->RandomIndex( - candidate_exit_blocks)]); - - if (!exit_block) { - // The block chosen is not suitable - continue; - } - - auto region_blocks = TransformationOutlineFunction::GetRegionBlocks( - GetIRContext(), entry_block, exit_block); - std::map input_id_to_fresh_id; - for (auto id : TransformationOutlineFunction::GetRegionInputIds( - GetIRContext(), region_blocks, exit_block)) { - input_id_to_fresh_id[id] = GetFuzzerContext()->GetFreshId(); - } - std::map output_id_to_fresh_id; - for (auto id : TransformationOutlineFunction::GetRegionOutputIds( - GetIRContext(), region_blocks, exit_block)) { - output_id_to_fresh_id[id] = GetFuzzerContext()->GetFreshId(); - } - TransformationOutlineFunction transformation( - entry_block->id(), exit_block->id(), - /*new_function_struct_return_type_id*/ - GetFuzzerContext()->GetFreshId(), - /*new_function_type_id*/ GetFuzzerContext()->GetFreshId(), - /*new_function_id*/ GetFuzzerContext()->GetFreshId(), - /*new_function_region_entry_block*/ - GetFuzzerContext()->GetFreshId(), - /*new_caller_result_id*/ GetFuzzerContext()->GetFreshId(), - /*new_callee_result_id*/ GetFuzzerContext()->GetFreshId(), - /*input_id_to_fresh_id*/ std::move(input_id_to_fresh_id), - /*output_id_to_fresh_id*/ std::move(output_id_to_fresh_id)); - MaybeApplyTransformation(transformation); - } -} - -opt::BasicBlock* -FuzzerPassOutlineFunctions::MaybeGetEntryBlockSuitableForOutlining( - opt::BasicBlock* entry_block) { - // If the entry block is a loop header, we need to get or create its - // preheader and make it the entry block, if possible. - if (entry_block->IsLoopHeader()) { - auto predecessors = - GetIRContext()->cfg()->preds(entry_block->GetLabel()->result_id()); - - if (predecessors.size() < 2) { - // The header only has one predecessor (the back-edge block) and thus - // it is unreachable. The block cannot be adjusted to be suitable for - // outlining. - return nullptr; - } - - // Get or create a suitable preheader and make it become the entry block. - entry_block = - GetOrCreateSimpleLoopPreheader(entry_block->GetLabel()->result_id()); - } - - assert(!entry_block->IsLoopHeader() && - "The entry block cannot be a loop header at this point."); - - // If the entry block starts with OpPhi or OpVariable, try to split it. - if (entry_block->begin()->opcode() == SpvOpPhi || - entry_block->begin()->opcode() == SpvOpVariable) { - // Find the first non-OpPhi and non-OpVariable instruction. - auto non_phi_or_var_inst = &*entry_block->begin(); - while (non_phi_or_var_inst->opcode() == SpvOpPhi || - non_phi_or_var_inst->opcode() == SpvOpVariable) { - non_phi_or_var_inst = non_phi_or_var_inst->NextNode(); - } - - // Split the block. - uint32_t new_block_id = GetFuzzerContext()->GetFreshId(); - ApplyTransformation(TransformationSplitBlock( - MakeInstructionDescriptor(GetIRContext(), non_phi_or_var_inst), - new_block_id)); - - // The new entry block is the newly-created block. - entry_block = &*entry_block->GetParent()->FindBlock(new_block_id); - } - - return entry_block; -} - -opt::BasicBlock* -FuzzerPassOutlineFunctions::MaybeGetExitBlockSuitableForOutlining( - opt::BasicBlock* exit_block) { - // The exit block must not be a continue target. - assert(!GetIRContext()->GetStructuredCFGAnalysis()->IsContinueBlock( - exit_block->id()) && - "A candidate exit block cannot be a continue target."); - - // If the exit block is a merge block, try to split it and return the second - // block in the pair as the exit block. - if (GetIRContext()->GetStructuredCFGAnalysis()->IsMergeBlock( - exit_block->id())) { - uint32_t new_block_id = GetFuzzerContext()->GetFreshId(); - - // Find the first non-OpPhi instruction, after which to split. - auto split_before = &*exit_block->begin(); - while (split_before->opcode() == SpvOpPhi) { - split_before = split_before->NextNode(); - } - - if (!MaybeApplyTransformation(TransformationSplitBlock( - MakeInstructionDescriptor(GetIRContext(), split_before), - new_block_id))) { - return nullptr; - } - - return &*exit_block->GetParent()->FindBlock(new_block_id); - } - - return exit_block; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h deleted file mode 100644 index 02022aa7c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_OUTLINE_FUNCTIONS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_OUTLINE_FUNCTIONS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for outlining single-entry single-exit regions of a control -// 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(); - - void Apply() override; - - // Returns a block suitable to be an entry block for a region that can be - // outlined, i.e. a block that is not a loop header and that does not start - // with OpPhi or OpVariable. In particular, it returns: - // - |entry_block| if it is suitable - // - otherwise, a block found by: - // - looking for or creating a new preheader, if |entry_block| is a loop - // header - // - splitting the candidate entry block, if it starts with OpPhi or - // OpVariable. - // Returns nullptr if a suitable block cannot be found following the - // instructions above. - opt::BasicBlock* MaybeGetEntryBlockSuitableForOutlining( - opt::BasicBlock* entry_block); - - // Returns: - // - |exit_block| if it is not a merge block - // - the second block obtained by splitting |exit_block|, if |exit_block| is a - // merge block. - // Assumes that |exit_block| is not a continue target. - // The block returned by this function should be suitable to be the exit block - // of a region that can be outlined. - // Returns nullptr if |exit_block| is a merge block and it cannot be split. - opt::BasicBlock* MaybeGetExitBlockSuitableForOutlining( - opt::BasicBlock* exit_block); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_OUTLINE_FUNCTIONS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp deleted file mode 100644 index 24c16fbbb..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_permute_blocks.h" - -#include "source/fuzz/transformation_move_block_down.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassPermuteBlocks::~FuzzerPassPermuteBlocks() = default; - -void FuzzerPassPermuteBlocks::Apply() { - // For now we do something very simple: we randomly decide whether to move a - // block, and for each block that we do move, we push it down as far as we - // legally can. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2635): it would be - // nice to randomly sample from the set of legal block permutations and then - // encode the chosen permutation via a series of move-block-down - // transformations. This should be possible but will require some thought. - - for (auto& function : *GetIRContext()->module()) { - std::vector block_ids; - // Collect all block ids for the function before messing with block - // ordering. - for (auto& block : function) { - block_ids.push_back(block.id()); - } - // Now consider each block id. We consider block ids in reverse, because - // e.g. in code generated from the following: - // - // if (...) { - // A - // B - // } else { - // C - // } - // - // block A cannot be moved down, but B has freedom to move and that movement - // would provide more freedom for A to move. - for (auto id = block_ids.rbegin(); id != block_ids.rend(); ++id) { - // Randomly decide whether to ignore the block id. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfMovingBlockDown())) { - continue; - } - // Keep pushing the block down, until pushing down fails. - // The loop is guaranteed to terminate because a block cannot be pushed - // down indefinitely. - while (true) { - TransformationMoveBlockDown transformation(*id); - if (!MaybeApplyTransformation(transformation)) { - break; - } - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h deleted file mode 100644 index f2d3b398b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ -#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for shuffling the blocks of the module in a validity-preserving -// manner. -class FuzzerPassPermuteBlocks : public FuzzerPass { - public: - FuzzerPassPermuteBlocks(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassPermuteBlocks() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.cpp deleted file mode 100644 index e15aef6e4..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_context.h" -#include "source/fuzz/fuzzer_pass_permute_function_parameters.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_permute_function_parameters.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassPermuteFunctionParameters::FuzzerPassPermuteFunctionParameters( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassPermuteFunctionParameters::~FuzzerPassPermuteFunctionParameters() = - default; - -void FuzzerPassPermuteFunctionParameters::Apply() { - for (const auto& function : *GetIRContext()->module()) { - uint32_t function_id = function.result_id(); - - // Skip the function if it is an entry point - if (fuzzerutil::FunctionIsEntryPoint(GetIRContext(), function_id)) { - continue; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfPermutingParameters())) { - continue; - } - - // Compute permutation for parameters - auto* function_type = - fuzzerutil::GetFunctionType(GetIRContext(), &function); - assert(function_type && "Function type is null"); - - // Don't take return type into account - uint32_t arg_size = function_type->NumInOperands() - 1; - - // Create a vector, fill it with [0, n-1] values and shuffle it - std::vector permutation(arg_size); - std::iota(permutation.begin(), permutation.end(), 0); - GetFuzzerContext()->Shuffle(&permutation); - - // Apply our transformation - ApplyTransformation(TransformationPermuteFunctionParameters( - function_id, GetFuzzerContext()->GetFreshId(), permutation)); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.h deleted file mode 100644 index bc1031cbb..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_function_parameters.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_PERMUTE_FUNCTION_PARAMETERS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_FUNCTION_PARAMETERS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Fuzzer pass that, given a non-entry-point function taking n parameters -// and a permutation of the set [0, n - 1]: -// 1. Introduces a new function type that is the same as the original -// function's type but with the order of arguments permuted -// (only add this if it doesn't already exist) -// 2. Changes the type of the function to this type -// 3. Adjusts all calls to the function so that their arguments are permuted -class FuzzerPassPermuteFunctionParameters : public FuzzerPass { - public: - FuzzerPassPermuteFunctionParameters( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassPermuteFunctionParameters() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_FUNCTION_PARAMETERS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.cpp deleted file mode 100644 index 6867053c6..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_permute_instructions.h" - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_move_instruction_down.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassPermuteInstructions::FuzzerPassPermuteInstructions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassPermuteInstructions::~FuzzerPassPermuteInstructions() = default; - -void FuzzerPassPermuteInstructions::Apply() { - // We are iterating over all instructions in all basic blocks. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // We need to collect all instructions in the block into a separate vector - // since application of the transformation below might invalidate - // iterators. - std::vector instructions; - for (auto& instruction : block) { - instructions.push_back(&instruction); - } - - // We consider all instructions in reverse to increase the possible number - // of applied transformations. - for (auto it = instructions.rbegin(); it != instructions.rend(); ++it) { - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfPermutingInstructions())) { - continue; - } - - while (MaybeApplyTransformation(TransformationMoveInstructionDown( - MakeInstructionDescriptor(GetIRContext(), *it)))) { - // Apply the transformation as many times as possible. - } - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.h deleted file mode 100644 index e02ddfae0..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_instructions.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_PERMUTE_INSTRUCTIONS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_INSTRUCTIONS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Permutes instructions in every block of all while preserving the module's -// semantics. -class FuzzerPassPermuteInstructions : public FuzzerPass { - public: - FuzzerPassPermuteInstructions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassPermuteInstructions() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_INSTRUCTIONS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.cpp deleted file mode 100644 index c241d9d3d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_context.h" -#include "source/fuzz/fuzzer_pass_permute_phi_operands.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_permute_phi_operands.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassPermutePhiOperands::FuzzerPassPermutePhiOperands( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassPermutePhiOperands::~FuzzerPassPermutePhiOperands() = default; - -void FuzzerPassPermutePhiOperands::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& /*unused*/) { - const auto& inst = *inst_it; - - if (inst.opcode() != SpvOpPhi) { - return; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfPermutingPhiOperands())) { - return; - } - - // Create a vector of indices for each pair of operands in the |inst|. - // OpPhi always has an even number of operands. - std::vector permutation(inst.NumInOperands() / 2); - std::iota(permutation.begin(), permutation.end(), 0); - GetFuzzerContext()->Shuffle(&permutation); - - ApplyTransformation(TransformationPermutePhiOperands( - inst.result_id(), std::move(permutation))); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.h deleted file mode 100644 index 974c2c1e7..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_phi_operands.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_PERMUTE_PHI_OPERANDS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_PHI_OPERANDS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Iterates over all instructions in the module and randomly decides for each -// OpPhi instruction whether to permute its operands. -class FuzzerPassPermutePhiOperands : public FuzzerPass { - public: - FuzzerPassPermutePhiOperands( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassPermutePhiOperands() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_PHI_OPERANDS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp deleted file mode 100644 index 2042d7c2c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_propagate_instructions_up.h" - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_propagate_instruction_up.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassPropagateInstructionsUp::FuzzerPassPropagateInstructionsUp( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassPropagateInstructionsUp::~FuzzerPassPropagateInstructionsUp() = - default; - -void FuzzerPassPropagateInstructionsUp::Apply() { - for (const auto& function : *GetIRContext()->module()) { - for (const auto& block : function) { - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfPropagatingInstructionsUp())) { - continue; - } - - if (TransformationPropagateInstructionUp::IsApplicableToBlock( - GetIRContext(), block.id())) { - std::map fresh_ids; - for (auto id : GetIRContext()->cfg()->preds(block.id())) { - auto& fresh_id = fresh_ids[id]; - - if (!fresh_id) { - // Create a fresh id if it hasn't been created yet. |fresh_id| will - // be default-initialized to 0 in this case. - fresh_id = GetFuzzerContext()->GetFreshId(); - } - } - - ApplyTransformation( - TransformationPropagateInstructionUp(block.id(), fresh_ids)); - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.h deleted file mode 100644 index d915b31eb..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_propagate_instructions_up.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_PROPAGATE_INSTRUCTIONS_UP_H_ -#define SOURCE_FUZZ_FUZZER_PASS_PROPAGATE_INSTRUCTIONS_UP_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Decides whether to propagate instructions from some block into its -// predecessors. -class FuzzerPassPropagateInstructionsUp : public FuzzerPass { - public: - FuzzerPassPropagateInstructionsUp( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassPropagateInstructionsUp() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_PROPAGATE_INSTRUCTIONS_UP_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp deleted file mode 100644 index 8d9acaa01..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_push_ids_through_variables.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_push_id_through_variable.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassPushIdsThroughVariables::FuzzerPassPushIdsThroughVariables( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassPushIdsThroughVariables::~FuzzerPassPushIdsThroughVariables() = - default; - -void FuzzerPassPushIdsThroughVariables::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* function, opt::BasicBlock* block, - opt::BasicBlock::iterator instruction_iterator, - const protobufs::InstructionDescriptor& instruction_descriptor) - -> void { - assert(instruction_iterator->opcode() == - instruction_descriptor.target_instruction_opcode() && - "The opcode of the instruction we might insert before must be " - "the same as the opcode in the descriptor for the instruction"); - - // Randomly decide whether to try pushing an id through a variable. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfPushingIdThroughVariable())) { - return; - } - - // The block containing the instruction we are going to insert before - // must be reachable. - if (!fuzzerutil::BlockIsReachableInItsFunction(GetIRContext(), block)) { - return; - } - - // It must be valid to insert OpStore and OpLoad instructions - // before the instruction to insert before. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpStore, instruction_iterator) || - !fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpLoad, instruction_iterator)) { - return; - } - - // Randomly decides whether a global or local variable will be added. - auto variable_storage_class = GetFuzzerContext()->ChooseEven() - ? SpvStorageClassPrivate - : SpvStorageClassFunction; - - // Gets the available basic and pointer types. - auto basic_type_ids_and_pointers = - GetAvailableBasicTypesAndPointers(variable_storage_class); - auto& basic_types = basic_type_ids_and_pointers.first; - uint32_t basic_type_id = - basic_types[GetFuzzerContext()->RandomIndex(basic_types)]; - - // Looks for ids that we might wish to consider pushing through a - // variable. - std::vector value_instructions = - FindAvailableInstructions( - function, block, instruction_iterator, - [this, basic_type_id, instruction_descriptor]( - opt::IRContext* ir_context, - opt::Instruction* instruction) -> bool { - if (!instruction->result_id() || !instruction->type_id()) { - return false; - } - - if (instruction->type_id() != basic_type_id) { - return false; - } - - // 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. - if (!GetTransformationContext() - ->GetFactManager() - ->IdIsIrrelevant(instruction->result_id()) && - !fuzzerutil::CanMakeSynonymOf(ir_context, - *GetTransformationContext(), - instruction)) { - return false; - } - - return fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, - FindInstruction(instruction_descriptor, ir_context), - instruction->result_id()); - }); - - if (value_instructions.empty()) { - return; - } - - // If the pointer type does not exist, then create it. - FindOrCreatePointerType(basic_type_id, variable_storage_class); - - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403): - // type support here is limited by the FindOrCreateZeroConstant - // function. - const auto* type_inst = - GetIRContext()->get_def_use_mgr()->GetDef(basic_type_id); - assert(type_inst); - switch (type_inst->opcode()) { - case SpvOpTypeBool: - case SpvOpTypeFloat: - case SpvOpTypeInt: - case SpvOpTypeArray: - case SpvOpTypeMatrix: - case SpvOpTypeVector: - case SpvOpTypeStruct: - break; - default: - return; - } - - // Create a constant to initialize the variable from. This might update - // module's id bound so it must be done before any fresh ids are - // computed. - auto initializer_id = FindOrCreateZeroConstant(basic_type_id, false); - - // Applies the push id through variable transformation. - ApplyTransformation(TransformationPushIdThroughVariable( - value_instructions[GetFuzzerContext()->RandomIndex( - value_instructions)] - ->result_id(), - GetFuzzerContext()->GetFreshId(), GetFuzzerContext()->GetFreshId(), - variable_storage_class, initializer_id, instruction_descriptor)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.h deleted file mode 100644 index 3ad540428..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_push_ids_through_variables.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_PUSH_IDS_THROUGH_VARIABLES_H_ -#define SOURCE_FUZZ_FUZZER_PASS_PUSH_IDS_THROUGH_VARIABLES_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Adds instructions to the module that store existing ids into fresh variables -// and immediately load from said variables into new ids, thus creating synonyms -// between the existing and fresh ids. -class FuzzerPassPushIdsThroughVariables : public FuzzerPass { - public: - FuzzerPassPushIdsThroughVariables( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassPushIdsThroughVariables() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_PUSH_IDS_THROUGH_VARIABLES_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp deleted file mode 100644 index 139dc6e2f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h" - -namespace spvtools { -namespace fuzz { - -namespace { -const uint32_t kArithmeticInstructionIndexLeftInOperand = 0; -} // namespace - -FuzzerPassReplaceAddsSubsMulsWithCarryingExtended:: - FuzzerPassReplaceAddsSubsMulsWithCarryingExtended( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassReplaceAddsSubsMulsWithCarryingExtended:: - ~FuzzerPassReplaceAddsSubsMulsWithCarryingExtended() = default; - -void FuzzerPassReplaceAddsSubsMulsWithCarryingExtended::Apply() { - std::vector instructions_for_transformation; - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - for (auto& instruction : block) { - // Randomly decide whether to apply the transformation. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfReplacingAddSubMulWithCarryingExtended())) { - continue; - } - - // Check if the transformation can be applied to this instruction. - if (!TransformationReplaceAddSubMulWithCarryingExtended:: - IsInstructionSuitable(GetIRContext(), instruction)) { - continue; - } - instructions_for_transformation.push_back(instruction); - } - } - } - for (auto& instruction : instructions_for_transformation) { - // Get the operand type id. We know that both operands have the same - // type. - uint32_t operand_type_id = - GetIRContext() - ->get_def_use_mgr() - ->GetDef(instruction.GetSingleWordInOperand( - kArithmeticInstructionIndexLeftInOperand)) - ->type_id(); - - // Ensure the required struct type exists. The struct type is based on - // the operand type. - FindOrCreateStructType({operand_type_id, operand_type_id}); - - ApplyTransformation(TransformationReplaceAddSubMulWithCarryingExtended( - GetFuzzerContext()->GetFreshId(), instruction.result_id())); - } -} -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h deleted file mode 100644 index f224d2bc3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_FUZZER_PASS_REPLACE_ADDS_SUBS_MULS_WITH_CARRYING_EXTENDED_H -#define SPIRV_TOOLS_FUZZER_PASS_REPLACE_ADDS_SUBS_MULS_WITH_CARRYING_EXTENDED_H - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass that replaces instructions OpIAdd, OpISub, OpIMul with pairs of -// instructions. The first one (OpIAddCarry, OpISubBorrow, OpUMulExtended, -// OpSMulExtended) computes the result into a struct. The second one extracts -// the appropriate component from the struct to yield the original result. -class FuzzerPassReplaceAddsSubsMulsWithCarryingExtended : public FuzzerPass { - public: - FuzzerPassReplaceAddsSubsMulsWithCarryingExtended( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassReplaceAddsSubsMulsWithCarryingExtended() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_FUZZER_PASS_REPLACE_ADDS_SUBS_MULS_WITH_CARRYING_EXTENDED_H diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp deleted file mode 100644 index 684714666..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_replace_copy_memory_with_load_store.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassReplaceCopyMemoriesWithLoadsStores:: - FuzzerPassReplaceCopyMemoriesWithLoadsStores( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassReplaceCopyMemoriesWithLoadsStores:: - ~FuzzerPassReplaceCopyMemoriesWithLoadsStores() = default; - -void FuzzerPassReplaceCopyMemoriesWithLoadsStores::Apply() { - GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { - // Randomly decide whether to replace the OpCopyMemory. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfReplacingCopyMemoryWithLoadStore())) { - return; - } - - // The instruction must be OpCopyMemory. - if (instruction->opcode() != SpvOpCopyMemory) { - return; - } - - // Apply the transformation replacing OpCopyMemory with OpLoad and OpStore. - ApplyTransformation(TransformationReplaceCopyMemoryWithLoadStore( - GetFuzzerContext()->GetFreshId(), - MakeInstructionDescriptor(GetIRContext(), instruction))); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h deleted file mode 100644 index 2a890064b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_FUZZER_PASS_REPLACE_COPY_MEMORIES_WITH_LOADS_STORES_H -#define SPIRV_TOOLS_FUZZER_PASS_REPLACE_COPY_MEMORIES_WITH_LOADS_STORES_H - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Replaces instructions OpCopyMemory with loading the source variable to -// an intermediate value and storing this value into the target variable of -// the original OpCopyMemory instruction. -class FuzzerPassReplaceCopyMemoriesWithLoadsStores : public FuzzerPass { - public: - FuzzerPassReplaceCopyMemoriesWithLoadsStores( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassReplaceCopyMemoriesWithLoadsStores() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_FUZZER_PASS_REPLACE_COPY_MEMORIES_WITH_LOADS_STORES_H diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp deleted file mode 100644 index 4c455a749..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_replace_copy_object_with_store_load.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassReplaceCopyObjectsWithStoresLoads:: - FuzzerPassReplaceCopyObjectsWithStoresLoads( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassReplaceCopyObjectsWithStoresLoads:: - ~FuzzerPassReplaceCopyObjectsWithStoresLoads() = default; - -void FuzzerPassReplaceCopyObjectsWithStoresLoads::Apply() { - GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { - // Randomly decide whether to replace OpCopyObject. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfReplacingCopyObjectWithStoreLoad())) { - return; - } - // The instruction must be OpCopyObject. - if (instruction->opcode() != SpvOpCopyObject) { - return; - } - // The opcode of the type_id instruction cannot be a OpTypePointer, - // because we cannot define a pointer to pointer. - if (GetIRContext() - ->get_def_use_mgr() - ->GetDef(instruction->type_id()) - ->opcode() == SpvOpTypePointer) { - return; - } - // It must be valid to insert OpStore and OpLoad instructions - // before the instruction OpCopyObject. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, - instruction) || - !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, instruction)) { - return; - } - - // Randomly decides whether a global or local variable will be added. - auto variable_storage_class = GetFuzzerContext()->ChooseEven() - ? SpvStorageClassPrivate - : SpvStorageClassFunction; - - // Find or create a constant to initialize the variable from. The type of - // |instruction| must be such that the function FindOrCreateConstant can be - // called. - auto instruction_type = - GetIRContext()->get_type_mgr()->GetType(instruction->type_id()); - if (!CanFindOrCreateZeroConstant(*instruction_type)) { - return; - } - auto variable_initializer_id = - FindOrCreateZeroConstant(instruction->type_id(), false); - - // Make sure that pointer type is defined. - FindOrCreatePointerType(instruction->type_id(), variable_storage_class); - // Apply the transformation replacing OpCopyObject with Store and Load. - ApplyTransformation(TransformationReplaceCopyObjectWithStoreLoad( - instruction->result_id(), GetFuzzerContext()->GetFreshId(), - variable_storage_class, variable_initializer_id)); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h deleted file mode 100644 index 15ec10b0c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_FUZZER_PASS_REPLACE_COPY_OBJECTS_WITH_STORES_LOADS_H -#define SPIRV_TOOLS_FUZZER_PASS_REPLACE_COPY_OBJECTS_WITH_STORES_LOADS_H - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Replaces instructions OpCopyObject with storing into a new variable -// and immediately loading this variable to |result_id| of the -// original OpCopyObject instruction. -class FuzzerPassReplaceCopyObjectsWithStoresLoads : public FuzzerPass { - public: - FuzzerPassReplaceCopyObjectsWithStoresLoads( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassReplaceCopyObjectsWithStoresLoads() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_FUZZER_PASS_REPLACE_COPY_OBJECTS_WITH_STORES_LOADS_H diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp deleted file mode 100644 index c3e65789e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_replace_linear_algebra_instructions.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_replace_linear_algebra_instruction.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassReplaceLinearAlgebraInstructions:: - FuzzerPassReplaceLinearAlgebraInstructions( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassReplaceLinearAlgebraInstructions:: - ~FuzzerPassReplaceLinearAlgebraInstructions() = default; - -void FuzzerPassReplaceLinearAlgebraInstructions::Apply() { - // For each instruction, checks whether it is a linear algebra instruction. In - // this case, the transformation is randomly applied. - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - for (auto& instruction : block) { - if (!spvOpcodeIsLinearAlgebra(instruction.opcode())) { - continue; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfReplacingLinearAlgebraInstructions())) { - continue; - } - - ApplyTransformation(TransformationReplaceLinearAlgebraInstruction( - GetFuzzerContext()->GetFreshIds( - TransformationReplaceLinearAlgebraInstruction:: - GetRequiredFreshIdCount(GetIRContext(), &instruction)), - MakeInstructionDescriptor(GetIRContext(), &instruction))); - } - } - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h deleted file mode 100644 index 2c6126cd1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_REPLACE_LINEAR_ALGEBRA_INSTRUCTIONS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_REPLACE_LINEAR_ALGEBRA_INSTRUCTIONS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// This fuzzer pass replaces linear algebra instructions with its mathematical -// definition. -class FuzzerPassReplaceLinearAlgebraInstructions : public FuzzerPass { - public: - FuzzerPassReplaceLinearAlgebraInstructions( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassReplaceLinearAlgebraInstructions(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_REPLACE_LINEAR_ALGEBRA_INSTRUCTIONS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp deleted file mode 100644 index 7690ac41a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_replace_load_store_with_copy_memory.h" -#include "source/opt/instruction.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassReplaceLoadsStoresWithCopyMemories:: - FuzzerPassReplaceLoadsStoresWithCopyMemories( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassReplaceLoadsStoresWithCopyMemories:: - ~FuzzerPassReplaceLoadsStoresWithCopyMemories() = default; - -void FuzzerPassReplaceLoadsStoresWithCopyMemories::Apply() { - // We look for matching pairs of instructions OpLoad and - // OpStore within the same block. Potential instructions OpLoad to be matched - // are stored in a hash map. If we encounter instructions that write to memory - // or instructions of memory barriers that could operate on variables within - // unsafe storage classes we need to erase the hash map to avoid unsafe - // operations. - - // A vector of matching OpLoad and OpStore instructions. - std::vector> - op_load_store_pairs; - - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - // A hash map storing potential OpLoad instructions. - std::unordered_map current_op_loads; - for (auto& instruction : block) { - // Add a potential OpLoad instruction. - if (instruction.opcode() == SpvOpLoad) { - current_op_loads[instruction.result_id()] = &instruction; - } else if (instruction.opcode() == SpvOpStore) { - if (current_op_loads.find(instruction.GetSingleWordOperand(1)) != - current_op_loads.end()) { - // We have found the matching OpLoad instruction to the current - // OpStore instruction. - op_load_store_pairs.push_back(std::make_pair( - current_op_loads[instruction.GetSingleWordOperand(1)], - &instruction)); - } - } - if (TransformationReplaceLoadStoreWithCopyMemory::IsMemoryWritingOpCode( - instruction.opcode())) { - current_op_loads.clear(); - } else if (TransformationReplaceLoadStoreWithCopyMemory:: - IsMemoryBarrierOpCode(instruction.opcode())) { - for (auto it = current_op_loads.begin(); - it != current_op_loads.end();) { - // Get the storage class. - opt::Instruction* source_id = - GetIRContext()->get_def_use_mgr()->GetDef( - it->second->GetSingleWordOperand(2)); - SpvStorageClass storage_class = - fuzzerutil::GetStorageClassFromPointerType( - GetIRContext(), source_id->type_id()); - if (!TransformationReplaceLoadStoreWithCopyMemory:: - IsStorageClassSafeAcrossMemoryBarriers(storage_class)) { - it = current_op_loads.erase(it); - } else { - it++; - } - } - } - } - } - } - for (auto instr_pair : op_load_store_pairs) { - // Randomly decide to apply the transformation for the - // potential pairs. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfReplacingLoadStoreWithCopyMemory())) { - ApplyTransformation(TransformationReplaceLoadStoreWithCopyMemory( - MakeInstructionDescriptor(GetIRContext(), instr_pair.first), - MakeInstructionDescriptor(GetIRContext(), instr_pair.second))); - } - } -} // namespace fuzz -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h deleted file mode 100644 index db09500c5..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_FUZZER_PASS_REPLACE_LOADS_STORES_WITH_COPY_MEMORIES_H -#define SPIRV_TOOLS_FUZZER_PASS_REPLACE_LOADS_STORES_WITH_COPY_MEMORIES_H - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass that takes pairs of instruction descriptors to OpLoad and -// OpStore that have the same intermediate value and in each pair replaces the -// OpStore with an equivalent OpCopyMemory. -class FuzzerPassReplaceLoadsStoresWithCopyMemories : public FuzzerPass { - public: - FuzzerPassReplaceLoadsStoresWithCopyMemories( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassReplaceLoadsStoresWithCopyMemories() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_FUZZER_PASS_REPLACE_LOADS_STORES_WITH_COPY_MEMORIES_H diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp deleted file mode 100644 index 8672a3bbe..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_replace_parameter_with_global.h" - -#include -#include - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_replace_parameter_with_global.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassReplaceParameterWithGlobal::FuzzerPassReplaceParameterWithGlobal( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassReplaceParameterWithGlobal::~FuzzerPassReplaceParameterWithGlobal() = - default; - -void FuzzerPassReplaceParameterWithGlobal::Apply() { - for (const auto& function : *GetIRContext()->module()) { - if (fuzzerutil::FunctionIsEntryPoint(GetIRContext(), - function.result_id())) { - continue; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfReplacingParametersWithGlobals())) { - continue; - } - - auto params = - fuzzerutil::GetParameters(GetIRContext(), function.result_id()); - - // Make sure at least one parameter can be replaced. Also checks that the - // function has at least one parameter. - if (std::none_of(params.begin(), params.end(), - [this](const opt::Instruction* param) { - const auto* param_type = - GetIRContext()->get_type_mgr()->GetType( - param->type_id()); - assert(param_type && "Parameter has invalid type"); - return TransformationReplaceParameterWithGlobal:: - IsParameterTypeSupported(*param_type); - })) { - continue; - } - - // Select id of a parameter to replace. - const opt::Instruction* replaced_param = nullptr; - const opt::analysis::Type* param_type = nullptr; - do { - replaced_param = GetFuzzerContext()->RemoveAtRandomIndex(¶ms); - param_type = - GetIRContext()->get_type_mgr()->GetType(replaced_param->type_id()); - assert(param_type && "Parameter has invalid type"); - } while ( - !TransformationReplaceParameterWithGlobal::IsParameterTypeSupported( - *param_type)); - - assert(replaced_param && "Unable to find a parameter to replace"); - - // Make sure type id for the global variable exists in the module. - FindOrCreatePointerType(replaced_param->type_id(), SpvStorageClassPrivate); - - // Make sure initializer for the global variable exists in the module. - FindOrCreateZeroConstant(replaced_param->type_id(), false); - - ApplyTransformation(TransformationReplaceParameterWithGlobal( - GetFuzzerContext()->GetFreshId(), replaced_param->result_id(), - GetFuzzerContext()->GetFreshId())); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h deleted file mode 100644 index 25011bdca..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_REPLACE_PARAMETER_WITH_GLOBAL_H_ -#define SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMETER_WITH_GLOBAL_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Iterates over all non-entry-point functions in the module and randomly -// replaces a parameter with a global variable. -class FuzzerPassReplaceParameterWithGlobal : public FuzzerPass { - public: - FuzzerPassReplaceParameterWithGlobal( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassReplaceParameterWithGlobal() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMETER_WITH_GLOBAL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp deleted file mode 100644 index 86d6d06be..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_replace_params_with_struct.h" - -#include -#include - -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_replace_params_with_struct.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassReplaceParamsWithStruct::FuzzerPassReplaceParamsWithStruct( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassReplaceParamsWithStruct::~FuzzerPassReplaceParamsWithStruct() = - default; - -void FuzzerPassReplaceParamsWithStruct::Apply() { - for (const auto& function : *GetIRContext()->module()) { - auto params = - fuzzerutil::GetParameters(GetIRContext(), function.result_id()); - - if (params.empty() || fuzzerutil::FunctionIsEntryPoint( - GetIRContext(), function.result_id())) { - continue; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfReplacingParametersWithStruct())) { - continue; - } - - std::vector parameter_index(params.size()); - std::iota(parameter_index.begin(), parameter_index.end(), 0); - - // Remove the indices of unsupported parameters. - auto new_end = std::remove_if( - parameter_index.begin(), parameter_index.end(), - [this, ¶ms](uint32_t index) { - const auto* type = - GetIRContext()->get_type_mgr()->GetType(params[index]->type_id()); - assert(type && "Parameter has invalid type"); - return !TransformationReplaceParamsWithStruct:: - IsParameterTypeSupported(*type); - }); - - // std::remove_if changes the vector so that removed elements are placed at - // the end (i.e. [new_end, parameter_index.end()) is a range of removed - // elements). However, the size of the vector is not changed so we need to - // change that explicitly by popping those elements from the vector. - parameter_index.erase(new_end, parameter_index.end()); - - if (parameter_index.empty()) { - continue; - } - - // Select |num_replaced_params| parameters at random. We shuffle the vector - // of indices for randomization and shrink it to select first - // |num_replaced_params| parameters. - auto num_replaced_params = std::min( - parameter_index.size(), - GetFuzzerContext()->GetRandomNumberOfParametersReplacedWithStruct( - static_cast(params.size()))); - - GetFuzzerContext()->Shuffle(¶meter_index); - parameter_index.resize(num_replaced_params); - - // Make sure OpTypeStruct exists in the module. - std::vector component_type_ids; - for (auto index : parameter_index) { - component_type_ids.push_back(params[index]->type_id()); - } - - FindOrCreateStructType(component_type_ids); - - // Map parameters' indices to parameters' ids. - std::vector parameter_id; - for (auto index : parameter_index) { - parameter_id.push_back(params[index]->result_id()); - } - - std::map caller_id_to_fresh_id; - for (const auto* inst : - fuzzerutil::GetCallers(GetIRContext(), function.result_id())) { - caller_id_to_fresh_id[inst->result_id()] = - GetFuzzerContext()->GetFreshId(); - } - - ApplyTransformation(TransformationReplaceParamsWithStruct( - parameter_id, GetFuzzerContext()->GetFreshId(), - GetFuzzerContext()->GetFreshId(), caller_id_to_fresh_id)); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.h deleted file mode 100644 index ed1aa6b5f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_params_with_struct.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_REPLACE_PARAMS_WITH_STRUCT_H_ -#define SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMS_WITH_STRUCT_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Iterates over all functions in the module and randomly decides for each one -// whether to replace a subset of its parameters with a struct value. -class FuzzerPassReplaceParamsWithStruct : public FuzzerPass { - public: - FuzzerPassReplaceParamsWithStruct( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassReplaceParamsWithStruct() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMS_WITH_STRUCT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp deleted file mode 100644 index 481cd9607..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_pass_split_blocks.h" - -#include - -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_split_block.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassSplitBlocks::FuzzerPassSplitBlocks( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassSplitBlocks::~FuzzerPassSplitBlocks() = default; - -void FuzzerPassSplitBlocks::Apply() { - // Gather up pointers to all the blocks in the module. We are then able to - // iterate over these pointers and split the blocks to which they point; - // we cannot safely split blocks while we iterate through the module. - std::vector blocks; - for (auto& function : *GetIRContext()->module()) { - for (auto& block : function) { - blocks.push_back(&block); - } - } - - // Now go through all the block pointers that were gathered. - for (auto& block : blocks) { - // Probabilistically decide whether to try to split this block. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfSplittingBlock())) { - // We are not going to try to split this block. - continue; - } - - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2964): consider - // taking a simpler approach to identifying the instruction before which - // to split a block. - - // We are going to try to split this block. We now need to choose where - // to split it. We describe the instruction before which we would like to - // split a block via an InstructionDescriptor, details of which are - // commented in the protobufs definition file. - std::vector instruction_descriptors; - - // The initial base instruction is the block label. - uint32_t base = block->id(); - - // Counts the number of times we have seen each opcode since we reset the - // base instruction. - std::map skip_count; - - // Consider every instruction in the block. The label is excluded: it is - // only necessary to consider it as a base in case the first instruction - // in the block does not have a result id. - for (auto& inst : *block) { - if (inst.HasResultId()) { - // In the case that the instruction has a result id, we use the - // instruction as its own base, and clear the skip counts we have - // collected. - base = inst.result_id(); - skip_count.clear(); - } - const SpvOp opcode = inst.opcode(); - instruction_descriptors.emplace_back(MakeInstructionDescriptor( - base, opcode, skip_count.count(opcode) ? skip_count.at(opcode) : 0)); - if (!inst.HasResultId()) { - skip_count[opcode] = - skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1; - } - } - // Having identified all the places we might be able to split the block, - // we choose one of them. - auto transformation = TransformationSplitBlock( - instruction_descriptors[GetFuzzerContext()->RandomIndex( - instruction_descriptors)], - GetFuzzerContext()->GetFreshId()); - // If the position we have chosen turns out to be a valid place to split - // the block, we apply the split. Otherwise the block just doesn't get - // split. - MaybeApplyTransformation(transformation); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h deleted file mode 100644 index 278ec6dc3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ -#define SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// A fuzzer pass for splitting blocks in the module, to create more blocks; this -// can be very useful for giving other passes a chance to apply. -class FuzzerPassSplitBlocks : public FuzzerPass { - public: - FuzzerPassSplitBlocks(opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassSplitBlocks() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp deleted file mode 100644 index 321e8efd6..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_swap_commutable_operands.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_swap_commutable_operands.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassSwapCommutableOperands::FuzzerPassSwapCommutableOperands( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassSwapCommutableOperands::~FuzzerPassSwapCommutableOperands() = default; - -void FuzzerPassSwapCommutableOperands::Apply() { - auto context = GetIRContext(); - // Iterates over the module's instructions and checks whether it is - // commutative. In this case, the transformation is probabilistically applied. - context->module()->ForEachInst( - [this, context](opt::Instruction* instruction) { - if (spvOpcodeIsCommutativeBinaryOperator(instruction->opcode()) && - GetFuzzerContext()->ChooseEven()) { - auto instructionDescriptor = - MakeInstructionDescriptor(context, instruction); - auto transformation = - TransformationSwapCommutableOperands(instructionDescriptor); - ApplyTransformation(transformation); - } - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.h deleted file mode 100644 index 74d937d8c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_commutable_operands.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_SWAP_COMMUTABLE_OPERANDS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_SWAP_COMMUTABLE_OPERANDS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// This fuzzer pass searches for all commutative instructions in the module, -// probabilistically choosing which of these instructions will have its input -// operands swapped. -class FuzzerPassSwapCommutableOperands : public FuzzerPass { - public: - FuzzerPassSwapCommutableOperands( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassSwapCommutableOperands(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_SWAP_COMMUTABLE_OPERANDS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp deleted file mode 100644 index dc8b1eb85..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_swap_conditional_branch_operands.h" -#include "source/fuzz/fuzzer_context.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_swap_conditional_branch_operands.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassSwapBranchConditionalOperands:: - FuzzerPassSwapBranchConditionalOperands( - opt::IRContext* ir_context, - TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassSwapBranchConditionalOperands:: - ~FuzzerPassSwapBranchConditionalOperands() = default; - -void FuzzerPassSwapBranchConditionalOperands::Apply() { - ForEachInstructionWithInstructionDescriptor( - [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, - opt::BasicBlock::iterator inst_it, - const protobufs::InstructionDescriptor& instruction_descriptor) { - const auto& inst = *inst_it; - - if (inst.opcode() != SpvOpBranchConditional) { - return; - } - - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext() - ->GetChanceOfSwappingConditionalBranchOperands())) { - return; - } - - ApplyTransformation(TransformationSwapConditionalBranchOperands( - instruction_descriptor, GetFuzzerContext()->GetFreshId())); - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h deleted file mode 100644 index f84f3ba40..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_SWAP_BRANCH_CONDITIONAL_OPERANDS_H_ -#define SOURCE_FUZZ_FUZZER_PASS_SWAP_BRANCH_CONDITIONAL_OPERANDS_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// Randomly decides for each OpBranchConditional instruction in the module -// whether to swap its operands or not. -class FuzzerPassSwapBranchConditionalOperands : public FuzzerPass { - public: - FuzzerPassSwapBranchConditionalOperands( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassSwapBranchConditionalOperands() override; - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_SWAP_BRANCH_CONDITIONAL_OPERANDS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp deleted file mode 100644 index 4f26cba36..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_toggle_access_chain_instruction.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/fuzz/transformation_toggle_access_chain_instruction.h" - -namespace spvtools { -namespace fuzz { - -FuzzerPassToggleAccessChainInstruction::FuzzerPassToggleAccessChainInstruction( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations) - : FuzzerPass(ir_context, transformation_context, fuzzer_context, - transformations) {} - -FuzzerPassToggleAccessChainInstruction:: - ~FuzzerPassToggleAccessChainInstruction() = default; - -void FuzzerPassToggleAccessChainInstruction::Apply() { - auto context = GetIRContext(); - // Iterates over the module's instructions and checks whether it is - // OpAccessChain or OpInBoundsAccessChain. In this case, the transformation is - // probabilistically applied. - context->module()->ForEachInst([this, - context](opt::Instruction* instruction) { - SpvOp opcode = instruction->opcode(); - if ((opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) && - GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfTogglingAccessChainInstruction())) { - auto instructionDescriptor = - MakeInstructionDescriptor(context, instruction); - auto transformation = - TransformationToggleAccessChainInstruction(instructionDescriptor); - ApplyTransformation(transformation); - } - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h deleted file mode 100644 index d77c7cbe7..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_TOGGLE_ACCESS_CHAIN_INSTRUCTION_H_ -#define SOURCE_FUZZ_FUZZER_PASS_TOGGLE_ACCESS_CHAIN_INSTRUCTION_H_ - -#include "source/fuzz/fuzzer_pass.h" - -namespace spvtools { -namespace fuzz { - -// This fuzzer pass searches for all access chain instructions in the module, -// probabilistically choosing which of these instructions will be toggled. -class FuzzerPassToggleAccessChainInstruction : public FuzzerPass { - public: - FuzzerPassToggleAccessChainInstruction( - opt::IRContext* ir_context, TransformationContext* transformation_context, - FuzzerContext* fuzzer_context, - protobufs::TransformationSequence* transformations); - - ~FuzzerPassToggleAccessChainInstruction(); - - void Apply() override; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_PASS_TOGGLE_ACCESS_CHAIN_INSTRUCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp deleted file mode 100644 index db77f5dd1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp +++ /dev/null @@ -1,1345 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/fuzzer_util.h" - -#include -#include - -#include "source/opt/build_module.h" - -namespace spvtools { -namespace fuzz { - -namespace fuzzerutil { -namespace { - -uint32_t MaybeGetOpConstant(opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& words, - uint32_t type_id, bool is_irrelevant) { - for (const auto& inst : ir_context->types_values()) { - if (inst.opcode() == SpvOpConstant && inst.type_id() == type_id && - inst.GetInOperand(0).words == words && - transformation_context.GetFactManager()->IdIsIrrelevant( - inst.result_id()) == is_irrelevant) { - return inst.result_id(); - } - } - - return 0; -} - -} // namespace - -bool IsFreshId(opt::IRContext* context, uint32_t id) { - return !context->get_def_use_mgr()->GetDef(id); -} - -void UpdateModuleIdBound(opt::IRContext* context, uint32_t id) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the - // case where the maximum id bound is reached. - context->module()->SetIdBound( - std::max(context->module()->id_bound(), id + 1)); -} - -opt::BasicBlock* MaybeFindBlock(opt::IRContext* context, - uint32_t maybe_block_id) { - auto inst = context->get_def_use_mgr()->GetDef(maybe_block_id); - if (inst == nullptr) { - // No instruction defining this id was found. - return nullptr; - } - if (inst->opcode() != SpvOpLabel) { - // The instruction defining the id is not a label, so it cannot be a block - // id. - return nullptr; - } - return context->cfg()->block(maybe_block_id); -} - -bool PhiIdsOkForNewEdge( - opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, - const google::protobuf::RepeatedField& phi_ids) { - if (bb_from->IsSuccessor(bb_to)) { - // There is already an edge from |from_block| to |to_block|, so there is - // no need to extend OpPhi instructions. Do not allow phi ids to be - // present. This might turn out to be too strict; perhaps it would be OK - // just to ignore the ids in this case. - return phi_ids.empty(); - } - // The edge would add a previously non-existent edge from |from_block| to - // |to_block|, so we go through the given phi ids and check that they exactly - // match the OpPhi instructions in |to_block|. - uint32_t phi_index = 0; - // An explicit loop, rather than applying a lambda to each OpPhi in |bb_to|, - // makes sense here because we need to increment |phi_index| for each OpPhi - // instruction. - for (auto& inst : *bb_to) { - if (inst.opcode() != SpvOpPhi) { - // The OpPhi instructions all occur at the start of the block; if we find - // a non-OpPhi then we have seen them all. - break; - } - if (phi_index == static_cast(phi_ids.size())) { - // Not enough phi ids have been provided to account for the OpPhi - // instructions. - return false; - } - // Look for an instruction defining the next phi id. - opt::Instruction* phi_extension = - context->get_def_use_mgr()->GetDef(phi_ids[phi_index]); - if (!phi_extension) { - // The id given to extend this OpPhi does not exist. - return false; - } - if (phi_extension->type_id() != inst.type_id()) { - // The instruction given to extend this OpPhi either does not have a type - // or its type does not match that of the OpPhi. - return false; - } - - if (context->get_instr_block(phi_extension)) { - // The instruction defining the phi id has an associated block (i.e., it - // is not a global value). Check whether its definition dominates the - // exit of |from_block|. - auto dominator_analysis = - context->GetDominatorAnalysis(bb_from->GetParent()); - if (!dominator_analysis->Dominates(phi_extension, - bb_from->terminator())) { - // The given id is no good as its definition does not dominate the exit - // of |from_block| - return false; - } - } - phi_index++; - } - // We allow some of the ids provided for extending OpPhi instructions to be - // unused. Their presence does no harm, and requiring a perfect match may - // make transformations less likely to cleanly apply. - return true; -} - -void AddUnreachableEdgeAndUpdateOpPhis( - opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, - uint32_t bool_id, - const google::protobuf::RepeatedField& phi_ids) { - assert(PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) && - "Precondition on phi_ids is not satisfied"); - assert(bb_from->terminator()->opcode() == SpvOpBranch && - "Precondition on terminator of bb_from is not satisfied"); - - // Get the id of the boolean constant to be used as the condition. - auto condition_inst = context->get_def_use_mgr()->GetDef(bool_id); - assert(condition_inst && - (condition_inst->opcode() == SpvOpConstantTrue || - condition_inst->opcode() == SpvOpConstantFalse) && - "|bool_id| is invalid"); - - auto condition_value = condition_inst->opcode() == SpvOpConstantTrue; - - const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to); - auto successor = bb_from->terminator()->GetSingleWordInOperand(0); - - // Add the dead branch, by turning OpBranch into OpBranchConditional, and - // ordering the targets depending on whether the given boolean corresponds to - // true or false. - bb_from->terminator()->SetOpcode(SpvOpBranchConditional); - bb_from->terminator()->SetInOperands( - {{SPV_OPERAND_TYPE_ID, {bool_id}}, - {SPV_OPERAND_TYPE_ID, {condition_value ? successor : bb_to->id()}}, - {SPV_OPERAND_TYPE_ID, {condition_value ? bb_to->id() : successor}}}); - - // Update OpPhi instructions in the target block if this branch adds a - // previously non-existent edge from source to target. - if (!from_to_edge_already_exists) { - uint32_t phi_index = 0; - for (auto& inst : *bb_to) { - if (inst.opcode() != SpvOpPhi) { - break; - } - assert(phi_index < static_cast(phi_ids.size()) && - "There should be at least one phi id per OpPhi instruction."); - inst.AddOperand({SPV_OPERAND_TYPE_ID, {phi_ids[phi_index]}}); - inst.AddOperand({SPV_OPERAND_TYPE_ID, {bb_from->id()}}); - phi_index++; - } - } -} - -bool BlockIsBackEdge(opt::IRContext* context, uint32_t block_id, - uint32_t loop_header_id) { - auto block = context->cfg()->block(block_id); - auto loop_header = context->cfg()->block(loop_header_id); - - // |block| and |loop_header| must be defined, |loop_header| must be in fact - // loop header and |block| must branch to it. - if (!(block && loop_header && loop_header->IsLoopHeader() && - block->IsSuccessor(loop_header))) { - return false; - } - - // |block_id| must be reachable and be dominated by |loop_header|. - opt::DominatorAnalysis* dominator_analysis = - context->GetDominatorAnalysis(loop_header->GetParent()); - return dominator_analysis->IsReachable(block_id) && - dominator_analysis->Dominates(loop_header_id, block_id); -} - -bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id, - uint32_t maybe_loop_header_id) { - // We deem a block to be part of a loop's continue construct if the loop's - // continue target dominates the block. - auto containing_construct_block = context->cfg()->block(maybe_loop_header_id); - if (containing_construct_block->IsLoopHeader()) { - auto continue_target = containing_construct_block->ContinueBlockId(); - if (context->GetDominatorAnalysis(containing_construct_block->GetParent()) - ->Dominates(continue_target, block_id)) { - return true; - } - } - return false; -} - -opt::BasicBlock::iterator GetIteratorForInstruction( - opt::BasicBlock* block, const opt::Instruction* inst) { - for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) { - if (inst == &*inst_it) { - return inst_it; - } - } - return block->end(); -} - -bool BlockIsReachableInItsFunction(opt::IRContext* context, - opt::BasicBlock* bb) { - auto enclosing_function = bb->GetParent(); - return context->GetDominatorAnalysis(enclosing_function) - ->Dominates(enclosing_function->entry().get(), bb); -} - -bool CanInsertOpcodeBeforeInstruction( - SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block) { - if (instruction_in_block->PreviousNode() && - (instruction_in_block->PreviousNode()->opcode() == SpvOpLoopMerge || - instruction_in_block->PreviousNode()->opcode() == SpvOpSelectionMerge)) { - // We cannot insert directly after a merge instruction. - return false; - } - if (opcode != SpvOpVariable && - instruction_in_block->opcode() == SpvOpVariable) { - // We cannot insert a non-OpVariable instruction directly before a - // variable; variables in a function must be contiguous in the entry block. - return false; - } - // We cannot insert a non-OpPhi instruction directly before an OpPhi, because - // OpPhi instructions need to be contiguous at the start of a block. - return opcode == SpvOpPhi || instruction_in_block->opcode() != SpvOpPhi; -} - -bool CanMakeSynonymOf(opt::IRContext* ir_context, - const TransformationContext& transformation_context, - 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()) { - // We can only make a synonym of an instruction that generates an id. - return false; - } - if (transformation_context.GetFactManager()->IdIsIrrelevant( - inst->result_id())) { - // An irrelevant id can't be a synonym of anything. - return false; - } - 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()); - 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()) { - case SpvOpConstantNull: - case SpvOpUndef: - // We disallow making synonyms of null or undefined pointers. This is - // to provide the property that if the original shader exhibited no bad - // pointer accesses, the transformed shader will not either. - return false; - default: - break; - } - } - - // We do not make synonyms of objects that have decorations: if the synonym is - // not decorated analogously, using the original object vs. its synonymous - // form may not be equivalent. - return ir_context->get_decoration_mgr() - ->GetDecorationsFor(inst->result_id(), true) - .empty(); -} - -bool IsCompositeType(const opt::analysis::Type* type) { - return type && (type->AsArray() || type->AsMatrix() || type->AsStruct() || - type->AsVector()); -} - -std::vector RepeatedFieldToVector( - const google::protobuf::RepeatedField& repeated_field) { - std::vector result; - for (auto i : repeated_field) { - result.push_back(i); - } - return result; -} - -uint32_t WalkOneCompositeTypeIndex(opt::IRContext* context, - uint32_t base_object_type_id, - uint32_t index) { - auto should_be_composite_type = - context->get_def_use_mgr()->GetDef(base_object_type_id); - assert(should_be_composite_type && "The type should exist."); - switch (should_be_composite_type->opcode()) { - case SpvOpTypeArray: { - auto array_length = GetArraySize(*should_be_composite_type, context); - if (array_length == 0 || index >= array_length) { - return 0; - } - return should_be_composite_type->GetSingleWordInOperand(0); - } - case SpvOpTypeMatrix: - case SpvOpTypeVector: { - auto count = should_be_composite_type->GetSingleWordInOperand(1); - if (index >= count) { - return 0; - } - return should_be_composite_type->GetSingleWordInOperand(0); - } - case SpvOpTypeStruct: { - if (index >= GetNumberOfStructMembers(*should_be_composite_type)) { - return 0; - } - return should_be_composite_type->GetSingleWordInOperand(index); - } - default: - return 0; - } -} - -uint32_t WalkCompositeTypeIndices( - opt::IRContext* context, uint32_t base_object_type_id, - const google::protobuf::RepeatedField& indices) { - uint32_t sub_object_type_id = base_object_type_id; - for (auto index : indices) { - sub_object_type_id = - WalkOneCompositeTypeIndex(context, sub_object_type_id, index); - if (!sub_object_type_id) { - return 0; - } - } - return sub_object_type_id; -} - -uint32_t GetNumberOfStructMembers( - const opt::Instruction& struct_type_instruction) { - assert(struct_type_instruction.opcode() == SpvOpTypeStruct && - "An OpTypeStruct instruction is required here."); - return struct_type_instruction.NumInOperands(); -} - -uint32_t GetArraySize(const opt::Instruction& array_type_instruction, - opt::IRContext* context) { - auto array_length_constant = - context->get_constant_mgr() - ->GetConstantFromInst(context->get_def_use_mgr()->GetDef( - array_type_instruction.GetSingleWordInOperand(1))) - ->AsIntConstant(); - if (array_length_constant->words().size() != 1) { - return 0; - } - return array_length_constant->GetU32(); -} - -uint32_t GetBoundForCompositeIndex(const opt::Instruction& composite_type_inst, - opt::IRContext* ir_context) { - switch (composite_type_inst.opcode()) { - case SpvOpTypeArray: - return fuzzerutil::GetArraySize(composite_type_inst, ir_context); - case SpvOpTypeMatrix: - case SpvOpTypeVector: - return composite_type_inst.GetSingleWordInOperand(1); - case SpvOpTypeStruct: { - return fuzzerutil::GetNumberOfStructMembers(composite_type_inst); - } - case SpvOpTypeRuntimeArray: - assert(false && - "GetBoundForCompositeIndex should not be invoked with an " - "OpTypeRuntimeArray, which does not have a static bound."); - return 0; - default: - assert(false && "Unknown composite type."); - return 0; - } -} - -bool IsValid(opt::IRContext* context, spv_validator_options validator_options) { - std::vector binary; - context->module()->ToBinary(&binary, false); - SpirvTools tools(context->grammar().target_env()); - return tools.Validate(binary.data(), binary.size(), validator_options); -} - -std::unique_ptr CloneIRContext(opt::IRContext* context) { - std::vector binary; - context->module()->ToBinary(&binary, false); - return BuildModule(context->grammar().target_env(), nullptr, binary.data(), - binary.size()); -} - -bool IsNonFunctionTypeId(opt::IRContext* ir_context, uint32_t id) { - auto type = ir_context->get_type_mgr()->GetType(id); - return type && !type->AsFunction(); -} - -bool IsMergeOrContinue(opt::IRContext* ir_context, uint32_t block_id) { - bool result = false; - ir_context->get_def_use_mgr()->WhileEachUse( - block_id, - [&result](const opt::Instruction* use_instruction, - uint32_t /*unused*/) -> bool { - switch (use_instruction->opcode()) { - case SpvOpLoopMerge: - case SpvOpSelectionMerge: - result = true; - return false; - default: - return true; - } - }); - return result; -} - -uint32_t FindFunctionType(opt::IRContext* ir_context, - const std::vector& type_ids) { - // Look through the existing types for a match. - for (auto& type_or_value : ir_context->types_values()) { - if (type_or_value.opcode() != SpvOpTypeFunction) { - // We are only interested in function types. - continue; - } - if (type_or_value.NumInOperands() != type_ids.size()) { - // Not a match: different numbers of arguments. - continue; - } - // Check whether the return type and argument types match. - bool input_operands_match = true; - for (uint32_t i = 0; i < type_or_value.NumInOperands(); i++) { - if (type_ids[i] != type_or_value.GetSingleWordInOperand(i)) { - input_operands_match = false; - break; - } - } - if (input_operands_match) { - // Everything matches. - return type_or_value.result_id(); - } - } - // No match was found. - return 0; -} - -opt::Instruction* GetFunctionType(opt::IRContext* context, - const opt::Function* function) { - uint32_t type_id = function->DefInst().GetSingleWordInOperand(1); - return context->get_def_use_mgr()->GetDef(type_id); -} - -opt::Function* FindFunction(opt::IRContext* ir_context, uint32_t function_id) { - for (auto& function : *ir_context->module()) { - if (function.result_id() == function_id) { - return &function; - } - } - return nullptr; -} - -bool FunctionContainsOpKillOrUnreachable(const opt::Function& function) { - for (auto& block : function) { - if (block.terminator()->opcode() == SpvOpKill || - block.terminator()->opcode() == SpvOpUnreachable) { - return true; - } - } - return false; -} - -bool FunctionIsEntryPoint(opt::IRContext* context, uint32_t function_id) { - for (auto& entry_point : context->module()->entry_points()) { - if (entry_point.GetSingleWordInOperand(1) == function_id) { - return true; - } - } - return false; -} - -bool IdIsAvailableAtUse(opt::IRContext* context, - opt::Instruction* use_instruction, - uint32_t use_input_operand_index, uint32_t id) { - auto defining_instruction = context->get_def_use_mgr()->GetDef(id); - auto enclosing_function = - context->get_instr_block(use_instruction)->GetParent(); - // If the id a function parameter, it needs to be associated with the - // function containing the use. - if (defining_instruction->opcode() == SpvOpFunctionParameter) { - return InstructionIsFunctionParameter(defining_instruction, - enclosing_function); - } - if (!context->get_instr_block(id)) { - // The id must be at global scope. - return true; - } - if (defining_instruction == use_instruction) { - // It is not OK for a definition to use itself. - return false; - } - auto dominator_analysis = context->GetDominatorAnalysis(enclosing_function); - if (use_instruction->opcode() == SpvOpPhi) { - // In the case where the use is an operand to OpPhi, it is actually the - // *parent* block associated with the operand that must be dominated by - // the synonym. - auto parent_block = - use_instruction->GetSingleWordInOperand(use_input_operand_index + 1); - return dominator_analysis->Dominates( - context->get_instr_block(defining_instruction)->id(), parent_block); - } - return dominator_analysis->Dominates(defining_instruction, use_instruction); -} - -bool IdIsAvailableBeforeInstruction(opt::IRContext* context, - opt::Instruction* instruction, - uint32_t id) { - auto defining_instruction = context->get_def_use_mgr()->GetDef(id); - auto enclosing_function = context->get_instr_block(instruction)->GetParent(); - // If the id a function parameter, it needs to be associated with the - // function containing the instruction. - if (defining_instruction->opcode() == SpvOpFunctionParameter) { - return InstructionIsFunctionParameter(defining_instruction, - enclosing_function); - } - if (!context->get_instr_block(id)) { - // The id is at global scope. - return true; - } - if (defining_instruction == instruction) { - // The instruction is not available right before its own definition. - return false; - } - return context->GetDominatorAnalysis(enclosing_function) - ->Dominates(defining_instruction, instruction); -} - -bool InstructionIsFunctionParameter(opt::Instruction* instruction, - opt::Function* function) { - if (instruction->opcode() != SpvOpFunctionParameter) { - return false; - } - bool found_parameter = false; - function->ForEachParam( - [instruction, &found_parameter](opt::Instruction* param) { - if (param == instruction) { - found_parameter = true; - } - }); - return found_parameter; -} - -uint32_t GetTypeId(opt::IRContext* context, uint32_t result_id) { - return context->get_def_use_mgr()->GetDef(result_id)->type_id(); -} - -uint32_t GetPointeeTypeIdFromPointerType(opt::Instruction* pointer_type_inst) { - assert(pointer_type_inst && pointer_type_inst->opcode() == SpvOpTypePointer && - "Precondition: |pointer_type_inst| must be OpTypePointer."); - return pointer_type_inst->GetSingleWordInOperand(1); -} - -uint32_t GetPointeeTypeIdFromPointerType(opt::IRContext* context, - uint32_t pointer_type_id) { - return GetPointeeTypeIdFromPointerType( - context->get_def_use_mgr()->GetDef(pointer_type_id)); -} - -SpvStorageClass GetStorageClassFromPointerType( - opt::Instruction* pointer_type_inst) { - assert(pointer_type_inst && pointer_type_inst->opcode() == SpvOpTypePointer && - "Precondition: |pointer_type_inst| must be OpTypePointer."); - return static_cast( - pointer_type_inst->GetSingleWordInOperand(0)); -} - -SpvStorageClass GetStorageClassFromPointerType(opt::IRContext* context, - uint32_t pointer_type_id) { - return GetStorageClassFromPointerType( - context->get_def_use_mgr()->GetDef(pointer_type_id)); -} - -uint32_t MaybeGetPointerType(opt::IRContext* context, uint32_t pointee_type_id, - SpvStorageClass storage_class) { - for (auto& inst : context->types_values()) { - switch (inst.opcode()) { - case SpvOpTypePointer: - if (inst.GetSingleWordInOperand(0) == storage_class && - inst.GetSingleWordInOperand(1) == pointee_type_id) { - return inst.result_id(); - } - break; - default: - break; - } - } - return 0; -} - -uint32_t InOperandIndexFromOperandIndex(const opt::Instruction& inst, - uint32_t absolute_index) { - // Subtract the number of non-input operands from the index - 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 GlobalVariablesMustBeDeclaredInEntryPointInterfaces( - const opt::IRContext* ir_context) { - // TODO(afd): We capture the universal environments for which this requirement - // holds. The check should be refined on demand for other target - // environments. - switch (ir_context->grammar().target_env()) { - case SPV_ENV_UNIVERSAL_1_0: - case SPV_ENV_UNIVERSAL_1_1: - case SPV_ENV_UNIVERSAL_1_2: - case SPV_ENV_UNIVERSAL_1_3: - return false; - default: - return true; - } -} - -void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id) { - if (GlobalVariablesMustBeDeclaredInEntryPointInterfaces(context)) { - // Conservatively add this global to the interface of every entry point in - // the module. This means that the global is available for other - // transformations to use. - // - // A downside of this is that the global will be in the interface even if it - // ends up never being used. - // - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit - // this if a more thorough approach to entry point interfaces is taken. - for (auto& entry_point : context->module()->entry_points()) { - entry_point.AddOperand({SPV_OPERAND_TYPE_ID, {id}}); - } - } -} - -void AddGlobalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, SpvStorageClass storage_class, - uint32_t initializer_id) { - // Check various preconditions. - assert(result_id != 0 && "Result id can't be 0"); - - assert((storage_class == SpvStorageClassPrivate || - storage_class == SpvStorageClassWorkgroup) && - "Variable's storage class must be either Private or Workgroup"); - - auto* type_inst = context->get_def_use_mgr()->GetDef(type_id); - (void)type_inst; // Variable becomes unused in release mode. - assert(type_inst && type_inst->opcode() == SpvOpTypePointer && - GetStorageClassFromPointerType(type_inst) == storage_class && - "Variable's type is invalid"); - - if (storage_class == SpvStorageClassWorkgroup) { - assert(initializer_id == 0); - } - - if (initializer_id != 0) { - const auto* constant_inst = - context->get_def_use_mgr()->GetDef(initializer_id); - (void)constant_inst; // Variable becomes unused in release mode. - assert(constant_inst && spvOpcodeIsConstant(constant_inst->opcode()) && - GetPointeeTypeIdFromPointerType(type_inst) == - constant_inst->type_id() && - "Initializer is invalid"); - } - - opt::Instruction::OperandList operands = { - {SPV_OPERAND_TYPE_STORAGE_CLASS, {static_cast(storage_class)}}}; - - if (initializer_id) { - operands.push_back({SPV_OPERAND_TYPE_ID, {initializer_id}}); - } - - context->module()->AddGlobalValue(MakeUnique( - context, SpvOpVariable, type_id, result_id, std::move(operands))); - - AddVariableIdToEntryPointInterfaces(context, result_id); - UpdateModuleIdBound(context, result_id); -} - -void AddLocalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, uint32_t function_id, - uint32_t initializer_id) { - // Check various preconditions. - assert(result_id != 0 && "Result id can't be 0"); - - auto* type_inst = context->get_def_use_mgr()->GetDef(type_id); - (void)type_inst; // Variable becomes unused in release mode. - assert(type_inst && type_inst->opcode() == SpvOpTypePointer && - GetStorageClassFromPointerType(type_inst) == SpvStorageClassFunction && - "Variable's type is invalid"); - - const auto* constant_inst = - context->get_def_use_mgr()->GetDef(initializer_id); - (void)constant_inst; // Variable becomes unused in release mode. - assert(constant_inst && spvOpcodeIsConstant(constant_inst->opcode()) && - GetPointeeTypeIdFromPointerType(type_inst) == - constant_inst->type_id() && - "Initializer is invalid"); - - auto* function = FindFunction(context, function_id); - assert(function && "Function id is invalid"); - - function->begin()->begin()->InsertBefore(MakeUnique( - context, SpvOpVariable, type_id, result_id, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}, - {SPV_OPERAND_TYPE_ID, {initializer_id}}})); - - UpdateModuleIdBound(context, result_id); -} - -bool HasDuplicates(const std::vector& arr) { - return std::unordered_set(arr.begin(), arr.end()).size() != - arr.size(); -} - -bool IsPermutationOfRange(const std::vector& arr, uint32_t lo, - uint32_t hi) { - if (arr.empty()) { - return lo > hi; - } - - if (HasDuplicates(arr)) { - return false; - } - - auto min_max = std::minmax_element(arr.begin(), arr.end()); - return arr.size() == hi - lo + 1 && *min_max.first == lo && - *min_max.second == hi; -} - -std::vector GetParameters(opt::IRContext* ir_context, - uint32_t function_id) { - auto* function = FindFunction(ir_context, function_id); - assert(function && "|function_id| is invalid"); - - std::vector result; - function->ForEachParam( - [&result](opt::Instruction* inst) { result.push_back(inst); }); - - return result; -} - -void RemoveParameter(opt::IRContext* ir_context, uint32_t parameter_id) { - auto* function = GetFunctionFromParameterId(ir_context, parameter_id); - assert(function && "|parameter_id| is invalid"); - assert(!FunctionIsEntryPoint(ir_context, function->result_id()) && - "Can't remove parameter from an entry point function"); - - function->RemoveParameter(parameter_id); - - // We've just removed parameters from the function and cleared their memory. - // Make sure analyses have no dangling pointers. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -std::vector GetCallers(opt::IRContext* ir_context, - uint32_t function_id) { - assert(FindFunction(ir_context, function_id) && - "|function_id| is not a result id of a function"); - - std::vector result; - ir_context->get_def_use_mgr()->ForEachUser( - function_id, [&result, function_id](opt::Instruction* inst) { - if (inst->opcode() == SpvOpFunctionCall && - inst->GetSingleWordInOperand(0) == function_id) { - result.push_back(inst); - } - }); - - return result; -} - -opt::Function* GetFunctionFromParameterId(opt::IRContext* ir_context, - uint32_t param_id) { - auto* param_inst = ir_context->get_def_use_mgr()->GetDef(param_id); - assert(param_inst && "Parameter id is invalid"); - - for (auto& function : *ir_context->module()) { - if (InstructionIsFunctionParameter(param_inst, &function)) { - return &function; - } - } - - return nullptr; -} - -uint32_t UpdateFunctionType(opt::IRContext* ir_context, uint32_t function_id, - uint32_t new_function_type_result_id, - uint32_t return_type_id, - const std::vector& parameter_type_ids) { - // Check some initial constraints. - assert(ir_context->get_type_mgr()->GetType(return_type_id) && - "Return type is invalid"); - for (auto id : parameter_type_ids) { - const auto* type = ir_context->get_type_mgr()->GetType(id); - (void)type; // Make compilers happy in release mode. - // Parameters can't be OpTypeVoid. - assert(type && !type->AsVoid() && "Parameter has invalid type"); - } - - auto* function = FindFunction(ir_context, function_id); - assert(function && "|function_id| is invalid"); - - auto* old_function_type = GetFunctionType(ir_context, function); - assert(old_function_type && "Function has invalid type"); - - std::vector operand_ids = {return_type_id}; - operand_ids.insert(operand_ids.end(), parameter_type_ids.begin(), - parameter_type_ids.end()); - - // A trivial case - we change nothing. - if (FindFunctionType(ir_context, operand_ids) == - old_function_type->result_id()) { - return old_function_type->result_id(); - } - - if (ir_context->get_def_use_mgr()->NumUsers(old_function_type) == 1 && - FindFunctionType(ir_context, operand_ids) == 0) { - // We can change |old_function_type| only if it's used once in the module - // and we are certain we won't create a duplicate as a result of the change. - - // Update |old_function_type| in-place. - opt::Instruction::OperandList operands; - for (auto id : operand_ids) { - operands.push_back({SPV_OPERAND_TYPE_ID, {id}}); - } - - old_function_type->SetInOperands(std::move(operands)); - - // |operands| may depend on result ids defined below the |old_function_type| - // in the module. - old_function_type->RemoveFromList(); - ir_context->AddType(std::unique_ptr(old_function_type)); - return old_function_type->result_id(); - } else { - // We can't modify the |old_function_type| so we have to either use an - // existing one or create a new one. - auto type_id = FindOrCreateFunctionType( - ir_context, new_function_type_result_id, operand_ids); - assert(type_id != old_function_type->result_id() && - "We should've handled this case above"); - - function->DefInst().SetInOperand(1, {type_id}); - - // DefUseManager hasn't been updated yet, so if the following condition is - // true, then |old_function_type| will have no users when this function - // returns. We might as well remove it. - if (ir_context->get_def_use_mgr()->NumUsers(old_function_type) == 1) { - ir_context->KillInst(old_function_type); - } - - return type_id; - } -} - -void AddFunctionType(opt::IRContext* ir_context, uint32_t result_id, - const std::vector& type_ids) { - assert(result_id != 0 && "Result id can't be 0"); - assert(!type_ids.empty() && - "OpTypeFunction always has at least one operand - function's return " - "type"); - assert(IsNonFunctionTypeId(ir_context, type_ids[0]) && - "Return type must not be a function"); - - for (size_t i = 1; i < type_ids.size(); ++i) { - const auto* param_type = ir_context->get_type_mgr()->GetType(type_ids[i]); - (void)param_type; // Make compiler happy in release mode. - assert(param_type && !param_type->AsVoid() && !param_type->AsFunction() && - "Function parameter can't have a function or void type"); - } - - opt::Instruction::OperandList operands; - operands.reserve(type_ids.size()); - for (auto id : type_ids) { - operands.push_back({SPV_OPERAND_TYPE_ID, {id}}); - } - - ir_context->AddType(MakeUnique( - ir_context, SpvOpTypeFunction, 0, result_id, std::move(operands))); - - UpdateModuleIdBound(ir_context, result_id); -} - -uint32_t FindOrCreateFunctionType(opt::IRContext* ir_context, - uint32_t result_id, - const std::vector& type_ids) { - if (auto existing_id = FindFunctionType(ir_context, type_ids)) { - return existing_id; - } - AddFunctionType(ir_context, result_id, type_ids); - return result_id; -} - -uint32_t MaybeGetIntegerType(opt::IRContext* ir_context, uint32_t width, - bool is_signed) { - opt::analysis::Integer type(width, is_signed); - return ir_context->get_type_mgr()->GetId(&type); -} - -uint32_t MaybeGetFloatType(opt::IRContext* ir_context, uint32_t width) { - opt::analysis::Float type(width); - return ir_context->get_type_mgr()->GetId(&type); -} - -uint32_t MaybeGetBoolType(opt::IRContext* ir_context) { - opt::analysis::Bool type; - return ir_context->get_type_mgr()->GetId(&type); -} - -uint32_t MaybeGetVectorType(opt::IRContext* ir_context, - uint32_t component_type_id, - uint32_t element_count) { - const auto* component_type = - ir_context->get_type_mgr()->GetType(component_type_id); - assert(component_type && - (component_type->AsInteger() || component_type->AsFloat() || - component_type->AsBool()) && - "|component_type_id| is invalid"); - assert(element_count >= 2 && element_count <= 4 && - "Precondition: component count must be in range [2, 4]."); - opt::analysis::Vector type(component_type, element_count); - return ir_context->get_type_mgr()->GetId(&type); -} - -uint32_t MaybeGetStructType(opt::IRContext* ir_context, - const std::vector& component_type_ids) { - std::vector component_types; - component_types.reserve(component_type_ids.size()); - - for (auto type_id : component_type_ids) { - const auto* component_type = ir_context->get_type_mgr()->GetType(type_id); - assert(component_type && !component_type->AsFunction() && - "Component type is invalid"); - component_types.push_back(component_type); - } - - opt::analysis::Struct type(component_types); - return ir_context->get_type_mgr()->GetId(&type); -} - -uint32_t MaybeGetZeroConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - uint32_t scalar_or_composite_type_id, bool is_irrelevant) { - const auto* type_inst = - ir_context->get_def_use_mgr()->GetDef(scalar_or_composite_type_id); - assert(type_inst && "|scalar_or_composite_type_id| is invalid"); - - switch (type_inst->opcode()) { - case SpvOpTypeBool: - return MaybeGetBoolConstant(ir_context, transformation_context, false, - is_irrelevant); - case SpvOpTypeFloat: - case SpvOpTypeInt: { - const auto width = type_inst->GetSingleWordInOperand(0); - std::vector words = {0}; - if (width > 32) { - words.push_back(0); - } - - return MaybeGetScalarConstant(ir_context, transformation_context, words, - scalar_or_composite_type_id, is_irrelevant); - } - case SpvOpTypeStruct: { - std::vector component_ids; - for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) { - const auto component_type_id = type_inst->GetSingleWordInOperand(i); - - auto component_id = - MaybeGetZeroConstant(ir_context, transformation_context, - component_type_id, is_irrelevant); - - if (component_id == 0 && is_irrelevant) { - // Irrelevant constants can use either relevant or irrelevant - // constituents. - component_id = MaybeGetZeroConstant( - ir_context, transformation_context, component_type_id, false); - } - - if (component_id == 0) { - return 0; - } - - component_ids.push_back(component_id); - } - - return MaybeGetCompositeConstant( - ir_context, transformation_context, component_ids, - scalar_or_composite_type_id, is_irrelevant); - } - case SpvOpTypeMatrix: - case SpvOpTypeVector: { - const auto component_type_id = type_inst->GetSingleWordInOperand(0); - - auto component_id = MaybeGetZeroConstant( - ir_context, transformation_context, component_type_id, is_irrelevant); - - if (component_id == 0 && is_irrelevant) { - // Irrelevant constants can use either relevant or irrelevant - // constituents. - component_id = MaybeGetZeroConstant(ir_context, transformation_context, - component_type_id, false); - } - - if (component_id == 0) { - return 0; - } - - const auto component_count = type_inst->GetSingleWordInOperand(1); - return MaybeGetCompositeConstant( - ir_context, transformation_context, - std::vector(component_count, component_id), - scalar_or_composite_type_id, is_irrelevant); - } - case SpvOpTypeArray: { - const auto component_type_id = type_inst->GetSingleWordInOperand(0); - - auto component_id = MaybeGetZeroConstant( - ir_context, transformation_context, component_type_id, is_irrelevant); - - if (component_id == 0 && is_irrelevant) { - // Irrelevant constants can use either relevant or irrelevant - // constituents. - component_id = MaybeGetZeroConstant(ir_context, transformation_context, - component_type_id, false); - } - - if (component_id == 0) { - return 0; - } - - return MaybeGetCompositeConstant( - ir_context, transformation_context, - std::vector(GetArraySize(*type_inst, ir_context), - component_id), - scalar_or_composite_type_id, is_irrelevant); - } - default: - assert(false && "Type is not supported"); - return 0; - } -} - -uint32_t MaybeGetScalarConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& words, uint32_t scalar_type_id, - bool is_irrelevant) { - const auto* type = ir_context->get_type_mgr()->GetType(scalar_type_id); - assert(type && "|scalar_type_id| is invalid"); - - if (const auto* int_type = type->AsInteger()) { - return MaybeGetIntegerConstant(ir_context, transformation_context, words, - int_type->width(), int_type->IsSigned(), - is_irrelevant); - } else if (const auto* float_type = type->AsFloat()) { - return MaybeGetFloatConstant(ir_context, transformation_context, words, - float_type->width(), is_irrelevant); - } else { - assert(type->AsBool() && words.size() == 1 && - "|scalar_type_id| doesn't represent a scalar type"); - return MaybeGetBoolConstant(ir_context, transformation_context, words[0], - is_irrelevant); - } -} - -uint32_t MaybeGetCompositeConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& component_ids, uint32_t composite_type_id, - bool is_irrelevant) { - const auto* type = ir_context->get_type_mgr()->GetType(composite_type_id); - (void)type; // Make compilers happy in release mode. - assert(IsCompositeType(type) && "|composite_type_id| is invalid"); - - for (const auto& inst : ir_context->types_values()) { - if (inst.opcode() == SpvOpConstantComposite && - inst.type_id() == composite_type_id && - transformation_context.GetFactManager()->IdIsIrrelevant( - inst.result_id()) == is_irrelevant && - inst.NumInOperands() == component_ids.size()) { - bool is_match = true; - - for (uint32_t i = 0; i < inst.NumInOperands(); ++i) { - if (inst.GetSingleWordInOperand(i) != component_ids[i]) { - is_match = false; - break; - } - } - - if (is_match) { - return inst.result_id(); - } - } - } - - return 0; -} - -uint32_t MaybeGetIntegerConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& words, uint32_t width, bool is_signed, - bool is_irrelevant) { - if (auto type_id = MaybeGetIntegerType(ir_context, width, is_signed)) { - return MaybeGetOpConstant(ir_context, transformation_context, words, - type_id, is_irrelevant); - } - - return 0; -} - -uint32_t MaybeGetIntegerConstantFromValueAndType(opt::IRContext* ir_context, - uint32_t value, - uint32_t int_type_id) { - auto int_type_inst = ir_context->get_def_use_mgr()->GetDef(int_type_id); - - assert(int_type_inst && "The given type id must exist."); - - auto int_type = ir_context->get_type_mgr() - ->GetType(int_type_inst->result_id()) - ->AsInteger(); - - assert(int_type && int_type->width() == 32 && - "The given type id must correspond to an 32-bit integer type."); - - opt::analysis::IntConstant constant(int_type, {value}); - - // Check that the constant exists in the module. - if (!ir_context->get_constant_mgr()->FindConstant(&constant)) { - return 0; - } - - return ir_context->get_constant_mgr() - ->GetDefiningInstruction(&constant) - ->result_id(); -} - -uint32_t MaybeGetFloatConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& words, uint32_t width, bool is_irrelevant) { - if (auto type_id = MaybeGetFloatType(ir_context, width)) { - return MaybeGetOpConstant(ir_context, transformation_context, words, - type_id, is_irrelevant); - } - - return 0; -} - -uint32_t MaybeGetBoolConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, bool value, - bool is_irrelevant) { - if (auto type_id = MaybeGetBoolType(ir_context)) { - for (const auto& inst : ir_context->types_values()) { - if (inst.opcode() == (value ? SpvOpConstantTrue : SpvOpConstantFalse) && - inst.type_id() == type_id && - transformation_context.GetFactManager()->IdIsIrrelevant( - inst.result_id()) == is_irrelevant) { - return inst.result_id(); - } - } - } - - return 0; -} - -void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width, bool is_signed) { - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeInt, 0, result_id, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {is_signed ? 1u : 0u}}})); - - UpdateModuleIdBound(ir_context, result_id); -} - -void AddFloatType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width) { - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeFloat, 0, result_id, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}}})); - - UpdateModuleIdBound(ir_context, result_id); -} - -void AddVectorType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t component_type_id, uint32_t element_count) { - const auto* component_type = - ir_context->get_type_mgr()->GetType(component_type_id); - (void)component_type; // Make compiler happy in release mode. - assert(component_type && - (component_type->AsInteger() || component_type->AsFloat() || - component_type->AsBool()) && - "|component_type_id| is invalid"); - assert(element_count >= 2 && element_count <= 4 && - "Precondition: component count must be in range [2, 4]."); - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeVector, 0, result_id, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {component_type_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {element_count}}})); - - UpdateModuleIdBound(ir_context, result_id); -} - -void AddStructType(opt::IRContext* ir_context, uint32_t result_id, - const std::vector& component_type_ids) { - opt::Instruction::OperandList operands; - operands.reserve(component_type_ids.size()); - - for (auto type_id : component_type_ids) { - const auto* type = ir_context->get_type_mgr()->GetType(type_id); - (void)type; // Make compiler happy in release mode. - assert(type && !type->AsFunction() && "Component's type id is invalid"); - operands.push_back({SPV_OPERAND_TYPE_ID, {type_id}}); - } - - ir_context->AddType(MakeUnique( - ir_context, SpvOpTypeStruct, 0, result_id, std::move(operands))); - - UpdateModuleIdBound(ir_context, result_id); -} - -bool TypesAreEqualUpToSign(opt::IRContext* ir_context, uint32_t type1_id, - uint32_t type2_id) { - if (type1_id == type2_id) { - return true; - } - - auto type1 = ir_context->get_type_mgr()->GetType(type1_id); - auto type2 = ir_context->get_type_mgr()->GetType(type2_id); - - // Integer scalar types must have the same width - if (type1->AsInteger() && type2->AsInteger()) { - return type1->AsInteger()->width() == type2->AsInteger()->width(); - } - - // Integer vector types must have the same number of components and their - // component types must be integers with the same width. - if (type1->AsVector() && type2->AsVector()) { - auto component_type1 = type1->AsVector()->element_type()->AsInteger(); - auto component_type2 = type2->AsVector()->element_type()->AsInteger(); - - // Only check the component count and width if they are integer. - if (component_type1 && component_type2) { - return type1->AsVector()->element_count() == - type2->AsVector()->element_count() && - component_type1->width() == component_type2->width(); - } - } - - // In all other cases, the types cannot be considered equal. - return false; -} - -std::map RepeatedUInt32PairToMap( - const google::protobuf::RepeatedPtrField& data) { - std::map result; - - for (const auto& entry : data) { - result[entry.first()] = entry.second(); - } - - return result; -} - -google::protobuf::RepeatedPtrField -MapToRepeatedUInt32Pair(const std::map& data) { - google::protobuf::RepeatedPtrField result; - - for (const auto& entry : data) { - protobufs::UInt32Pair pair; - pair.set_first(entry.first); - pair.set_second(entry.second); - *result.Add() = std::move(pair); - } - - return result; -} - -opt::Instruction* GetLastInsertBeforeInstruction(opt::IRContext* ir_context, - uint32_t block_id, - SpvOp opcode) { - // CFG::block uses std::map::at which throws an exception when |block_id| is - // invalid. The error message is unhelpful, though. Thus, we test that - // |block_id| is valid here. - const auto* label_inst = ir_context->get_def_use_mgr()->GetDef(block_id); - (void)label_inst; // Make compilers happy in release mode. - assert(label_inst && label_inst->opcode() == SpvOpLabel && - "|block_id| is invalid"); - - auto* block = ir_context->cfg()->block(block_id); - auto it = block->rbegin(); - assert(it != block->rend() && "Basic block can't be empty"); - - if (block->GetMergeInst()) { - ++it; - assert(it != block->rend() && - "|block| must have at least two instructions:" - "terminator and a merge instruction"); - } - - return CanInsertOpcodeBeforeInstruction(opcode, &*it) ? &*it : nullptr; -} - -} // namespace fuzzerutil -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h deleted file mode 100644 index af709f889..000000000 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_FUZZER_UTIL_H_ -#define SOURCE_FUZZ_FUZZER_UTIL_H_ - -#include -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/transformation_context.h" -#include "source/opt/basic_block.h" -#include "source/opt/instruction.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// Provides types and global utility methods for use by the fuzzer -namespace fuzzerutil { - -// Function type that produces a SPIR-V module. -using ModuleSupplier = std::function()>; - -// Returns true if and only if the module does not define the given id. -bool IsFreshId(opt::IRContext* context, uint32_t id); - -// Updates the module's id bound if needed so that it is large enough to -// account for the given id. -void UpdateModuleIdBound(opt::IRContext* context, uint32_t id); - -// Return the block with id |maybe_block_id| if it exists, and nullptr -// otherwise. -opt::BasicBlock* MaybeFindBlock(opt::IRContext* context, - uint32_t maybe_block_id); - -// When adding an edge from |bb_from| to |bb_to| (which are assumed to be blocks -// in the same function), it is important to supply |bb_to| with ids that can be -// used to augment OpPhi instructions in the case that there is not already such -// an edge. This function returns true if and only if the ids provided in -// |phi_ids| suffice for this purpose, -bool PhiIdsOkForNewEdge( - opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, - const google::protobuf::RepeatedField& phi_ids); - -// Requires that |bool_id| is a valid result id of either OpConstantTrue or -// OpConstantFalse, that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) -// holds, and that bb_from ends with "OpBranch %some_block". Turns OpBranch -// into "OpBranchConditional |condition_value| ...", such that control will -// branch to %some_block, with |bb_to| being the unreachable alternative. -// Updates OpPhi instructions in |bb_to| using |phi_ids| so that the new edge is -// valid. |condition_value| above is equal to |true| if |bool_id| is a result id -// of an OpConstantTrue instruction. -void AddUnreachableEdgeAndUpdateOpPhis( - opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, - uint32_t bool_id, - const google::protobuf::RepeatedField& phi_ids); - -// Returns true if and only if |loop_header_id| is a loop header and -// |block_id| is a reachable block branching to and dominated by -// |loop_header_id|. -bool BlockIsBackEdge(opt::IRContext* context, uint32_t block_id, - uint32_t loop_header_id); - -// Returns true if and only if |maybe_loop_header_id| is a loop header and -// |block_id| is in the continue construct of the associated loop. -bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id, - uint32_t maybe_loop_header_id); - -// If |block| contains |inst|, an iterator for |inst| is returned. -// Otherwise |block|->end() is returned. -opt::BasicBlock::iterator GetIteratorForInstruction( - opt::BasicBlock* block, const opt::Instruction* inst); - -// Returns true if and only if there is a path to |bb| from the entry block of -// the function that contains |bb|. -bool BlockIsReachableInItsFunction(opt::IRContext* context, - opt::BasicBlock* bb); - -// Determines whether it is OK to insert an instruction with opcode |opcode| -// before |instruction_in_block|. -bool CanInsertOpcodeBeforeInstruction( - SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block); - -// Determines whether it is OK to make a synonym of |inst|. -// |transformation_context| is used to verify that the result id of |inst| -// does not participate in IdIsIrrelevant fact. -bool CanMakeSynonymOf(opt::IRContext* ir_context, - const TransformationContext& transformation_context, - opt::Instruction* inst); - -// Determines whether the given type is a composite; that is: an array, matrix, -// struct or vector. -bool IsCompositeType(const opt::analysis::Type* type); - -// Returns a vector containing the same elements as |repeated_field|. -std::vector RepeatedFieldToVector( - const google::protobuf::RepeatedField& repeated_field); - -// Given a type id, |base_object_type_id|, returns 0 if the type is not a -// composite type or if |index| is too large to be used as an index into the -// composite. Otherwise returns the type id of the type associated with the -// composite's index. -// -// Example: if |base_object_type_id| is 10, and we have: -// -// %10 = OpTypeStruct %3 %4 %5 -// -// then 3 will be returned if |index| is 0, 5 if |index| is 2, and 0 if index -// is 3 or larger. -uint32_t WalkOneCompositeTypeIndex(opt::IRContext* context, - uint32_t base_object_type_id, - uint32_t index); - -// Given a type id, |base_object_type_id|, checks that the given sequence of -// |indices| is suitable for indexing into this type. Returns the id of the -// type of the final sub-object reached via the indices if they are valid, and -// 0 otherwise. -uint32_t WalkCompositeTypeIndices( - opt::IRContext* context, uint32_t base_object_type_id, - const google::protobuf::RepeatedField& indices); - -// Returns the number of members associated with |struct_type_instruction|, -// which must be an OpStructType instruction. -uint32_t GetNumberOfStructMembers( - const opt::Instruction& struct_type_instruction); - -// Returns the constant size of the array associated with -// |array_type_instruction|, which must be an OpArrayType instruction. Returns -// 0 if there is not a static size. -uint32_t GetArraySize(const opt::Instruction& array_type_instruction, - opt::IRContext* context); - -// Returns the bound for indexing into a composite of type -// |composite_type_inst|, i.e. the number of fields of a struct, the size of an -// array, the number of components of a vector, or the number of columns of a -// matrix. |composite_type_inst| must be the type of a composite. -uint32_t GetBoundForCompositeIndex(const opt::Instruction& composite_type_inst, - opt::IRContext* ir_context); - -// Returns true if and only if |context| is valid, according to the validator -// instantiated with |validator_options|. -bool IsValid(opt::IRContext* context, spv_validator_options validator_options); - -// Returns a clone of |context|, by writing |context| to a binary and then -// parsing it again. -std::unique_ptr CloneIRContext(opt::IRContext* context); - -// Returns true if and only if |id| is the id of a type that is not a function -// type. -bool IsNonFunctionTypeId(opt::IRContext* ir_context, uint32_t id); - -// Returns true if and only if |block_id| is a merge block or continue target -bool IsMergeOrContinue(opt::IRContext* ir_context, uint32_t block_id); - -// Returns the result id of an instruction of the form: -// %id = OpTypeFunction |type_ids| -// or 0 if no such instruction exists. -uint32_t FindFunctionType(opt::IRContext* ir_context, - const std::vector& type_ids); - -// Returns a type instruction (OpTypeFunction) for |function|. -// Returns |nullptr| if type is not found. -opt::Instruction* GetFunctionType(opt::IRContext* context, - const opt::Function* function); - -// Returns the function with result id |function_id|, or |nullptr| if no such -// function exists. -opt::Function* FindFunction(opt::IRContext* ir_context, uint32_t function_id); - -// Returns true if |function| has a block that the termination instruction is -// OpKill or OpUnreachable. -bool FunctionContainsOpKillOrUnreachable(const opt::Function& function); - -// Returns |true| if one of entry points has function id |function_id|. -bool FunctionIsEntryPoint(opt::IRContext* context, uint32_t function_id); - -// Checks whether |id| is available (according to dominance rules) at the use -// point defined by input operand |use_input_operand_index| of -// |use_instruction|. -bool IdIsAvailableAtUse(opt::IRContext* context, - opt::Instruction* use_instruction, - uint32_t use_input_operand_index, uint32_t id); - -// Checks whether |id| is available (according to dominance rules) at the -// program point directly before |instruction|. -bool IdIsAvailableBeforeInstruction(opt::IRContext* context, - opt::Instruction* instruction, uint32_t id); - -// Returns true if and only if |instruction| is an OpFunctionParameter -// associated with |function|. -bool InstructionIsFunctionParameter(opt::Instruction* instruction, - opt::Function* function); - -// Returns the type id of the instruction defined by |result_id|, or 0 if there -// is no such result id. -uint32_t GetTypeId(opt::IRContext* context, uint32_t result_id); - -// Given |pointer_type_inst|, which must be an OpTypePointer instruction, -// returns the id of the associated pointee type. -uint32_t GetPointeeTypeIdFromPointerType(opt::Instruction* pointer_type_inst); - -// Given |pointer_type_id|, which must be the id of a pointer type, returns the -// id of the associated pointee type. -uint32_t GetPointeeTypeIdFromPointerType(opt::IRContext* context, - uint32_t pointer_type_id); - -// Given |pointer_type_inst|, which must be an OpTypePointer instruction, -// returns the associated storage class. -SpvStorageClass GetStorageClassFromPointerType( - opt::Instruction* pointer_type_inst); - -// Given |pointer_type_id|, which must be the id of a pointer type, returns the -// associated storage class. -SpvStorageClass GetStorageClassFromPointerType(opt::IRContext* context, - uint32_t pointer_type_id); - -// Returns the id of a pointer with pointee type |pointee_type_id| and storage -// class |storage_class|, if it exists, and 0 otherwise. -uint32_t MaybeGetPointerType(opt::IRContext* context, uint32_t pointee_type_id, - SpvStorageClass storage_class); - -// Given an instruction |inst| and an operand absolute index |absolute_index|, -// returns the index of the operand restricted to the input operands. -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); - -// 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 -// to be listed in that entry point's interface. -bool GlobalVariablesMustBeDeclaredInEntryPointInterfaces( - const opt::IRContext* context); - -// Adds |id| into the interface of every entry point of the shader. -// Does nothing if SPIR-V doesn't require global variables, that are accessed -// from an entry point function, to be listed in that function's interface. -void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id); - -// Adds a global variable with storage class |storage_class| to the module, with -// type |type_id| and either no initializer or |initializer_id| as an -// initializer, depending on whether |initializer_id| is 0. The global variable -// has result id |result_id|. Updates module's id bound to accommodate for -// |result_id|. -// -// - |type_id| must be the id of a pointer type with the same storage class as -// |storage_class|. -// - |storage_class| must be Private or Workgroup. -// - |initializer_id| must be 0 if |storage_class| is Workgroup, and otherwise -// may either be 0 or the id of a constant whose type is the pointee type of -// |type_id|. -void AddGlobalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, SpvStorageClass storage_class, - uint32_t initializer_id); - -// Adds an instruction to the start of |function_id|, of the form: -// |result_id| = OpVariable |type_id| Function |initializer_id|. -// Updates module's id bound to accommodate for |result_id|. -// -// - |type_id| must be the id of a pointer type with Function storage class. -// - |initializer_id| must be the id of a constant with the same type as the -// pointer's pointee type. -// - |function_id| must be the id of a function. -void AddLocalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, uint32_t function_id, - uint32_t initializer_id); - -// Returns true if the vector |arr| has duplicates. -bool HasDuplicates(const std::vector& arr); - -// Checks that the given vector |arr| contains a permutation of a range -// [lo, hi]. That being said, all elements in the range are present without -// duplicates. If |arr| is empty, returns true iff |lo > hi|. -bool IsPermutationOfRange(const std::vector& arr, uint32_t lo, - uint32_t hi); - -// Returns OpFunctionParameter instructions corresponding to the function -// with result id |function_id|. -std::vector GetParameters(opt::IRContext* ir_context, - uint32_t function_id); - -// Removes an OpFunctionParameter instruction with result id |parameter_id| -// from the its function. Parameter's function must not be an entry-point -// function. The function must have a parameter with result id |parameter_id|. -// -// Prefer using this function to opt::Function::RemoveParameter since -// this function also guarantees that |ir_context| has no invalid pointers -// to the removed parameter. -void RemoveParameter(opt::IRContext* ir_context, uint32_t parameter_id); - -// Returns all OpFunctionCall instructions that call a function with result id -// |function_id|. -std::vector GetCallers(opt::IRContext* ir_context, - uint32_t function_id); - -// Returns a function that contains OpFunctionParameter instruction with result -// id |param_id|. Returns nullptr if the module has no such function. -opt::Function* GetFunctionFromParameterId(opt::IRContext* ir_context, - uint32_t param_id); - -// Changes the type of function |function_id| so that its return type is -// |return_type_id| and its parameters' types are |parameter_type_ids|. If a -// suitable function type already exists in the module, it is used, otherwise -// |new_function_type_result_id| is used as the result id of a suitable new -// function type instruction. If the old type of the function doesn't have any -// more users, it is removed from the module. Returns the result id of the -// OpTypeFunction instruction that is used as a type of the function with -// |function_id|. -// -// CAUTION: When the old type of the function is removed from the module, its -// memory is deallocated. Be sure not to use any pointers to the old -// type when this function returns. -uint32_t UpdateFunctionType(opt::IRContext* ir_context, uint32_t function_id, - uint32_t new_function_type_result_id, - uint32_t return_type_id, - const std::vector& parameter_type_ids); - -// Creates new OpTypeFunction instruction in the module. |type_ids| may not be -// empty. It may not contain result ids of OpTypeFunction instructions. -// |type_ids[i]| may not be a result id of OpTypeVoid instruction for |i >= 1|. -// |result_id| may not equal to 0. Updates module's id bound to accommodate for -// |result_id|. -void AddFunctionType(opt::IRContext* ir_context, uint32_t result_id, - const std::vector& type_ids); - -// Returns a result id of an OpTypeFunction instruction in the module. Creates a -// new instruction if required and returns |result_id|. type_ids| may not be -// empty. It may not contain result ids of OpTypeFunction instructions. -// |type_ids[i]| may not be a result id of OpTypeVoid instruction for |i >= 1|. -// |result_id| must not be equal to 0. Updates module's id bound to accommodate -// for |result_id|. -uint32_t FindOrCreateFunctionType(opt::IRContext* ir_context, - uint32_t result_id, - const std::vector& type_ids); - -// Returns a result id of an OpTypeInt instruction if present. Returns 0 -// otherwise. -uint32_t MaybeGetIntegerType(opt::IRContext* ir_context, uint32_t width, - bool is_signed); - -// Returns a result id of an OpTypeFloat instruction if present. Returns 0 -// otherwise. -uint32_t MaybeGetFloatType(opt::IRContext* ir_context, uint32_t width); - -// Returns a result id of an OpTypeBool instruction if present. Returns 0 -// otherwise. -uint32_t MaybeGetBoolType(opt::IRContext* ir_context); - -// Returns a result id of an OpTypeVector instruction if present. Returns 0 -// otherwise. |component_type_id| must be a valid result id of an OpTypeInt, -// OpTypeFloat or OpTypeBool instruction in the module. |element_count| must be -// in the range [2, 4]. -uint32_t MaybeGetVectorType(opt::IRContext* ir_context, - uint32_t component_type_id, uint32_t element_count); - -// Returns a result id of an OpTypeStruct instruction if present. Returns 0 -// otherwise. |component_type_ids| may not contain a result id of an -// OpTypeFunction. -uint32_t MaybeGetStructType(opt::IRContext* ir_context, - const std::vector& component_type_ids); - -// Recursive definition is the following: -// - if |scalar_or_composite_type_id| is a result id of a scalar type - returns -// a result id of the following constants (depending on the type): int -> 0, -// float -> 0.0, bool -> false. -// - otherwise, returns a result id of an OpConstantComposite instruction. -// Every component of the composite constant is looked up by calling this -// function with the type id of that component. -// Returns 0 if no such instruction is present in the module. -// The returned id either participates in IdIsIrrelevant fact or not, depending -// on the |is_irrelevant| parameter. -uint32_t MaybeGetZeroConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - uint32_t scalar_or_composite_type_id, bool is_irrelevant); - -// Returns the result id of an OpConstant instruction. |scalar_type_id| must be -// a result id of a scalar type (i.e. int, float or bool). Returns 0 if no such -// instruction is present in the module. The returned id either participates in -// IdIsIrrelevant fact or not, depending on the |is_irrelevant| parameter. -uint32_t MaybeGetScalarConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& words, uint32_t scalar_type_id, - bool is_irrelevant); - -// Returns the result id of an OpConstantComposite instruction. -// |composite_type_id| must be a result id of a composite type (i.e. vector, -// matrix, struct or array). Returns 0 if no such instruction is present in the -// module. The returned id either participates in IdIsIrrelevant fact or not, -// depending on the |is_irrelevant| parameter. -uint32_t MaybeGetCompositeConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& component_ids, uint32_t composite_type_id, - bool is_irrelevant); - -// Returns the result id of an OpConstant instruction of integral type. -// Returns 0 if no such instruction or type is present in the module. -// The returned id either participates in IdIsIrrelevant fact or not, depending -// on the |is_irrelevant| parameter. -uint32_t MaybeGetIntegerConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& words, uint32_t width, bool is_signed, - bool is_irrelevant); - -// Returns the id of a 32-bit integer constant in the module with type -// |int_type_id| and value |value|, or 0 if no such constant exists in the -// module. |int_type_id| must exist in the module and it must correspond to a -// 32-bit integer type. -uint32_t MaybeGetIntegerConstantFromValueAndType(opt::IRContext* ir_context, - uint32_t value, - uint32_t int_type_id); - -// Returns the result id of an OpConstant instruction of floating-point type. -// Returns 0 if no such instruction or type is present in the module. -// The returned id either participates in IdIsIrrelevant fact or not, depending -// on the |is_irrelevant| parameter. -uint32_t MaybeGetFloatConstant( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - const std::vector& words, uint32_t width, bool is_irrelevant); - -// Returns the id of a boolean constant with value |value| if it exists in the -// module, or 0 otherwise. The returned id either participates in IdIsIrrelevant -// fact or not, depending on the |is_irrelevant| parameter. -uint32_t MaybeGetBoolConstant( - opt::IRContext* context, - const TransformationContext& transformation_context, bool value, - bool is_irrelevant); - -// Creates a new OpTypeInt instruction in the module. Updates module's id bound -// to accommodate for |result_id|. -void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width, bool is_signed); - -// Creates a new OpTypeFloat instruction in the module. Updates module's id -// bound to accommodate for |result_id|. -void AddFloatType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width); - -// Creates a new OpTypeVector instruction in the module. |component_type_id| -// must be a valid result id of an OpTypeInt, OpTypeFloat or OpTypeBool -// instruction in the module. |element_count| must be in the range [2, 4]. -// Updates module's id bound to accommodate for |result_id|. -void AddVectorType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t component_type_id, uint32_t element_count); - -// Creates a new OpTypeStruct instruction in the module. Updates module's id -// bound to accommodate for |result_id|. |component_type_ids| may not contain -// a result id of an OpTypeFunction. -void AddStructType(opt::IRContext* ir_context, uint32_t result_id, - const std::vector& component_type_ids); - -// Returns a bit pattern that represents a floating-point |value|. -inline uint32_t FloatToWord(float value) { - uint32_t result; - memcpy(&result, &value, sizeof(uint32_t)); - return result; -} - -// Returns true if any of the following is true: -// - |type1_id| and |type2_id| are the same id -// - |type1_id| and |type2_id| refer to integer scalar or vector types, only -// differing by their signedness. -bool TypesAreEqualUpToSign(opt::IRContext* ir_context, uint32_t type1_id, - uint32_t type2_id); - -// Converts repeated field of UInt32Pair to a map. If two or more equal values -// of |UInt32Pair::first()| are available in |data|, the last value of -// |UInt32Pair::second()| is used. -std::map RepeatedUInt32PairToMap( - const google::protobuf::RepeatedPtrField& data); - -// Converts a map into a repeated field of UInt32Pair. -google::protobuf::RepeatedPtrField -MapToRepeatedUInt32Pair(const std::map& data); - -// Returns the last instruction in |block_id| before which an instruction with -// opcode |opcode| can be inserted, or nullptr if there is no such instruction. -opt::Instruction* GetLastInsertBeforeInstruction(opt::IRContext* ir_context, - uint32_t block_id, - SpvOp opcode); - -} // namespace fuzzerutil -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_FUZZER_UTIL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.cpp b/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.cpp deleted file mode 100644 index 4e10146fa..000000000 --- a/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/id_use_descriptor.h" - -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -opt::Instruction* FindInstructionContainingUse( - const protobufs::IdUseDescriptor& id_use_descriptor, - opt::IRContext* context) { - auto result = - FindInstruction(id_use_descriptor.enclosing_instruction(), context); - if (!result) { - return nullptr; - } - if (id_use_descriptor.in_operand_index() >= result->NumInOperands()) { - return nullptr; - } - if (result->GetSingleWordInOperand(id_use_descriptor.in_operand_index()) != - id_use_descriptor.id_of_interest()) { - return nullptr; - } - return result; -} - -protobufs::IdUseDescriptor MakeIdUseDescriptor( - uint32_t id_of_interest, - const protobufs::InstructionDescriptor& enclosing_instruction, - uint32_t in_operand_index) { - protobufs::IdUseDescriptor result; - result.set_id_of_interest(id_of_interest); - *result.mutable_enclosing_instruction() = enclosing_instruction; - result.set_in_operand_index(in_operand_index); - return result; -} - -protobufs::IdUseDescriptor MakeIdUseDescriptorFromUse( - opt::IRContext* context, opt::Instruction* inst, - uint32_t in_operand_index) { - const auto& in_operand = inst->GetInOperand(in_operand_index); - assert(spvIsInIdType(in_operand.type)); - return MakeIdUseDescriptor(in_operand.words[0], - MakeInstructionDescriptor(context, inst), - in_operand_index); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.h b/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.h deleted file mode 100644 index d18bb668d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/id_use_descriptor.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_ -#define SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_ - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// Looks for an instruction in |context| that contains a use -// identified by |id_use_descriptor|. -// Returns |nullptr| if no such instruction can be found. -opt::Instruction* FindInstructionContainingUse( - const protobufs::IdUseDescriptor& id_use_descriptor, - opt::IRContext* context); - -// Creates an IdUseDescriptor protobuf message from the given components. -// See the protobuf definition for details of what these components mean. -protobufs::IdUseDescriptor MakeIdUseDescriptor( - uint32_t id_of_interest, - const protobufs::InstructionDescriptor& enclosing_instruction, - uint32_t in_operand_index); - -// Given an id use, represented by the instruction |inst| that uses the id, and -// the input operand index |in_operand_index| associated with the usage, returns -// an IdUseDescriptor that represents the use. -protobufs::IdUseDescriptor MakeIdUseDescriptorFromUse( - opt::IRContext* context, opt::Instruction* inst, uint32_t in_operand_index); - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/instruction_descriptor.cpp b/3rdparty/spirv-tools/source/fuzz/instruction_descriptor.cpp deleted file mode 100644 index c0cc5e52c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/instruction_descriptor.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -opt::Instruction* FindInstruction( - const protobufs::InstructionDescriptor& instruction_descriptor, - spvtools::opt::IRContext* context) { - for (auto& function : *context->module()) { - for (auto& block : function) { - bool found_base = - block.id() == instruction_descriptor.base_instruction_result_id(); - uint32_t num_ignored = 0; - for (auto& instruction : block) { - if (instruction.HasResultId() && - instruction.result_id() == - instruction_descriptor.base_instruction_result_id()) { - assert(!found_base && - "It should not be possible to find the base instruction " - "multiple times."); - found_base = true; - assert(num_ignored == 0 && - "The skipped instruction count should only be incremented " - "after the instruction base has been found."); - } - if (found_base && - instruction.opcode() == - instruction_descriptor.target_instruction_opcode()) { - if (num_ignored == instruction_descriptor.num_opcodes_to_ignore()) { - return &instruction; - } - num_ignored++; - } - } - if (found_base) { - // We found the base instruction, but did not find the target - // instruction in the same block. - return nullptr; - } - } - } - return nullptr; -} - -protobufs::InstructionDescriptor MakeInstructionDescriptor( - uint32_t base_instruction_result_id, SpvOp target_instruction_opcode, - uint32_t num_opcodes_to_ignore) { - protobufs::InstructionDescriptor result; - result.set_base_instruction_result_id(base_instruction_result_id); - result.set_target_instruction_opcode(target_instruction_opcode); - result.set_num_opcodes_to_ignore(num_opcodes_to_ignore); - return result; -} - -protobufs::InstructionDescriptor MakeInstructionDescriptor( - const opt::BasicBlock& block, - const opt::BasicBlock::const_iterator& inst_it) { - const SpvOp opcode = - inst_it->opcode(); // The opcode of the instruction being described. - uint32_t skip_count = 0; // The number of these opcodes we have skipped when - // searching backwards. - - // Consider instructions in the block in reverse order, starting from - // |inst_it|. - for (opt::BasicBlock::const_iterator backwards_iterator = inst_it;; - --backwards_iterator) { - if (backwards_iterator->HasResultId()) { - // As soon as we find an instruction with a result id, we can return a - // descriptor for |inst_it|. - return MakeInstructionDescriptor(backwards_iterator->result_id(), opcode, - skip_count); - } - if (backwards_iterator != inst_it && - backwards_iterator->opcode() == opcode) { - // We are skipping over an instruction with the same opcode as |inst_it|; - // we increase our skip count to reflect this. - skip_count++; - } - if (backwards_iterator == block.begin()) { - // We exit the loop when we reach the start of the block, but only after - // we have processed the first instruction in the block. - break; - } - } - // We did not find an instruction inside the block with a result id, so we use - // the block's label's id. - return MakeInstructionDescriptor(block.id(), opcode, skip_count); -} - -protobufs::InstructionDescriptor MakeInstructionDescriptor( - opt::IRContext* context, opt::Instruction* inst) { - auto block = context->get_instr_block(inst); - uint32_t base_instruction_result_id = block->id(); - uint32_t num_opcodes_to_ignore = 0; - for (auto& inst_in_block : *block) { - if (inst_in_block.HasResultId()) { - base_instruction_result_id = inst_in_block.result_id(); - num_opcodes_to_ignore = 0; - } - if (&inst_in_block == inst) { - return MakeInstructionDescriptor(base_instruction_result_id, - inst->opcode(), num_opcodes_to_ignore); - } - if (inst_in_block.opcode() == inst->opcode()) { - num_opcodes_to_ignore++; - } - } - assert(false && "No matching instruction was found."); - return protobufs::InstructionDescriptor(); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/instruction_descriptor.h b/3rdparty/spirv-tools/source/fuzz/instruction_descriptor.h deleted file mode 100644 index 2ccd15a23..000000000 --- a/3rdparty/spirv-tools/source/fuzz/instruction_descriptor.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_ -#define SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_ - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/basic_block.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// Looks for an instruction in |context| corresponding to |descriptor|. -// Returns |nullptr| if no such instruction can be found. -opt::Instruction* FindInstruction( - const protobufs::InstructionDescriptor& instruction_descriptor, - opt::IRContext* context); - -// Creates an InstructionDescriptor protobuf message from the given -// components. See the protobuf definition for details of what these -// components mean. -protobufs::InstructionDescriptor MakeInstructionDescriptor( - uint32_t base_instruction_result_id, SpvOp target_instruction_opcode, - uint32_t num_opcodes_to_ignore); - -// Returns an instruction descriptor that describing the instruction at -// |inst_it|, which must be inside |block|. The descriptor will be with -// respect to the first instruction at or before |inst_it| that has a result -// id. -protobufs::InstructionDescriptor MakeInstructionDescriptor( - const opt::BasicBlock& block, - const opt::BasicBlock::const_iterator& inst_it); - -// Returns an InstructionDescriptor that describes the given instruction |inst|. -protobufs::InstructionDescriptor MakeInstructionDescriptor( - opt::IRContext* context, opt::Instruction* inst); - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/instruction_message.cpp b/3rdparty/spirv-tools/source/fuzz/instruction_message.cpp deleted file mode 100644 index 44777aede..000000000 --- a/3rdparty/spirv-tools/source/fuzz/instruction_message.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/instruction_message.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -protobufs::Instruction MakeInstructionMessage( - SpvOp opcode, uint32_t result_type_id, uint32_t result_id, - const opt::Instruction::OperandList& input_operands) { - protobufs::Instruction result; - result.set_opcode(opcode); - result.set_result_type_id(result_type_id); - result.set_result_id(result_id); - for (auto& operand : input_operands) { - auto operand_message = result.add_input_operand(); - operand_message->set_operand_type(static_cast(operand.type)); - for (auto operand_word : operand.words) { - operand_message->add_operand_data(operand_word); - } - } - return result; -} - -std::unique_ptr InstructionFromMessage( - opt::IRContext* ir_context, - const protobufs::Instruction& instruction_message) { - // First, update the module's id bound with respect to the new instruction, - // if it has a result id. - if (instruction_message.result_id()) { - fuzzerutil::UpdateModuleIdBound(ir_context, - instruction_message.result_id()); - } - // Now create a sequence of input operands from the input operand data in the - // protobuf message. - opt::Instruction::OperandList in_operands; - for (auto& operand_message : instruction_message.input_operand()) { - opt::Operand::OperandData operand_data; - for (auto& word : operand_message.operand_data()) { - operand_data.push_back(word); - } - in_operands.push_back( - {static_cast(operand_message.operand_type()), - operand_data}); - } - // Create and return the instruction. - return MakeUnique( - ir_context, static_cast(instruction_message.opcode()), - instruction_message.result_type_id(), instruction_message.result_id(), - in_operands); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/instruction_message.h b/3rdparty/spirv-tools/source/fuzz/instruction_message.h deleted file mode 100644 index c010c2f6a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/instruction_message.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_INSTRUCTION_MESSAGE_H_ -#define SOURCE_FUZZ_INSTRUCTION_MESSAGE_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/instruction.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// Creates an Instruction protobuf message from its component parts. -protobufs::Instruction MakeInstructionMessage( - SpvOp opcode, uint32_t result_type_id, uint32_t result_id, - const opt::Instruction::OperandList& input_operands); - -// Creates and returns an opt::Instruction from protobuf message -// |instruction_message|, relative to |ir_context|. In the process, the module -// id bound associated with |ir_context| is updated to be at least as large as -// the result id (if any) associated with the new instruction. -std::unique_ptr InstructionFromMessage( - opt::IRContext* ir_context, - const protobufs::Instruction& instruction_message); - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_INSTRUCTION_MESSAGE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/overflow_id_source.cpp b/3rdparty/spirv-tools/source/fuzz/overflow_id_source.cpp deleted file mode 100644 index d90045546..000000000 --- a/3rdparty/spirv-tools/source/fuzz/overflow_id_source.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/overflow_id_source.h" - -namespace spvtools { -namespace fuzz { - -OverflowIdSource::~OverflowIdSource() = default; - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/overflow_id_source.h b/3rdparty/spirv-tools/source/fuzz/overflow_id_source.h deleted file mode 100644 index b428fa540..000000000 --- a/3rdparty/spirv-tools/source/fuzz/overflow_id_source.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_ -#define SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_ - -#include - -namespace spvtools { -namespace fuzz { - -// An implementation of this interface can be used to provide fresh ids on -// demand when applying a transformation. -// -// During fuzzing this should never be required: a fuzzer pass should determine -// all the fresh ids it requires to apply a transformation. -// -// However, during shrinking we can have the situation where, after removing -// an early transformation, a later transformation needs more ids. -// -// As an example, suppose a SPIR-V function originally has this form: -// -// main() { -// stmt1; -// stmt2; -// stmt3; -// stmt4; -// } -// -// Now suppose two *outlining* transformations are applied. The first -// transformation, T1, outlines "stmt1; stmt2;" into a function foo, giving us: -// -// foo() { -// stmt1; -// stmt2; -// } -// -// main() { -// foo(); -// stmt3; -// stmt4; -// } -// -// The second transformation, T2, outlines "foo(); stmt3;" from main into a -// function bar, giving us: -// -// foo() { -// stmt1; -// stmt2; -// } -// -// bar() { -// foo(); -// stmt3; -// } -// -// main() { -// bar(); -// stmt4; -// } -// -// Suppose that T2 used a set of fresh ids, FRESH, in order to perform its -// outlining. -// -// Now suppose that during shrinking we remove T1, but still want to apply T2. -// The fresh ids used by T2 - FRESH - are sufficient to outline "foo(); stmt3;". -// However, because we did not apply T1, "foo();" does not exist and instead the -// task of T2 is to outline "stmt1; stmt2; stmt3;". The set FRESH contains -// *some* of the fresh ids required to do this (those for "stmt3;"), but not all -// of them (those for "stmt1; stmt2;" are missing). -// -// A source of overflow ids can be used to allow the shrinker to proceed -// nevertheless. -// -// It is desirable to use overflow ids only when needed. In our worked example, -// T2 should still use the ids from FRESH when handling "stmt3;", because later -// transformations might refer to those ids and will become inapplicable if -// overflow ids are used instead. -class OverflowIdSource { - public: - virtual ~OverflowIdSource(); - - // Returns true if and only if this source is capable of providing overflow - // ids. - virtual bool HasOverflowIds() const = 0; - - // Precondition: HasOverflowIds() must hold. Returns the next available - // overflow id. - virtual uint32_t GetNextOverflowId() = 0; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h b/3rdparty/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h deleted file mode 100644 index 26b8672f1..000000000 --- a/3rdparty/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ -#define SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ - -// This header file serves to act as a barrier between the protobuf header -// files and files that include them. It uses compiler pragmas to disable -// diagnostics, in order to ignore warnings generated during the processing -// of these header files without having to compromise on freedom from warnings -// in the rest of the project. - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-parameter" -#elif defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wshadow" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#elif defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4244) -#endif - -// The following should be the only place in the project where protobuf files -// are directly included. This is so that they can be compiled in a manner -// where warnings are ignored. - -#include "google/protobuf/util/json_util.h" -#include "google/protobuf/util/message_differencer.h" -#include "source/fuzz/protobufs/spvtoolsfuzz.pb.h" - -#if defined(__clang__) -#pragma clang diagnostic pop -#elif defined(__GNUC__) -#pragma GCC diagnostic pop -#elif defined(_MSC_VER) -#pragma warning(pop) -#endif - -#endif // SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto deleted file mode 100644 index ed3ce0e3f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto +++ /dev/null @@ -1,1700 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This file is specifically named spvtools_fuzz.proto so that the string -// 'spvtools_fuzz' appears in the names of global-scope symbols that protoc -// generates when targeting C++. This is to reduce the potential for name -// clashes with other globally-scoped symbols. - -syntax = "proto3"; - -package spvtools.fuzz.protobufs; - -message UInt32Pair { - - // A pair of uint32s; useful for defining mappings. - - uint32 first = 1; - - uint32 second = 2; - -} - -message InstructionDescriptor { - - // Describes an instruction in some block of a function with respect to a - // base instruction. - - // The id of an instruction after which the instruction being described is - // believed to be located. It might be the using instruction itself. - uint32 base_instruction_result_id = 1; - - // The opcode for the instruction being described. - uint32 target_instruction_opcode = 2; - - // The number of matching opcodes to skip over when searching from the base - // instruction to the instruction being described. - uint32 num_opcodes_to_ignore = 3; - -} - -message IdUseDescriptor { - - // Describes a use of an id as an input operand to an instruction in some - // block of a function. - - // Example: - // - id_of_interest = 42 - // - enclosing_instruction = ( - // base_instruction_result_id = 50, - // target_instruction_opcode = OpStore - // num_opcodes_to_ignore = 7 - // ) - // - in_operand_index = 1 - // represents a use of id 42 as input operand 1 to an OpStore instruction, - // such that the OpStore instruction can be found in the same basic block as - // the instruction with result id 50, and in particular is the 8th OpStore - // instruction found from instruction 50 onwards (i.e. 7 OpStore - // instructions are skipped). - - // An id that we would like to be able to find a use of. - uint32 id_of_interest = 1; - - // The input operand index at which the use is expected. - InstructionDescriptor enclosing_instruction = 2; - - uint32 in_operand_index = 3; - -} - -message DataDescriptor { - - // Represents a data element that can be accessed from an id, by walking the - // type hierarchy via a sequence of 0 or more indices. - // - // Very similar to a UniformBufferElementDescriptor, except that a - // DataDescriptor is rooted at the id of a scalar or composite. - - // The object being accessed - a scalar or composite - uint32 object = 1; - - // 0 or more indices, used to index into a composite object - repeated uint32 index = 2; - -} - -message UniformBufferElementDescriptor { - - // Represents a data element inside a uniform buffer. The element is - // specified via (a) the result id of a uniform variable in which the element - // is contained, and (b) a series of indices that need to be followed to get - // to the element (via fields and array/vector indices). - // - // Example: suppose there is a uniform variable with descriptor set 7 and - // binding 9, and that the uniform variable has the following type (using - // GLSL-like syntax): - // - // struct S { - // float f; - // vec3 g; - // int4 h[10]; - // }; - // - // Then: - // - (7, 9, [0]) describes the 'f' field. - // - (7, 9, [1,1]) describes the y component of the 'g' field. - // - (7, 9, [2,7,3]) describes the w component of element 7 of the 'h' field - - // The descriptor set and binding associated with a uniform variable. - uint32 descriptor_set = 1; - uint32 binding = 2; - - // An ordered sequence of indices through composite structures in the - // uniform buffer. - repeated uint32 index = 3; - -} - -message InstructionOperand { - - // Represents an operand to a SPIR-V instruction. - - // The type of the operand. - uint32 operand_type = 1; - - // The data associated with the operand. For most operands (e.g. ids, - // storage classes and literals) this will be a single word. - repeated uint32 operand_data = 2; - -} - -message Instruction { - - // Represents a SPIR-V instruction. - - // The instruction's opcode (e.g. OpLabel). - uint32 opcode = 1; - - // The id of the instruction's result type; 0 if there is no result type. - uint32 result_type_id = 2; - - // The id of the instruction's result; 0 if there is no result. - uint32 result_id = 3; - - // Zero or more input operands. - repeated InstructionOperand input_operand = 4; - -} - -message FactSequence { - repeated Fact fact = 1; -} - -message Fact { - oneof fact { - // Order the fact options by numeric id (rather than alphabetically). - FactConstantUniform constant_uniform_fact = 1; - FactDataSynonym data_synonym_fact = 2; - FactBlockIsDead block_is_dead_fact = 3; - FactFunctionIsLivesafe function_is_livesafe_fact = 4; - FactPointeeValueIsIrrelevant pointee_value_is_irrelevant_fact = 5; - FactIdEquation id_equation_fact = 6; - FactIdIsIrrelevant id_is_irrelevant = 7; - } -} - -// Keep fact message types in alphabetical order: - -message FactBlockIsDead { - - // Records the fact that a block is guaranteed to be dynamically unreachable. - // This is useful because it informs the fuzzer that rather arbitrary changes - // can be made to this block. - - uint32 block_id = 1; - -} - -message FactConstantUniform { - - // Records the fact that a uniform buffer element is guaranteed to be equal - // to a particular constant value. spirv-fuzz can use such guarantees to - // obfuscate code, e.g. to manufacture an expression that will (due to the - // guarantee) evaluate to a particular value at runtime but in a manner that - // cannot be predicted at compile-time. - - // An element of a uniform buffer - UniformBufferElementDescriptor uniform_buffer_element_descriptor = 1; - - // The words of the associated constant - repeated uint32 constant_word = 2; - -} - -message FactDataSynonym { - - // Records the fact that the data held in two data descriptors are guaranteed - // to be equal. spirv-fuzz can use this to replace uses of one piece of data - // with a known-to-be-equal piece of data. - - // Data descriptors guaranteed to hold identical data. - DataDescriptor data1 = 1; - - DataDescriptor data2 = 2; - -} - -message FactFunctionIsLivesafe { - - // Records the fact that a function is guaranteed to be "livesafe", meaning - // that it will not make out-of-bounds accesses, does not contain reachable - // OpKill or OpUnreachable instructions, does not contain loops that will - // execute for large numbers of iterations, and only invokes other livesafe - // functions. - - uint32 function_id = 1; - -} - -message FactIdEquation { - - // Records the fact that the equation: - // - // lhs_id = opcode rhs_id[0] rhs_id[1] ... rhs_id[N-1] - // - // holds; e.g. that the equation: - // - // %12 = OpIAdd %13 %14 - // - // holds in the case where lhs_id is 12, rhs_id is [13, 14], and the opcode is - // OpIAdd. - - // The left-hand-side of the equation. - uint32 lhs_id = 1; - - // A SPIR-V opcode, from a restricted set of instructions for which equation - // facts make sense. - uint32 opcode = 2; - - // The operands to the right-hand-side of the equation. - repeated uint32 rhs_id = 3; - -} - -message FactIdIsIrrelevant { - - // Records a fact that |result_id| is irrelevant (i.e. it's usage doesn't - // change the semantics of the module). This implies that a use of this id - // can later be replaced with some other id of the same type, or the - // definition of |result_id| can be changed so that it yields a different value. - - // An irrelevant id. - uint32 result_id = 1; - -} - -message FactPointeeValueIsIrrelevant { - - // Records the fact that value of the data pointed to by a pointer id does - // not influence the observable behaviour of the module. This means that - // arbitrary stores can be made through the pointer, and that nothing can be - // guaranteed about the values that are loaded via the pointer. - - // A result id of pointer type - uint32 pointer_id = 1; - -} - -message AccessChainClampingInfo { - - // When making a function livesafe it is necessary to clamp the indices that - // occur as operands to access chain instructions so that they are guaranteed - // to be in bounds. This message type allows an access chain instruction to - // have an associated sequence of ids that are reserved for comparing an - // access chain index with a bound (e.g. an array size), and selecting - // between the access chain index (if it is within bounds) and the bound (if - // it is not). - // - // This allows turning an instruction of the form: - // - // %result = OpAccessChain %type %object ... %index ... - // - // into: - // - // %t1 = OpULessThanEqual %bool %index %bound_minus_one - // %t2 = OpSelect %int_type %t1 %index %bound_minus_one - // %result = OpAccessChain %type %object ... %t2 ... - - // The result id of an OpAccessChain or OpInBoundsAccessChain instruction. - uint32 access_chain_id = 1; - - // A series of pairs of fresh ids, one per access chain index, for the results - // of a compare instruction and a select instruction, serving the roles of %t1 - // and %t2 in the above example. - repeated UInt32Pair compare_and_select_ids = 2; - -} - -message LoopLimiterInfo { - - // Structure capturing the information required to manipulate a loop limiter - // at a loop header. - - // The header for the loop. - uint32 loop_header_id = 1; - - // A fresh id into which the loop limiter's current value can be loaded. - uint32 load_id = 2; - - // A fresh id that can be used to increment the loaded value by 1. - uint32 increment_id = 3; - - // A fresh id that can be used to compare the loaded value with the loop - // limit. - uint32 compare_id = 4; - - // A fresh id that can be used to compute the conjunction or disjunction of - // an original loop exit condition with |compare_id|, if the loop's back edge - // block can conditionally exit the loop. - uint32 logical_op_id = 5; - - // A sequence of ids suitable for extending OpPhi instructions of the loop - // merge block if it did not previously have an incoming edge from the loop - // back edge block. - repeated uint32 phi_id = 6; - -} - -message TransformationSequence { - repeated Transformation transformation = 1; -} - -message Transformation { - oneof transformation { - // Order the transformation options by numeric id (rather than - // alphabetically). - TransformationMoveBlockDown move_block_down = 1; - TransformationSplitBlock split_block = 2; - TransformationAddConstantBoolean add_constant_boolean = 3; - TransformationAddConstantScalar add_constant_scalar = 4; - TransformationAddTypeBoolean add_type_boolean = 5; - TransformationAddTypeFloat add_type_float = 6; - TransformationAddTypeInt add_type_int = 7; - TransformationAddDeadBreak add_dead_break = 8; - TransformationReplaceBooleanConstantWithConstantBinary - replace_boolean_constant_with_constant_binary = 9; - TransformationAddTypePointer add_type_pointer = 10; - TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11; - TransformationAddDeadContinue add_dead_continue = 12; - TransformationReplaceIdWithSynonym replace_id_with_synonym = 13; - TransformationSetSelectionControl set_selection_control = 14; - TransformationCompositeConstruct composite_construct = 15; - TransformationSetLoopControl set_loop_control = 16; - TransformationSetFunctionControl set_function_control = 17; - TransformationAddNoContractionDecoration add_no_contraction_decoration = 18; - TransformationSetMemoryOperandsMask set_memory_operands_mask = 19; - TransformationCompositeExtract composite_extract = 20; - TransformationVectorShuffle vector_shuffle = 21; - TransformationOutlineFunction outline_function = 22; - TransformationMergeBlocks merge_blocks = 23; - TransformationAddTypeVector add_type_vector = 24; - TransformationAddTypeArray add_type_array = 25; - TransformationAddTypeMatrix add_type_matrix = 26; - TransformationAddTypeStruct add_type_struct = 27; - TransformationAddTypeFunction add_type_function = 28; - TransformationAddConstantComposite add_constant_composite = 29; - TransformationAddGlobalVariable add_global_variable = 30; - TransformationAddGlobalUndef add_global_undef = 31; - TransformationAddFunction add_function = 32; - TransformationAddDeadBlock add_dead_block = 33; - TransformationAddLocalVariable add_local_variable = 34; - TransformationLoad load = 35; - TransformationStore store = 36; - TransformationFunctionCall function_call = 37; - TransformationAccessChain access_chain = 38; - TransformationEquationInstruction equation_instruction = 39; - TransformationSwapCommutableOperands swap_commutable_operands = 40; - TransformationPermuteFunctionParameters permute_function_parameters = 41; - TransformationToggleAccessChainInstruction toggle_access_chain_instruction = 42; - TransformationAddConstantNull add_constant_null = 43; - TransformationComputeDataSynonymFactClosure compute_data_synonym_fact_closure = 44; - TransformationAdjustBranchWeights adjust_branch_weights = 45; - TransformationPushIdThroughVariable push_id_through_variable = 46; - TransformationAddSpecConstantOp add_spec_constant_op = 47; - TransformationReplaceLinearAlgebraInstruction replace_linear_algebra_instruction = 48; - TransformationSwapConditionalBranchOperands swap_conditional_branch_operands = 49; - TransformationPermutePhiOperands permute_phi_operands = 50; - TransformationAddParameter add_parameter = 51; - TransformationAddCopyMemory add_copy_memory = 52; - TransformationInvertComparisonOperator invert_comparison_operator = 53; - TransformationAddImageSampleUnusedComponents add_image_sample_unused_components = 54; - TransformationReplaceParameterWithGlobal replace_parameter_with_global = 55; - TransformationRecordSynonymousConstants record_synonymous_constants = 56; - TransformationAddSynonym add_synonym = 57; - TransformationAddRelaxedDecoration add_relaxed_decoration = 58; - TransformationReplaceParamsWithStruct replace_params_with_struct = 59; - TransformationReplaceCopyObjectWithStoreLoad replace_copy_object_with_store_load = 60; - TransformationReplaceCopyMemoryWithLoadStore replace_copy_memory_with_load_store = 61; - TransformationReplaceLoadStoreWithCopyMemory replace_load_store_with_copy_memory = 62; - TransformationAddLoopPreheader add_loop_preheader = 63; - TransformationMoveInstructionDown move_instruction_down = 64; - TransformationMakeVectorOperationDynamic make_vector_operation_dynamic = 65; - TransformationReplaceAddSubMulWithCarryingExtended replace_add_sub_mul_with_carrying_extended = 66; - TransformationPropagateInstructionUp propagate_instruction_up = 67; - TransformationCompositeInsert composite_insert = 68; - TransformationInlineFunction inline_function = 69; - TransformationAddOpPhiSynonym add_opphi_synonym = 70; - // Add additional option using the next available number. - } -} - -// Keep transformation message types in alphabetical order: - -message TransformationAccessChain { - - // Adds an access chain instruction based on a given pointer and indices. - - // When accessing a struct, the corresponding indices must be 32-bit integer constants. - // For any other composite, the indices can be any 32-bit integer, and the transformation - // adds two instructions for each such index to clamp it to the bound, as follows: - // - // %t1 = OpULessThanEqual %bool %index %bound_minus_one - // %t2 = OpSelect %int_type %t1 %index %bound_minus_one - - // Result id for the access chain - uint32 fresh_id = 1; - - // The pointer from which the access chain starts - uint32 pointer_id = 2; - - // Zero or more access chain indices - repeated uint32 index_id = 3; - - // A descriptor for an instruction in a block before which the new - // OpAccessChain instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 4; - - // Additional fresh ids, required to clamp index variables. A pair is needed - // for each access to a non-struct composite. - repeated UInt32Pair fresh_ids_for_clamping = 5; - -} - -message TransformationAddConstantBoolean { - - // Supports adding the constants true and false to a module, which may be - // necessary in order to enable other transformations if they are not present. - // Also, creates an IdIsIrrelevant fact about |fresh_id| if |is_irrelevant| is true. - - uint32 fresh_id = 1; - bool is_true = 2; - - // If the constant should be marked as irrelevant. - bool is_irrelevant = 3; - -} - -message TransformationAddConstantComposite { - - // Adds a constant of the given composite type to the module. - // Also, creates an IdIsIrrelevant fact about |fresh_id| if - // |is_irrelevant| is true. - - // Fresh id for the composite - uint32 fresh_id = 1; - - // A composite type id - uint32 type_id = 2; - - // Constituent ids for the composite - repeated uint32 constituent_id = 3; - - // If the constant should be marked as irrelevant. - bool is_irrelevant = 4; - -} - -message TransformationAddConstantNull { - - // Adds a null constant. - - // Id for the constant - uint32 fresh_id = 1; - - // Type of the constant - uint32 type_id = 2; - -} - -message TransformationAddConstantScalar { - - // Adds a constant of the given scalar type. - // Also, creates an IdIsIrrelevant fact about - // |fresh_id| if |is_irrelevant| is true. - - // Id for the constant - uint32 fresh_id = 1; - - // Id for the scalar type of the constant - uint32 type_id = 2; - - // Value of the constant - repeated uint32 word = 3; - - // If the constant should be marked as irrelevant. - bool is_irrelevant = 4; - -} - -message TransformationAddCopyMemory { - - // Adds an OpCopyMemory instruction into the module. - // Creates either a global or a local variable (based on - // |storage_class| field) to copy the target into. - - // OpCopyMemory will be inserted before this instruction. - InstructionDescriptor instruction_descriptor = 1; - - // Fresh id to copy memory into. - uint32 fresh_id = 2; - - // Source to copy memory from. - uint32 source_id = 3; - - // Storage class for the target variable. Can be either Function or Private. - uint32 storage_class = 4; - - // Result id for the variable's initializer operand. Its type must be equal to - // variable's pointee type. - uint32 initializer_id = 5; - -} - -message TransformationAddDeadBlock { - - // Adds a new block to the module that is statically reachable from an - // existing block, but dynamically unreachable. - - // Fresh id for the dead block - uint32 fresh_id = 1; - - // Id of an existing block terminated with OpBranch, such that this OpBranch - // can be replaced with an OpBranchConditional to its exiting successor or - // the dead block - uint32 existing_block = 2; - - // Determines whether the condition associated with the OpBranchConditional - // is true or false - bool condition_value = 3; - -} - -message TransformationAddDeadBreak { - - // A transformation that turns a basic block that unconditionally branches to - // its successor into a block that potentially breaks out of a structured - // control flow construct, but in such a manner that the break cannot actually - // be taken. - - // The block to break from - uint32 from_block = 1; - - // The merge block to break to - uint32 to_block = 2; - - // Determines whether the break condition is true or false - bool break_condition_value = 3; - - // A sequence of ids suitable for extending OpPhi instructions as a result of - // the new break edge - repeated uint32 phi_id = 4; - -} - -message TransformationAddDeadContinue { - - // A transformation that turns a basic block appearing in a loop and that - // unconditionally branches to its successor into a block that potentially - // branches to the continue target of the loop, but in such a manner that the - // continue branch cannot actually be taken. - - // The block to continue from - uint32 from_block = 1; - - // Determines whether the continue condition is true or false - bool continue_condition_value = 2; - - // A sequence of ids suitable for extending OpPhi instructions as a result of - // the new break edge - repeated uint32 phi_id = 3; - -} - -message TransformationAddFunction { - - // Adds a SPIR-V function to the module. - - // The series of instructions that comprise the function. - repeated Instruction instruction = 1; - - // True if and only if the given function should be made livesafe (see - // FactFunctionIsLivesafe for definition). - bool is_livesafe = 2; - - // Fresh id for a new variable that will serve as a "loop limiter" for the - // function; only relevant if |is_livesafe| holds. - uint32 loop_limiter_variable_id = 3; - - // Id of an existing unsigned integer constant providing the maximum value - // that the loop limiter can reach before the loop is broken from; only - // relevant if |is_livesafe| holds. - uint32 loop_limit_constant_id = 4; - - // Fresh ids for each loop in the function that allow the loop limiter to be - // manipulated; only relevant if |is_livesafe| holds. - repeated LoopLimiterInfo loop_limiter_info = 5; - - // Id of an existing global value with the same return type as the function - // that can be used to replace OpKill and OpReachable instructions with - // ReturnValue instructions. Ignored if the function has void return type. - uint32 kill_unreachable_return_value_id = 6; - - // A mapping (represented as a sequence) from every access chain result id in - // the function to the ids required to clamp its indices to ensure they are in - // bounds. - repeated AccessChainClampingInfo access_chain_clamping_info = 7; - -} - -message TransformationAddGlobalUndef { - - // Adds an undefined value of a given type to the module at global scope. - - // Fresh id for the undefined value - uint32 fresh_id = 1; - - // The type of the undefined value - uint32 type_id = 2; - -} - -message TransformationAddGlobalVariable { - - // Adds a global variable of the given type to the module, with Private or - // Workgroup storage class, and optionally (for the Private case) with an - // initializer. - - // Fresh id for the global variable - uint32 fresh_id = 1; - - // The type of the global variable - uint32 type_id = 2; - - uint32 storage_class = 3; - - // Initial value of the variable - uint32 initializer_id = 4; - - // True if and only if the behaviour of the module should not depend on the - // value of the variable, in which case stores to the variable can be - // performed in an arbitrary fashion. - bool value_is_irrelevant = 5; - -} - -message TransformationAddImageSampleUnusedComponents { - - // A transformation that adds unused components to an image sample coordinate. - - // An vector id with the original coordinate and the unused components. - uint32 coordinate_with_unused_components_id = 1; - - // A descriptor for an image sample instruction. - InstructionDescriptor instruction_descriptor = 2; - -} - -message TransformationAddLocalVariable { - - // Adds a local variable of the given type (which must be a pointer with - // Function storage class) to the given function, initialized to the given - // id. - - // Fresh id for the local variable - uint32 fresh_id = 1; - - // The type of the local variable - uint32 type_id = 2; - - // The id of the function to which the local variable should be added - uint32 function_id = 3; - - // Initial value of the variable - uint32 initializer_id = 4; - - // True if and only if the behaviour of the module should not depend on the - // value of the variable, in which case stores to the variable can be - // performed in an arbitrary fashion. - bool value_is_irrelevant = 5; - -} - -message TransformationAddLoopPreheader { - - // A transformation that adds a loop preheader block before the given loop header. - - // The id of the loop header block - uint32 loop_header_block = 1; - - // A fresh id for the preheader block - uint32 fresh_id = 2; - - // Fresh ids for splitting the OpPhi instructions in the header. - // A new OpPhi instruction in the preheader is needed for each OpPhi instruction in the header, - // if the header has more than one predecessor outside of the loop. - // This allows turning instructions of the form: - // - // %loop_header_block = OpLabel - // %id1 = OpPhi %type %val1 %pred1_id %val2 %pred2_id %val3 %backedge_block_id - // - // into: - // %fresh_id = OpLabel - // %phi_id1 = OpPhi %type %val1 %pred1_id %val2 %pred2_id - // OpBranch %header_id - // %loop_header_block = OpLabel - // %id1 = OpPhi %type %phi_id1 %fresh_id %val3 %backedge_block_id - repeated uint32 phi_id = 3; - -} - -message TransformationAddNoContractionDecoration { - - // Applies OpDecorate NoContraction to the given result id - - // Result id to be decorated - uint32 result_id = 1; - -} - -message TransformationAddOpPhiSynonym { - - // Adds an OpPhi instruction at the start of a block with n predecessors (pred_1, pred_2, ..., pred_n) - // and n related ids (id_1, id_2, ..., id_n) which are pairwise synonymous. - // The instruction will be of the form: - // %fresh_id = OpPhi %type %id_1 %pred_1 %id_2 %pred_2 ... %id_n %pred_n - // and fresh_id will be recorded as being synonymous with all the other ids. - - // Label id of the block - uint32 block_id = 1; - - // Pairs (pred_i, id_i) - repeated UInt32Pair pred_to_id = 2; - - // Fresh id for the new instruction - uint32 fresh_id = 3; -} - -message TransformationAddParameter { - - // Adds a new parameter into the function. - - // Result id of the function to add parameters to. - uint32 function_id = 1; - - // Fresh id for a new parameter. - uint32 parameter_fresh_id = 2; - - // Type id for a new parameter. - uint32 parameter_type_id = 3; - - // A map that maps from the OpFunctionCall id to the id that will be passed as the new - // parameter at that call site. It must have the same type as that of the new parameter. - repeated UInt32Pair call_parameter_ids = 4; - - // A fresh id for a new function type. This might not be used - // if a required function type already exists or if we can change - // the old function type. - uint32 function_type_fresh_id = 5; - -} - -message TransformationAddRelaxedDecoration { - - // Applies OpDecorate RelaxedPrecision to the given result id - - // Result id to be decorated - uint32 result_id = 1; - -} - -message TransformationAddSpecConstantOp { - - // Adds OpSpecConstantOp into the module. - - // Result id for the new instruction. - uint32 fresh_id = 1; - - // Type id for the new instruction. - uint32 type_id = 2; - - // Opcode operand of the OpSpecConstantOp instruction. - uint32 opcode = 3; - - // Operands of the |opcode| instruction. - repeated InstructionOperand operand = 4; - -} - -message TransformationAddSynonym { - - // Adds a |synonymous_instruction| before |insert_before| instruction with - // and creates a fact that |result_id| and the result id of |synonymous_instruction| - // are synonymous. - - // Result id of the first synonym. - uint32 result_id = 1; - - // Type of the synonym to apply. Some types might produce instructions - // with commutative operands. Such types do not specify the order of the - // operands since we have a special transformation to swap commutable operands. - // - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3499): - // Consider adding more types here. - enum SynonymType { - // New synonym is derived by adding zero to the |result_id|. - ADD_ZERO = 0; - - // New synonym is derived by subtracting zero from the |result_id|. - SUB_ZERO = 1; - - // New synonym is derived by multiplying |result_id| by one. - MUL_ONE = 2; - - // New synonym is derived by applying OpCopyObject instruction to |result_id|. - COPY_OBJECT = 3; - - // New synonym is derived by applying OpLogicalOr to |result_id| with the second - // operand being 'false'. - LOGICAL_OR = 4; - - // New synonym is derived by applying OpLogicalAnd to |result_id| with the second - // operand being 'true'. - LOGICAL_AND = 5; - } - - // Type of the synonym to create. See SynonymType for more details. - SynonymType synonym_type = 2; - - // Fresh result id for a created synonym. - uint32 synonym_fresh_id = 3; - - // An instruction to insert a new synonym before. - InstructionDescriptor insert_before = 4; - -} - -message TransformationAddTypeArray { - - // Adds an array type of the given element type and size to the module - - // Fresh id for the array type - uint32 fresh_id = 1; - - // The array's element type - uint32 element_type_id = 2; - - // The array's size - uint32 size_id = 3; - -} - -message TransformationAddTypeBoolean { - - // Adds OpTypeBool to the module - - // Id to be used for the type - uint32 fresh_id = 1; - -} - -message TransformationAddTypeFloat { - - // Adds OpTypeFloat to the module with the given width - - // Id to be used for the type - uint32 fresh_id = 1; - - // Floating-point width - uint32 width = 2; - -} - -message TransformationAddTypeFunction { - - // Adds a function type to the module - - // Fresh id for the function type - uint32 fresh_id = 1; - - // The function's return type - uint32 return_type_id = 2; - - // The function's argument types - repeated uint32 argument_type_id = 3; - -} - -message TransformationAddTypeInt { - - // Adds OpTypeInt to the module with the given width and signedness - - // Id to be used for the type - uint32 fresh_id = 1; - - // Integer width - uint32 width = 2; - - // True if and only if this is a signed type - bool is_signed = 3; - -} - -message TransformationAddTypeMatrix { - - // Adds a matrix type to the module - - // Fresh id for the matrix type - uint32 fresh_id = 1; - - // The matrix's column type, which must be a floating-point vector (as per - // the "data rules" in the SPIR-V specification). - uint32 column_type_id = 2; - - // The matrix's column count - uint32 column_count = 3; - -} - -message TransformationAddTypePointer { - - // Adds OpTypePointer to the module, with the given storage class and base - // type - - // Id to be used for the type - uint32 fresh_id = 1; - - // Pointer storage class - uint32 storage_class = 2; - - // Id of the base type for the pointer - uint32 base_type_id = 3; - -} - -message TransformationAddTypeStruct { - - // Adds a struct type to the module - - // Fresh id for the struct type - uint32 fresh_id = 1; - - // The struct's member types - repeated uint32 member_type_id = 3; - -} - -message TransformationAddTypeVector { - - // Adds a vector type to the module - - // Fresh id for the vector type - uint32 fresh_id = 1; - - // The vector's component type - uint32 component_type_id = 2; - - // The vector's component count - uint32 component_count = 3; - -} - -message TransformationAdjustBranchWeights { - - // A transformation that adjusts the branch weights - // of a branch conditional instruction. - - // A descriptor for a branch conditional instruction. - InstructionDescriptor instruction_descriptor = 1; - - // Branch weights of a branch conditional instruction. - UInt32Pair branch_weights = 2; - -} - -message TransformationCompositeConstruct { - - // A transformation that introduces an OpCompositeConstruct instruction to - // make a composite object. - - // Id of the type of the composite that is to be constructed - uint32 composite_type_id = 1; - - // Ids of the objects that will form the components of the composite - repeated uint32 component = 2; - - // A descriptor for an instruction in a block before which the new - // OpCompositeConstruct instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 3; - - // A fresh id for the composite object - uint32 fresh_id = 4; - -} - -message TransformationCompositeExtract { - - // A transformation that adds an instruction to extract an element from a - // composite. - - // A descriptor for an instruction in a block before which the new - // OpCompositeExtract instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 1; - - // Result id for the extract operation. - uint32 fresh_id = 2; - - // Id of the composite from which data is to be extracted. - uint32 composite_id = 3; - - // Indices that indicate which part of the composite should be extracted. - repeated uint32 index = 4; - -} - -message TransformationCompositeInsert { - - // A transformation that adds an instruction OpCompositeInsert which creates - // a new composite from an existing composite, with an element inserted. - - // A descriptor for an instruction before which the new instruction - // OpCompositeInsert should be inserted. - InstructionDescriptor instruction_to_insert_before = 1; - - // Result id of the inserted OpCompositeInsert instruction. - uint32 fresh_id = 2; - - // Id of the composite used as the basis for the insertion. - uint32 composite_id = 3; - - // Id of the object to be inserted. - uint32 object_id = 4; - - // Indices that indicate which part of the composite should be inserted into. - repeated uint32 index = 5; - -} - -message TransformationComputeDataSynonymFactClosure { - - // A transformation that impacts the fact manager only, forcing a computation - // of the closure of data synonym facts, so that e.g. if the components of - // vectors v and w are known to be pairwise synonymous, it is deduced that v - // and w are themselves synonymous. - - // When searching equivalence classes for implied facts, equivalence classes - // larger than this size will be skipped. - uint32 maximum_equivalence_class_size = 1; - -} - -message TransformationEquationInstruction { - - // A transformation that adds an instruction to the module that defines an - // equation between its result id and input operand ids, such that the - // equation is guaranteed to hold at any program point where all ids involved - // are available (i.e. at any program point dominated by the instruction). - - // The result id of the new instruction - uint32 fresh_id = 1; - - // The instruction's opcode - uint32 opcode = 2; - - // The input operands to the instruction - repeated uint32 in_operand_id = 3; - - // A descriptor for an instruction in a block before which the new - // instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 4; - -} - -message TransformationFunctionCall { - - // A transformation that introduces an OpFunctionCall instruction. The call - // must not make the module's call graph cyclic. Beyond that, if the call - // is in a dead block it can be to any function with arbitrary suitably-typed - // arguments; otherwise it must be to a livesafe function, with injected - // variables as pointer arguments and arbitrary non-pointer arguments. - - // A fresh id for the result of the call - uint32 fresh_id = 1; - - // Id of the function to be called - uint32 callee_id = 2; - - // Ids for arguments to the function - repeated uint32 argument_id = 3; - - // A descriptor for an instruction in a block before which the new - // OpFunctionCall instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 4; - -} - -message TransformationInlineFunction { - - // This transformation inlines a function by mapping the function instructions to fresh ids. - - // Result id of the function call instruction. - uint32 function_call_id = 1; - - // For each result id defined by the called function, - // this map provides an associated fresh id that can - // be used in the inlined version of the function call. - repeated UInt32Pair result_id_map = 2; - -} - -message TransformationInvertComparisonOperator { - - // For some instruction with result id |operator_id| that - // represents a binary comparison operator (e.g. <, >, <=), this transformation - // will replace that instruction's result id with |fresh_id|, - // invert the opcode (< will become >=) and insert OpLogicalNot - // instruction with result id |operator_id| below. - - // Result id of the instruction to invert. - uint32 operator_id = 1; - - // Fresh id that will be used by the operator after the inversion. - uint32 fresh_id = 2; - -} - -message TransformationLoad { - - // Transformation that adds an OpLoad instruction from a pointer into an id. - - // The result of the load instruction - uint32 fresh_id = 1; - - // The pointer to be loaded from - uint32 pointer_id = 2; - - // A descriptor for an instruction in a block before which the new OpLoad - // instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 3; - -} - -message TransformationMakeVectorOperationDynamic { - - // A transformation that replaces the OpCompositeExtract and OpCompositeInsert - // instructions with the OpVectorExtractDynamic and OpVectorInsertDynamic instructions. - - // The composite instruction result id. - uint32 instruction_result_id = 1; - - // The OpCompositeExtract/Insert instructions accept integer literals as indices to the composite object. - // However, the OpVectorInsert/ExtractDynamic instructions require its single index to be an integer instruction. - // This is the result id of the integer instruction. - uint32 constant_index_id = 2; - -} - -message TransformationMergeBlocks { - - // A transformation that merges a block with its predecessor. - - // The id of the block that is to be merged with its predecessor; the merged - // block will have the *predecessor's* id. - uint32 block_id = 1; - -} - -message TransformationMoveBlockDown { - - // A transformation that moves a basic block to be one position lower in - // program order. - - // The id of the block to move down. - uint32 block_id = 1; -} - -message TransformationMoveInstructionDown { - - // Swaps |instruction| with the next instruction in the block. - - // The instruction to move down. - InstructionDescriptor instruction = 1; - -} - -message TransformationOutlineFunction { - - // A transformation that outlines a single-entry single-exit region of a - // control flow graph into a separate function, and replaces the region with - // a call to that function. - - // Id of the entry block of the single-entry single-exit region to be outlined - uint32 entry_block = 1; - - // Id of the exit block of the single-entry single-exit region to be outlined - uint32 exit_block = 2; - - // Id of a struct that will store the return values of the new function - uint32 new_function_struct_return_type_id = 3; - - // A fresh id for the type of the outlined function - uint32 new_function_type_id = 4; - - // A fresh id for the outlined function itself - uint32 new_function_id = 5; - - // A fresh id to represent the block in the outlined function that represents - // the first block of the outlined region. - uint32 new_function_region_entry_block = 6; - - // A fresh id for the result of the OpFunctionCall instruction that will call - // the outlined function - uint32 new_caller_result_id = 7; - - // A fresh id to capture the return value of the outlined function - the - // argument to OpReturn - uint32 new_callee_result_id = 8; - - // Ids defined outside the region and used inside the region will become - // parameters to the outlined function. This is a mapping from used ids to - // fresh parameter ids. - repeated UInt32Pair input_id_to_fresh_id = 9; - - // Ids defined inside the region and used outside the region will become - // fresh ids defined by the outlined function, which get copied into the - // function's struct return value and then copied into their destination ids - // by the caller. This is a mapping from original ids to corresponding fresh - // ids. - repeated UInt32Pair output_id_to_fresh_id = 10; - -} - -message TransformationPermuteFunctionParameters { - - // A transformation that, given a non-entry-point function taking n - // parameters and a permutation of the set [0, n-1]: - // - Introduces a new function type that is the same as the original - // function's type but with the order of arguments permuted - // (only if it doesn't already exist) - // - Changes the type of the function to this type - // - Adjusts all calls to the function so that their arguments are permuted - - // Function, whose parameters will be permuted - uint32 function_id = 1; - - // Fresh id for a new type of the function. This might not be used - // if a required function type already exists or if we can change - // the old function type. - uint32 function_type_fresh_id = 2; - - // An array of size |n|, where |n| is a number of arguments to a function - // with |function_id|. For each i: 0 <= permutation[i] < n. - // - // i-th element of this array contains a position for an i-th - // function's argument (i.e. i-th argument will be permutation[i]-th - // after running this transformation) - repeated uint32 permutation = 3; - -} - -message TransformationPermutePhiOperands { - - // Permutes operands of some OpPhi instruction. - - // Result id of the instruction to apply the transformation to. - uint32 result_id = 1; - - // A sequence of numbers in the range [0, n/2 - 1] where |n| is the number - // of operands of the OpPhi instruction with |result_id|. - repeated uint32 permutation = 2; - -} - -message TransformationPropagateInstructionUp { - - // Propagates an instruction in the block into the block's predecessors. - // Concretely, this transformation clones some particular instruction from - // the |block_id| into every block's predecessor and replaces the original - // instruction with OpPhi. Take a look at the transformation class to learn - // more about how we choose what instruction to propagate. - - // Id of the block to propagate an instruction from. - uint32 block_id = 1; - - // A map from the id of some predecessor of the |block_id| to the fresh id. - // The map contains a fresh id for at least every predecessor of the |block_id|. - // The instruction is propagated by creating a number of clones - one clone for - // each predecessor. Fresh ids from this field are used as result ids of cloned - // instructions. - repeated UInt32Pair predecessor_id_to_fresh_id = 2; - -} - -message TransformationPushIdThroughVariable { - - // A transformation that makes |value_synonym_id| and |value_id| to be - // synonymous by storing |value_id| into |variable_id| and - // loading |variable_id| to |value_synonym_id|. - - // The value to be stored. - uint32 value_id = 1; - - // A fresh id for the result of the load instruction. - uint32 value_synonym_id = 2; - - // A fresh id for the variable to be stored to. - uint32 variable_id = 3; - - // Constant to initialize the variable from. - uint32 initializer_id = 4; - - // The variable storage class (global or local). - uint32 variable_storage_class = 5; - - // A descriptor for an instruction which the new OpStore - // and OpLoad instructions might be inserted before. - InstructionDescriptor instruction_descriptor = 6; - -} - -message TransformationRecordSynonymousConstants { - - // A transformation that, given the IDs to two synonymous constants, - // records the fact that they are synonymous. The module is not changed. - // Two constants are synonymous if: - // - they have the same type (ignoring the presence of integer sign) - // - they have the same opcode (one of OpConstant, OpConstantTrue, - // OpConstantFalse, OpConstantNull) - // - they have the same value - // If the types are the same, OpConstantNull is equivalent to - // OpConstantFalse or OpConstant with value zero. - - // The id of a constant - uint32 constant1_id = 1; - - // The id of the synonym - uint32 constant2_id = 2; - -} - -message TransformationReplaceAddSubMulWithCarryingExtended { - - // Replaces OpIAdd with OpIAddCarry, OpISub with OpISubBorrow, OpIMul - // with OpUMulExtended or OpSMulExtended (depending on the signedness - // of the operands) and stores the result into a |struct_fresh_id|. - // In the original instruction the result type id and the type ids of - // the operands must be the same. Then the transformation extracts - // the first element of the result into the original |result_id|. - // This value is the same as the result of the original instruction. - - // The fresh id of the intermediate result. - uint32 struct_fresh_id = 1; - - // The result id of the original instruction. - uint32 result_id = 2; - -} - -message TransformationReplaceParameterWithGlobal { - - // Removes parameter with result id |parameter_id| from its function - // and creates a global variable to pass its value to the function instead. - - // Fresh id for a new function type. This might not be used if a required - // function type already exists or if we can change the old function type. - uint32 function_type_fresh_id = 2; - - // Result id of the OpFunctionParameter instruction to remove. - uint32 parameter_id = 3; - - // Fresh id of a global variable used to pass parameter's value to the function. - uint32 global_variable_fresh_id = 4; - -} - -message TransformationReplaceBooleanConstantWithConstantBinary { - - // A transformation to capture replacing a use of a boolean constant with - // binary operation on two constant values - - // A descriptor for the boolean constant id we would like to replace - IdUseDescriptor id_use_descriptor = 1; - - // Id for the constant to be used on the LHS of the comparision - uint32 lhs_id = 2; - - // Id for the constant to be used on the RHS of the comparision - uint32 rhs_id = 3; - - // Opcode for binary operator - uint32 opcode = 4; - - // Id that will store the result of the binary operation instruction - uint32 fresh_id_for_binary_operation = 5; - -} - -message TransformationReplaceConstantWithUniform { - - // Replaces a use of a constant id with the result of a load from an - // element of uniform buffer known to hold the same value as the constant - - // A descriptor for the id we would like to replace - IdUseDescriptor id_use_descriptor = 1; - - // Uniform descriptor to identify which uniform value to choose - UniformBufferElementDescriptor uniform_descriptor = 2; - - // Id that will store the result of an access chain - uint32 fresh_id_for_access_chain = 3; - - // Id that will store the result of a load - uint32 fresh_id_for_load = 4; - -} - -message TransformationReplaceCopyMemoryWithLoadStore { - - // A transformation that replaces instructions OpCopyMemory with loading - // the source variable to an intermediate value and storing this value into the - // target variable of the original OpCopyMemory instruction. - - // The intermediate value. - uint32 fresh_id = 1; - - // The instruction descriptor to OpCopyMemory. It is necessary, because - // OpCopyMemory doesn't have a result id. - InstructionDescriptor copy_memory_instruction_descriptor = 2; -} - -message TransformationReplaceCopyObjectWithStoreLoad { - - // A transformation that replaces instruction OpCopyObject with - // storing into a new variable and immediately loading from this - // variable to |result_id| of the original OpCopyObject instruction. - - // The result id of initial OpCopyObject instruction - uint32 copy_object_result_id = 1; - - // A fresh id for the variable to be stored to. - uint32 fresh_variable_id = 2; - - // The variable storage class (Function or Private). - uint32 variable_storage_class = 3; - - // Constant to initialize the variable with. - uint32 variable_initializer_id = 4; -} - -message TransformationReplaceIdWithSynonym { - - // Replaces a use of an id with an id that is known to be synonymous, e.g. - // because it was obtained via applying OpCopyObject - - // The id use that is to be replaced - IdUseDescriptor id_use_descriptor = 1; - - // The synonymous id - uint32 synonymous_id = 2; - -} - -message TransformationReplaceLinearAlgebraInstruction { - - // Replaces a linear algebra instruction with its - // mathematical definition. - - // The fresh ids needed to apply the transformation. - repeated uint32 fresh_ids = 1; - - // A descriptor for a linear algebra instruction. - InstructionDescriptor instruction_descriptor = 2; - -} - -message TransformationReplaceLoadStoreWithCopyMemory { - // A transformation that takes a pair of instruction descriptors - // to OpLoad and OpStore that have the same intermediate value - // and replaces the OpStore with an equivalent OpCopyMemory. - - // The instruction descriptor to OpLoad - InstructionDescriptor load_instruction_descriptor = 1; - - // The instruction descriptor to OpStore - InstructionDescriptor store_instruction_descriptor = 2; -} - -message TransformationReplaceParamsWithStruct { - - // Replaces parameters of the function with a struct containing - // values of those parameters. - - // Result ids of parameters to replace. - repeated uint32 parameter_id = 1; - - // Fresh id for a new function type. This might be unused if the required type - // already exists in the module or if we can change the old type. - uint32 fresh_function_type_id = 2; - - // Fresh id for a new struct function parameter to be used as a replacement. - uint32 fresh_parameter_id = 3; - - // Fresh ids for struct objects containing values of replaced parameters. - // This field contains a fresh id for at least every result id of a relevant - // OpFunctionCall instruction. - repeated UInt32Pair caller_id_to_fresh_composite_id = 4; - -} - -message TransformationSetFunctionControl { - - // A transformation that sets the function control operand of an OpFunction - // instruction. - - // The result id of an OpFunction instruction - uint32 function_id = 1; - - // The value to which the 'function control' operand should be set. - uint32 function_control = 2; - -} - -message TransformationSetLoopControl { - - // A transformation that sets the loop control operand of an OpLoopMerge - // instruction. - - // The id of a basic block that should contain OpLoopMerge - uint32 block_id = 1; - - // The value to which the 'loop control' operand should be set. - // This must be a legal loop control mask. - uint32 loop_control = 2; - - // Provides a peel count value for the loop. Used if and only if the - // PeelCount bit is set. Must be zero if the PeelCount bit is not set (can - // still be zero if this bit is set). - uint32 peel_count = 3; - - // Provides a partial count value for the loop. Used if and only if the - // PartialCount bit is set. Must be zero if the PartialCount bit is not set - // (can still be zero if this bit is set). - uint32 partial_count = 4; - -} - -message TransformationSetMemoryOperandsMask { - - // A transformation that sets the memory operands mask of a memory access - // instruction. - - // A descriptor for a memory access instruction, e.g. an OpLoad - InstructionDescriptor memory_access_instruction = 1; - - // A mask of memory operands to be applied to the instruction. It must be the - // same as the original mask, except that Volatile can be added, and - // Nontemporal can be added or removed. - uint32 memory_operands_mask = 2; - - // Some memory access instructions allow more than one mask to be specified; - // this field indicates which mask should be set - uint32 memory_operands_mask_index = 3; - -} - -message TransformationSetSelectionControl { - - // A transformation that sets the selection control operand of an - // OpSelectionMerge instruction. - - // The id of a basic block that should contain OpSelectionMerge - uint32 block_id = 1; - - // The value to which the 'selection control' operand should be set. - // Although technically 'selection control' is a literal mask that can be - // some combination of 'None', 'Flatten' and 'DontFlatten', the combination - // 'Flatten | DontFlatten' does not make sense and is not allowed here. - uint32 selection_control = 2; - -} - -message TransformationSplitBlock { - - // A transformation that splits a basic block into two basic blocks - - // A descriptor for an instruction such that the block containing the - // described instruction should be split right before the instruction. - InstructionDescriptor instruction_to_split_before = 1; - - // An id that must not yet be used by the module to which this transformation - // is applied. Rather than having the transformation choose a suitable id on - // application, we require the id to be given upfront in order to facilitate - // reducing fuzzed shaders by removing transformations. The reason is that - // future transformations may refer to the fresh id introduced by this - // transformation, and if we end up changing what that id is, due to removing - // earlier transformations, it may inhibit later transformations from - // applying. - uint32 fresh_id = 2; - -} - -message TransformationStore { - - // Transformation that adds an OpStore instruction of an id to a pointer. - - // The pointer to be stored to - uint32 pointer_id = 1; - - // The value to be stored - uint32 value_id = 2; - - // A descriptor for an instruction in a block before which the new OpStore - // instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 3; - -} - -message TransformationSwapCommutableOperands { - - // A transformation that swaps the operands of a commutative instruction. - - // A descriptor for a commutative instruction - InstructionDescriptor instruction_descriptor = 1; - -} - -message TransformationSwapConditionalBranchOperands { - - // Swaps label ids in OpBranchConditional instruction. - // Additionally, inverts the guard and swaps branch weights - // if present. - - // Descriptor of the instruction to swap operands of. - InstructionDescriptor instruction_descriptor = 1; - - // Fresh result id for the OpLogicalNot instruction, used - // to invert the guard. - uint32 fresh_id = 2; - -} - -message TransformationToggleAccessChainInstruction { - - // A transformation that toggles an access chain instruction. - - // A descriptor for an access chain instruction - InstructionDescriptor instruction_descriptor = 1; - -} - -message TransformationVectorShuffle { - - // A transformation that adds a vector shuffle instruction. - - // A descriptor for an instruction in a block before which the new - // OpVectorShuffle instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 1; - - // Result id for the shuffle operation. - uint32 fresh_id = 2; - - // Id of the first vector operand. - uint32 vector1 = 3; - - // Id of the second vector operand. - uint32 vector2 = 4; - - // Indices that indicate which components of the input vectors should be used. - repeated uint32 component = 5; - -} diff --git a/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.cpp b/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.cpp deleted file mode 100644 index 9643264a2..000000000 --- a/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/pseudo_random_generator.h" - -#include - -namespace spvtools { -namespace fuzz { - -PseudoRandomGenerator::PseudoRandomGenerator(uint32_t seed) : mt_(seed) {} - -PseudoRandomGenerator::~PseudoRandomGenerator() = default; - -uint32_t PseudoRandomGenerator::RandomUint32(uint32_t bound) { - assert(bound > 0 && "Bound must be positive"); - return static_cast( - std::uniform_int_distribution<>(0, bound - 1)(mt_)); -} - -bool PseudoRandomGenerator::RandomBool() { - return static_cast(std::uniform_int_distribution<>(0, 1)(mt_)); -} - -uint32_t PseudoRandomGenerator::RandomPercentage() { - // We use 101 because we want a result in the closed interval [0, 100], and - // RandomUint32 is not inclusive of its bound. - return RandomUint32(101); -} - -double PseudoRandomGenerator::RandomDouble() { - return std::uniform_real_distribution(0.0, 1.0)(mt_); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.h b/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.h deleted file mode 100644 index d2f529205..000000000 --- a/3rdparty/spirv-tools/source/fuzz/pseudo_random_generator.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ -#define SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ - -#include - -#include "source/fuzz/random_generator.h" - -namespace spvtools { -namespace fuzz { - -// Generates random data from a pseudo-random number generator. -class PseudoRandomGenerator : public RandomGenerator { - public: - explicit PseudoRandomGenerator(uint32_t seed); - - ~PseudoRandomGenerator() override; - - uint32_t RandomUint32(uint32_t bound) override; - - uint32_t RandomPercentage() override; - - bool RandomBool() override; - - double RandomDouble() override; - - private: - std::mt19937 mt_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/random_generator.cpp b/3rdparty/spirv-tools/source/fuzz/random_generator.cpp deleted file mode 100644 index 9ec4845df..000000000 --- a/3rdparty/spirv-tools/source/fuzz/random_generator.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/random_generator.h" - -namespace spvtools { -namespace fuzz { - -RandomGenerator::RandomGenerator() = default; - -RandomGenerator::~RandomGenerator() = default; - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/random_generator.h b/3rdparty/spirv-tools/source/fuzz/random_generator.h deleted file mode 100644 index 9c467983d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/random_generator.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_RANDOM_GENERATOR_H_ -#define SOURCE_FUZZ_RANDOM_GENERATOR_H_ - -#include - -namespace spvtools { -namespace fuzz { - -class RandomGenerator { - public: - RandomGenerator(); - - virtual ~RandomGenerator(); - - // Returns a value in the half-open interval [0, bound). - virtual uint32_t RandomUint32(uint32_t bound) = 0; - - // Returns a value in the closed interval [0, 100]. - virtual uint32_t RandomPercentage() = 0; - - // Returns a boolean. - virtual bool RandomBool() = 0; - - // Returns a double in the closed interval [0, 1] - virtual double RandomDouble() = 0; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_RANDOM_GENERATOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/replayer.cpp b/3rdparty/spirv-tools/source/fuzz/replayer.cpp deleted file mode 100644 index d439b9dfe..000000000 --- a/3rdparty/spirv-tools/source/fuzz/replayer.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/replayer.h" - -#include -#include - -#include "source/fuzz/counter_overflow_id_source.h" -#include "source/fuzz/fact_manager/fact_manager.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/transformation.h" -#include "source/fuzz/transformation_context.h" -#include "source/opt/build_module.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { - -Replayer::Replayer(spv_target_env target_env, bool validate_during_replay, - spv_validator_options validator_options) - : target_env_(target_env), - validate_during_replay_(validate_during_replay), - validator_options_(validator_options) {} - -Replayer::~Replayer() = default; - -void Replayer::SetMessageConsumer(MessageConsumer consumer) { - consumer_ = std::move(consumer); -} - -Replayer::ReplayerResultStatus Replayer::Run( - const std::vector& binary_in, - const protobufs::FactSequence& initial_facts, - const protobufs::TransformationSequence& transformation_sequence_in, - uint32_t num_transformations_to_apply, uint32_t first_overflow_id, - std::vector* binary_out, - protobufs::TransformationSequence* transformation_sequence_out) const { - // Check compatibility between the library version being linked with and the - // header files being used. - GOOGLE_PROTOBUF_VERIFY_VERSION; - - if (num_transformations_to_apply > - static_cast(transformation_sequence_in.transformation_size())) { - consumer_(SPV_MSG_ERROR, nullptr, {}, - "The number of transformations to be replayed must not " - "exceed the size of the transformation sequence."); - return Replayer::ReplayerResultStatus::kTooManyTransformationsRequested; - } - - spvtools::SpirvTools tools(target_env_); - if (!tools.IsValid()) { - consumer_(SPV_MSG_ERROR, nullptr, {}, - "Failed to create SPIRV-Tools interface; stopping."); - return Replayer::ReplayerResultStatus::kFailedToCreateSpirvToolsInterface; - } - - // Initial binary should be valid. - if (!tools.Validate(&binary_in[0], binary_in.size(), validator_options_)) { - consumer_(SPV_MSG_INFO, nullptr, {}, - "Initial binary is invalid; stopping."); - return Replayer::ReplayerResultStatus::kInitialBinaryInvalid; - } - - // Build the module from the input binary. - std::unique_ptr ir_context = - BuildModule(target_env_, consumer_, binary_in.data(), binary_in.size()); - assert(ir_context); - - // For replay validation, we track the last valid SPIR-V binary that was - // observed. Initially this is the input binary. - std::vector last_valid_binary; - if (validate_during_replay_) { - last_valid_binary = binary_in; - } - - FactManager fact_manager; - fact_manager.AddFacts(consumer_, initial_facts, ir_context.get()); - std::unique_ptr transformation_context = - first_overflow_id == 0 - ? MakeUnique(&fact_manager, validator_options_) - : MakeUnique( - &fact_manager, validator_options_, - MakeUnique(first_overflow_id)); - - // We track the largest id bound observed, to ensure that it only increases - // as transformations are applied. - uint32_t max_observed_id_bound = ir_context->module()->id_bound(); - (void)(max_observed_id_bound); // Keep release-mode compilers happy. - - // Consider the transformation proto messages in turn. - uint32_t counter = 0; - for (auto& message : transformation_sequence_in.transformation()) { - if (counter >= num_transformations_to_apply) { - break; - } - counter++; - - auto transformation = Transformation::FromMessage(message); - - // Check whether the transformation can be applied. - if (transformation->IsApplicable(ir_context.get(), - *transformation_context)) { - // The transformation is applicable, so apply it, and copy it to the - // sequence of transformations that were applied. - transformation->Apply(ir_context.get(), transformation_context.get()); - *transformation_sequence_out->add_transformation() = message; - - assert(ir_context->module()->id_bound() >= max_observed_id_bound && - "The module's id bound should only increase due to applying " - "transformations."); - max_observed_id_bound = ir_context->module()->id_bound(); - - if (validate_during_replay_) { - std::vector binary_to_validate; - ir_context->module()->ToBinary(&binary_to_validate, false); - - // Check whether the latest transformation led to a valid binary. - if (!tools.Validate(&binary_to_validate[0], binary_to_validate.size(), - validator_options_)) { - consumer_(SPV_MSG_INFO, nullptr, {}, - "Binary became invalid during replay (set a " - "breakpoint to inspect); stopping."); - return Replayer::ReplayerResultStatus::kReplayValidationFailure; - } - - // The binary was valid, so it becomes the latest valid binary. - last_valid_binary = std::move(binary_to_validate); - } - } - } - - // Write out the module as a binary. - ir_context->module()->ToBinary(binary_out, false); - return Replayer::ReplayerResultStatus::kComplete; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/replayer.h b/3rdparty/spirv-tools/source/fuzz/replayer.h deleted file mode 100644 index a10e536a7..000000000 --- a/3rdparty/spirv-tools/source/fuzz/replayer.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_REPLAYER_H_ -#define SOURCE_FUZZ_REPLAYER_H_ - -#include -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace fuzz { - -// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by -// applying a series of pre-defined transformations. -class Replayer { - public: - // Possible statuses that can result from running the replayer. - enum ReplayerResultStatus { - kComplete, - kFailedToCreateSpirvToolsInterface, - kInitialBinaryInvalid, - kReplayValidationFailure, - kTooManyTransformationsRequested, - }; - - // Constructs a replayer from the given target environment. - Replayer(spv_target_env target_env, bool validate_during_replay, - spv_validator_options validator_options); - - // Disables copy/move constructor/assignment operations. - Replayer(const Replayer&) = delete; - Replayer(Replayer&&) = delete; - Replayer& operator=(const Replayer&) = delete; - Replayer& operator=(Replayer&&) = delete; - - ~Replayer(); - - // Sets the message consumer to the given |consumer|. The |consumer| will be - // invoked once for each message communicated from the library. - void SetMessageConsumer(MessageConsumer consumer); - - // Transforms |binary_in| to |binary_out| by attempting to apply the first - // |num_transformations_to_apply| transformations from - // |transformation_sequence_in|. - // - // Initial facts about the input binary and the context in which it will - // execute are provided via |initial_facts|. - // - // |first_overflow_id| should be set to 0 if overflow ids are not available - // during replay. Otherwise |first_overflow_id| must be larger than any id - // referred to in |binary_in| or |transformation_sequence_in|, and overflow - // ids will be available during replay starting from this value. - // - // The transformations that were successfully applied are returned via - // |transformation_sequence_out|. - ReplayerResultStatus Run( - const std::vector& binary_in, - const protobufs::FactSequence& initial_facts, - const protobufs::TransformationSequence& transformation_sequence_in, - uint32_t num_transformations_to_apply, uint32_t first_overflow_id, - std::vector* binary_out, - protobufs::TransformationSequence* transformation_sequence_out) const; - - private: - // Target environment. - const spv_target_env target_env_; - - // Message consumer. - MessageConsumer consumer_; - - // Controls whether the validator should be run after every replay step. - const bool validate_during_replay_; - - // Options to control validation - spv_validator_options validator_options_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_REPLAYER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/shrinker.cpp b/3rdparty/spirv-tools/source/fuzz/shrinker.cpp deleted file mode 100644 index 7b88405a3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/shrinker.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/shrinker.h" - -#include - -#include "source/fuzz/pseudo_random_generator.h" -#include "source/fuzz/replayer.h" -#include "source/opt/build_module.h" -#include "source/opt/ir_context.h" -#include "source/spirv_fuzzer_options.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { - -namespace { - -// A helper to get the size of a protobuf transformation sequence in a less -// verbose manner. -uint32_t NumRemainingTransformations( - const protobufs::TransformationSequence& transformation_sequence) { - return static_cast(transformation_sequence.transformation_size()); -} - -// A helper to return a transformation sequence identical to |transformations|, -// except that a chunk of size |chunk_size| starting from |chunk_index| x -// |chunk_size| is removed (or as many transformations as available if the whole -// chunk is not). -protobufs::TransformationSequence RemoveChunk( - const protobufs::TransformationSequence& transformations, - uint32_t chunk_index, uint32_t chunk_size) { - uint32_t lower = chunk_index * chunk_size; - uint32_t upper = std::min((chunk_index + 1) * chunk_size, - NumRemainingTransformations(transformations)); - assert(lower < upper); - assert(upper <= NumRemainingTransformations(transformations)); - protobufs::TransformationSequence result; - for (uint32_t j = 0; j < NumRemainingTransformations(transformations); j++) { - if (j >= lower && j < upper) { - continue; - } - protobufs::Transformation transformation = - transformations.transformation()[j]; - *result.mutable_transformation()->Add() = transformation; - } - return result; -} - -} // namespace - -uint32_t Shrinker::GetIdBound(const std::vector& binary) const { - // Build the module from the input binary. - std::unique_ptr ir_context = - BuildModule(target_env_, consumer_, binary.data(), binary.size()); - assert(ir_context && "Error building module."); - return ir_context->module()->id_bound(); -} - -Shrinker::Shrinker(spv_target_env target_env, uint32_t step_limit, - bool validate_during_replay, - spv_validator_options validator_options) - : target_env_(target_env), - step_limit_(step_limit), - validate_during_replay_(validate_during_replay), - validator_options_(validator_options) {} - -Shrinker::~Shrinker() = default; - -void Shrinker::SetMessageConsumer(MessageConsumer consumer) { - consumer_ = std::move(consumer); -} - -Shrinker::ShrinkerResultStatus Shrinker::Run( - const std::vector& binary_in, - const protobufs::FactSequence& initial_facts, - const protobufs::TransformationSequence& transformation_sequence_in, - const Shrinker::InterestingnessFunction& interestingness_function, - std::vector* binary_out, - protobufs::TransformationSequence* transformation_sequence_out) const { - // Check compatibility between the library version being linked with and the - // header files being used. - GOOGLE_PROTOBUF_VERIFY_VERSION; - - SpirvTools tools(target_env_); - if (!tools.IsValid()) { - consumer_(SPV_MSG_ERROR, nullptr, {}, - "Failed to create SPIRV-Tools interface; stopping."); - return Shrinker::ShrinkerResultStatus::kFailedToCreateSpirvToolsInterface; - } - - // Initial binary should be valid. - if (!tools.Validate(&binary_in[0], binary_in.size(), validator_options_)) { - consumer_(SPV_MSG_INFO, nullptr, {}, - "Initial binary is invalid; stopping."); - return Shrinker::ShrinkerResultStatus::kInitialBinaryInvalid; - } - - std::vector current_best_binary; - protobufs::TransformationSequence current_best_transformations; - - // Run a replay of the initial transformation sequence to (a) check that it - // succeeds, (b) get the binary that results from running these - // transformations, and (c) get the subsequence of the initial transformations - // that actually apply (in principle this could be a strict subsequence). - Replayer replayer(target_env_, validate_during_replay_, validator_options_); - replayer.SetMessageConsumer(consumer_); - if (replayer.Run(binary_in, initial_facts, transformation_sequence_in, - static_cast( - transformation_sequence_in.transformation_size()), - /* No overflow ids */ 0, ¤t_best_binary, - ¤t_best_transformations) != - Replayer::ReplayerResultStatus::kComplete) { - return ShrinkerResultStatus::kReplayFailed; - } - - // Check that the binary produced by applying the initial transformations is - // indeed interesting. - if (!interestingness_function(current_best_binary, 0)) { - consumer_(SPV_MSG_INFO, nullptr, {}, - "Initial binary is not interesting; stopping."); - return ShrinkerResultStatus::kInitialBinaryNotInteresting; - } - - // The largest id used by the module before any shrinking has been applied - // serves as the first id that can be used for overflow purposes. - const uint32_t first_overflow_id = GetIdBound(current_best_binary); - assert(first_overflow_id >= GetIdBound(binary_in) && - "Applying transformations should only increase a module's id bound."); - - uint32_t attempt = 0; // Keeps track of the number of shrink attempts that - // have been tried, whether successful or not. - - uint32_t chunk_size = - std::max(1u, NumRemainingTransformations(current_best_transformations) / - 2); // The number of contiguous transformations that the - // shrinker will try to remove in one go; starts - // high and decreases during the shrinking process. - - // Keep shrinking until we: - // - reach the step limit, - // - run out of transformations to remove, or - // - cannot make the chunk size any smaller. - while (attempt < step_limit_ && - !current_best_transformations.transformation().empty() && - chunk_size > 0) { - bool progress_this_round = - false; // Used to decide whether to make the chunk size with which we - // remove transformations smaller. If we managed to remove at - // least one chunk of transformations at a particular chunk - // size, we set this flag so that we do not yet decrease the - // chunk size. - - assert(chunk_size <= - NumRemainingTransformations(current_best_transformations) && - "Chunk size should never exceed the number of transformations that " - "remain."); - - // The number of chunks is the ceiling of (#remaining_transformations / - // chunk_size). - const uint32_t num_chunks = - (NumRemainingTransformations(current_best_transformations) + - chunk_size - 1) / - chunk_size; - assert(num_chunks >= 1 && "There should be at least one chunk."); - assert(num_chunks * chunk_size >= - NumRemainingTransformations(current_best_transformations) && - "All transformations should be in some chunk."); - - // We go through the transformations in reverse, in chunks of size - // |chunk_size|, using |chunk_index| to track which chunk to try removing - // next. The loop exits early if we reach the shrinking step limit. - for (int chunk_index = num_chunks - 1; - attempt < step_limit_ && chunk_index >= 0; chunk_index--) { - // Remove a chunk of transformations according to the current index and - // chunk size. - auto transformations_with_chunk_removed = - RemoveChunk(current_best_transformations, - static_cast(chunk_index), chunk_size); - - // Replay the smaller sequence of transformations to get a next binary and - // transformation sequence. Note that the transformations arising from - // replay might be even smaller than the transformations with the chunk - // removed, because removing those transformations might make further - // transformations inapplicable. - std::vector next_binary; - protobufs::TransformationSequence next_transformation_sequence; - if (replayer.Run( - binary_in, initial_facts, transformations_with_chunk_removed, - static_cast( - transformations_with_chunk_removed.transformation_size()), - first_overflow_id, &next_binary, &next_transformation_sequence) != - Replayer::ReplayerResultStatus::kComplete) { - // Replay should not fail; if it does, we need to abort shrinking. - return ShrinkerResultStatus::kReplayFailed; - } - - assert(NumRemainingTransformations(next_transformation_sequence) >= - chunk_index * chunk_size && - "Removing this chunk of transformations should not have an effect " - "on earlier chunks."); - - if (interestingness_function(next_binary, attempt)) { - // If the binary arising from the smaller transformation sequence is - // interesting, this becomes our current best binary and transformation - // sequence. - current_best_binary = next_binary; - current_best_transformations = next_transformation_sequence; - progress_this_round = true; - } - // Either way, this was a shrink attempt, so increment our count of shrink - // attempts. - attempt++; - } - if (!progress_this_round) { - // If we didn't manage to remove any chunks at this chunk size, try a - // smaller chunk size. - chunk_size /= 2; - } - // Decrease the chunk size until it becomes no larger than the number of - // remaining transformations. - while (chunk_size > - NumRemainingTransformations(current_best_transformations)) { - chunk_size /= 2; - } - } - - // The output from the shrinker is the best binary we saw, and the - // transformations that led to it. - *binary_out = current_best_binary; - *transformation_sequence_out = current_best_transformations; - - // Indicate whether shrinking completed or was truncated due to reaching the - // step limit. - assert(attempt <= step_limit_); - if (attempt == step_limit_) { - std::stringstream strstream; - strstream << "Shrinking did not complete; step limit " << step_limit_ - << " was reached."; - consumer_(SPV_MSG_WARNING, nullptr, {}, strstream.str().c_str()); - return Shrinker::ShrinkerResultStatus::kStepLimitReached; - } - return Shrinker::ShrinkerResultStatus::kComplete; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/shrinker.h b/3rdparty/spirv-tools/source/fuzz/shrinker.h deleted file mode 100644 index 0fe89290d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/shrinker.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_SHRINKER_H_ -#define SOURCE_FUZZ_SHRINKER_H_ - -#include -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace fuzz { - -// Shrinks a sequence of transformations that lead to an interesting SPIR-V -// binary to yield a smaller sequence of transformations that still produce an -// interesting binary. -class Shrinker { - public: - // Possible statuses that can result from running the shrinker. - enum ShrinkerResultStatus { - kComplete, - kFailedToCreateSpirvToolsInterface, - kInitialBinaryInvalid, - kInitialBinaryNotInteresting, - kReplayFailed, - kStepLimitReached, - }; - - // The type for a function that will take a binary, |binary|, and return true - // if and only if the binary is deemed interesting. (The function also takes - // an integer argument, |counter|, that will be incremented each time the - // function is called; this is for debugging purposes). - // - // The notion of "interesting" depends on what properties of the binary or - // tools that process the binary we are trying to maintain during shrinking. - using InterestingnessFunction = std::function& binary, uint32_t counter)>; - - Shrinker(spv_target_env target_env, uint32_t step_limit, - bool validate_during_replay, - spv_validator_options validator_options); - - // Disables copy/move constructor/assignment operations. - Shrinker(const Shrinker&) = delete; - Shrinker(Shrinker&&) = delete; - Shrinker& operator=(const Shrinker&) = delete; - Shrinker& operator=(Shrinker&&) = delete; - - ~Shrinker(); - - // 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); - - // Requires that when |transformation_sequence_in| is applied to |binary_in| - // with initial facts |initial_facts|, the resulting binary is interesting - // according to |interestingness_function|. - // - // Produces, via |transformation_sequence_out|, a subsequence of - // |transformation_sequence_in| that, when applied with initial facts - // |initial_facts|, produces a binary (captured via |binary_out|) that is - // also interesting according to |interestingness_function|. - ShrinkerResultStatus Run( - const std::vector& binary_in, - const protobufs::FactSequence& initial_facts, - const protobufs::TransformationSequence& transformation_sequence_in, - const InterestingnessFunction& interestingness_function, - std::vector* binary_out, - protobufs::TransformationSequence* transformation_sequence_out) const; - - private: - // Returns the id bound for the given SPIR-V binary, which is assumed to be - // valid. - uint32_t GetIdBound(const std::vector& binary) const; - - // Target environment. - const spv_target_env target_env_; - - // Message consumer. - MessageConsumer consumer_; - - // Step limit to decide when to terminate shrinking early. - const uint32_t step_limit_; - - // Determines whether to check for validity during the replaying of - // transformations. - const bool validate_during_replay_; - - // Options to control validation. - spv_validator_options validator_options_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_SHRINKER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation.cpp b/3rdparty/spirv-tools/source/fuzz/transformation.cpp deleted file mode 100644 index 3cadac95b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_access_chain.h" -#include "source/fuzz/transformation_add_constant_boolean.h" -#include "source/fuzz/transformation_add_constant_composite.h" -#include "source/fuzz/transformation_add_constant_null.h" -#include "source/fuzz/transformation_add_constant_scalar.h" -#include "source/fuzz/transformation_add_copy_memory.h" -#include "source/fuzz/transformation_add_dead_block.h" -#include "source/fuzz/transformation_add_dead_break.h" -#include "source/fuzz/transformation_add_dead_continue.h" -#include "source/fuzz/transformation_add_function.h" -#include "source/fuzz/transformation_add_global_undef.h" -#include "source/fuzz/transformation_add_global_variable.h" -#include "source/fuzz/transformation_add_image_sample_unused_components.h" -#include "source/fuzz/transformation_add_local_variable.h" -#include "source/fuzz/transformation_add_loop_preheader.h" -#include "source/fuzz/transformation_add_no_contraction_decoration.h" -#include "source/fuzz/transformation_add_opphi_synonym.h" -#include "source/fuzz/transformation_add_parameter.h" -#include "source/fuzz/transformation_add_relaxed_decoration.h" -#include "source/fuzz/transformation_add_spec_constant_op.h" -#include "source/fuzz/transformation_add_synonym.h" -#include "source/fuzz/transformation_add_type_array.h" -#include "source/fuzz/transformation_add_type_boolean.h" -#include "source/fuzz/transformation_add_type_float.h" -#include "source/fuzz/transformation_add_type_function.h" -#include "source/fuzz/transformation_add_type_int.h" -#include "source/fuzz/transformation_add_type_matrix.h" -#include "source/fuzz/transformation_add_type_pointer.h" -#include "source/fuzz/transformation_add_type_struct.h" -#include "source/fuzz/transformation_add_type_vector.h" -#include "source/fuzz/transformation_adjust_branch_weights.h" -#include "source/fuzz/transformation_composite_construct.h" -#include "source/fuzz/transformation_composite_extract.h" -#include "source/fuzz/transformation_composite_insert.h" -#include "source/fuzz/transformation_compute_data_synonym_fact_closure.h" -#include "source/fuzz/transformation_equation_instruction.h" -#include "source/fuzz/transformation_function_call.h" -#include "source/fuzz/transformation_inline_function.h" -#include "source/fuzz/transformation_invert_comparison_operator.h" -#include "source/fuzz/transformation_load.h" -#include "source/fuzz/transformation_make_vector_operation_dynamic.h" -#include "source/fuzz/transformation_merge_blocks.h" -#include "source/fuzz/transformation_move_block_down.h" -#include "source/fuzz/transformation_move_instruction_down.h" -#include "source/fuzz/transformation_outline_function.h" -#include "source/fuzz/transformation_permute_function_parameters.h" -#include "source/fuzz/transformation_permute_phi_operands.h" -#include "source/fuzz/transformation_propagate_instruction_up.h" -#include "source/fuzz/transformation_push_id_through_variable.h" -#include "source/fuzz/transformation_record_synonymous_constants.h" -#include "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h" -#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" -#include "source/fuzz/transformation_replace_constant_with_uniform.h" -#include "source/fuzz/transformation_replace_copy_memory_with_load_store.h" -#include "source/fuzz/transformation_replace_copy_object_with_store_load.h" -#include "source/fuzz/transformation_replace_id_with_synonym.h" -#include "source/fuzz/transformation_replace_linear_algebra_instruction.h" -#include "source/fuzz/transformation_replace_load_store_with_copy_memory.h" -#include "source/fuzz/transformation_replace_parameter_with_global.h" -#include "source/fuzz/transformation_replace_params_with_struct.h" -#include "source/fuzz/transformation_set_function_control.h" -#include "source/fuzz/transformation_set_loop_control.h" -#include "source/fuzz/transformation_set_memory_operands_mask.h" -#include "source/fuzz/transformation_set_selection_control.h" -#include "source/fuzz/transformation_split_block.h" -#include "source/fuzz/transformation_store.h" -#include "source/fuzz/transformation_swap_commutable_operands.h" -#include "source/fuzz/transformation_swap_conditional_branch_operands.h" -#include "source/fuzz/transformation_toggle_access_chain_instruction.h" -#include "source/fuzz/transformation_vector_shuffle.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { - -Transformation::~Transformation() = default; - -std::unique_ptr Transformation::FromMessage( - const protobufs::Transformation& message) { - switch (message.transformation_case()) { - case protobufs::Transformation::TransformationCase::kAccessChain: - return MakeUnique(message.access_chain()); - case protobufs::Transformation::TransformationCase::kAddConstantBoolean: - return MakeUnique( - message.add_constant_boolean()); - case protobufs::Transformation::TransformationCase::kAddConstantComposite: - return MakeUnique( - message.add_constant_composite()); - case protobufs::Transformation::TransformationCase::kAddConstantNull: - return MakeUnique( - message.add_constant_null()); - case protobufs::Transformation::TransformationCase::kAddConstantScalar: - return MakeUnique( - message.add_constant_scalar()); - case protobufs::Transformation::TransformationCase::kAddCopyMemory: - return MakeUnique(message.add_copy_memory()); - case protobufs::Transformation::TransformationCase::kAddDeadBlock: - return MakeUnique(message.add_dead_block()); - case protobufs::Transformation::TransformationCase::kAddDeadBreak: - return MakeUnique(message.add_dead_break()); - case protobufs::Transformation::TransformationCase::kAddDeadContinue: - return MakeUnique( - message.add_dead_continue()); - case protobufs::Transformation::TransformationCase::kAddFunction: - return MakeUnique(message.add_function()); - case protobufs::Transformation::TransformationCase::kAddGlobalUndef: - return MakeUnique( - message.add_global_undef()); - case protobufs::Transformation::TransformationCase::kAddGlobalVariable: - return MakeUnique( - message.add_global_variable()); - case protobufs::Transformation::TransformationCase:: - kAddImageSampleUnusedComponents: - return MakeUnique( - message.add_image_sample_unused_components()); - case protobufs::Transformation::TransformationCase::kAddLocalVariable: - return MakeUnique( - message.add_local_variable()); - case protobufs::Transformation::TransformationCase::kAddLoopPreheader: - return MakeUnique( - message.add_loop_preheader()); - case protobufs::Transformation::TransformationCase:: - kAddNoContractionDecoration: - return MakeUnique( - message.add_no_contraction_decoration()); - case protobufs::Transformation::TransformationCase::kAddOpphiSynonym: - return MakeUnique( - message.add_opphi_synonym()); - case protobufs::Transformation::TransformationCase::kAddParameter: - return MakeUnique(message.add_parameter()); - case protobufs::Transformation::TransformationCase::kAddRelaxedDecoration: - return MakeUnique( - message.add_relaxed_decoration()); - case protobufs::Transformation::TransformationCase::kAddSpecConstantOp: - return MakeUnique( - message.add_spec_constant_op()); - case protobufs::Transformation::TransformationCase::kAddSynonym: - return MakeUnique(message.add_synonym()); - case protobufs::Transformation::TransformationCase::kAddTypeArray: - return MakeUnique(message.add_type_array()); - case protobufs::Transformation::TransformationCase::kAddTypeBoolean: - return MakeUnique( - message.add_type_boolean()); - case protobufs::Transformation::TransformationCase::kAddTypeFloat: - return MakeUnique(message.add_type_float()); - case protobufs::Transformation::TransformationCase::kAddTypeFunction: - return MakeUnique( - message.add_type_function()); - case protobufs::Transformation::TransformationCase::kAddTypeInt: - return MakeUnique(message.add_type_int()); - case protobufs::Transformation::TransformationCase::kAddTypeMatrix: - return MakeUnique(message.add_type_matrix()); - case protobufs::Transformation::TransformationCase::kAddTypePointer: - return MakeUnique( - message.add_type_pointer()); - case protobufs::Transformation::TransformationCase::kAddTypeStruct: - return MakeUnique(message.add_type_struct()); - case protobufs::Transformation::TransformationCase::kAddTypeVector: - return MakeUnique(message.add_type_vector()); - case protobufs::Transformation::TransformationCase::kAdjustBranchWeights: - return MakeUnique( - message.adjust_branch_weights()); - case protobufs::Transformation::TransformationCase::kCompositeConstruct: - return MakeUnique( - message.composite_construct()); - case protobufs::Transformation::TransformationCase::kCompositeExtract: - return MakeUnique( - message.composite_extract()); - case protobufs::Transformation::TransformationCase::kCompositeInsert: - return MakeUnique( - message.composite_insert()); - case protobufs::Transformation::TransformationCase:: - kComputeDataSynonymFactClosure: - return MakeUnique( - message.compute_data_synonym_fact_closure()); - case protobufs::Transformation::TransformationCase::kEquationInstruction: - return MakeUnique( - message.equation_instruction()); - case protobufs::Transformation::TransformationCase::kFunctionCall: - return MakeUnique(message.function_call()); - case protobufs::Transformation::TransformationCase::kInlineFunction: - return MakeUnique( - message.inline_function()); - case protobufs::Transformation::TransformationCase:: - kInvertComparisonOperator: - return MakeUnique( - message.invert_comparison_operator()); - case protobufs::Transformation::TransformationCase::kLoad: - return MakeUnique(message.load()); - case protobufs::Transformation::TransformationCase:: - kMakeVectorOperationDynamic: - return MakeUnique( - message.make_vector_operation_dynamic()); - case protobufs::Transformation::TransformationCase::kMergeBlocks: - return MakeUnique(message.merge_blocks()); - case protobufs::Transformation::TransformationCase::kMoveBlockDown: - return MakeUnique(message.move_block_down()); - case protobufs::Transformation::TransformationCase::kMoveInstructionDown: - return MakeUnique( - message.move_instruction_down()); - case protobufs::Transformation::TransformationCase::kOutlineFunction: - return MakeUnique( - message.outline_function()); - case protobufs::Transformation::TransformationCase:: - kPermuteFunctionParameters: - return MakeUnique( - message.permute_function_parameters()); - case protobufs::Transformation::TransformationCase::kPermutePhiOperands: - return MakeUnique( - message.permute_phi_operands()); - case protobufs::Transformation::TransformationCase::kPropagateInstructionUp: - return MakeUnique( - message.propagate_instruction_up()); - case protobufs::Transformation::TransformationCase::kPushIdThroughVariable: - return MakeUnique( - message.push_id_through_variable()); - case protobufs::Transformation::TransformationCase:: - kRecordSynonymousConstants: - return MakeUnique( - message.record_synonymous_constants()); - case protobufs::Transformation::TransformationCase:: - kReplaceAddSubMulWithCarryingExtended: - return MakeUnique( - message.replace_add_sub_mul_with_carrying_extended()); - case protobufs::Transformation::TransformationCase:: - kReplaceBooleanConstantWithConstantBinary: - return MakeUnique( - message.replace_boolean_constant_with_constant_binary()); - case protobufs::Transformation::TransformationCase:: - kReplaceConstantWithUniform: - return MakeUnique( - message.replace_constant_with_uniform()); - case protobufs::Transformation::TransformationCase:: - kReplaceCopyMemoryWithLoadStore: - return MakeUnique( - message.replace_copy_memory_with_load_store()); - case protobufs::Transformation::TransformationCase:: - kReplaceCopyObjectWithStoreLoad: - return MakeUnique( - message.replace_copy_object_with_store_load()); - case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym: - return MakeUnique( - message.replace_id_with_synonym()); - case protobufs::Transformation::TransformationCase:: - kReplaceLinearAlgebraInstruction: - return MakeUnique( - message.replace_linear_algebra_instruction()); - case protobufs::Transformation::TransformationCase:: - kReplaceLoadStoreWithCopyMemory: - return MakeUnique( - message.replace_load_store_with_copy_memory()); - case protobufs::Transformation::TransformationCase:: - kReplaceParameterWithGlobal: - return MakeUnique( - message.replace_parameter_with_global()); - case protobufs::Transformation::TransformationCase:: - kReplaceParamsWithStruct: - return MakeUnique( - message.replace_params_with_struct()); - case protobufs::Transformation::TransformationCase::kSetFunctionControl: - return MakeUnique( - message.set_function_control()); - case protobufs::Transformation::TransformationCase::kSetLoopControl: - return MakeUnique( - message.set_loop_control()); - case protobufs::Transformation::TransformationCase::kSetMemoryOperandsMask: - return MakeUnique( - message.set_memory_operands_mask()); - case protobufs::Transformation::TransformationCase::kSetSelectionControl: - return MakeUnique( - message.set_selection_control()); - case protobufs::Transformation::TransformationCase::kSplitBlock: - return MakeUnique(message.split_block()); - case protobufs::Transformation::TransformationCase::kStore: - return MakeUnique(message.store()); - case protobufs::Transformation::TransformationCase::kSwapCommutableOperands: - return MakeUnique( - message.swap_commutable_operands()); - case protobufs::Transformation::TransformationCase:: - kSwapConditionalBranchOperands: - return MakeUnique( - message.swap_conditional_branch_operands()); - case protobufs::Transformation::TransformationCase:: - kToggleAccessChainInstruction: - return MakeUnique( - message.toggle_access_chain_instruction()); - case protobufs::Transformation::TransformationCase::kVectorShuffle: - return MakeUnique(message.vector_shuffle()); - case protobufs::Transformation::TRANSFORMATION_NOT_SET: - assert(false && "An unset transformation was encountered."); - return nullptr; - } - assert(false && "Should be unreachable as all cases must be handled above."); - return nullptr; -} - -bool Transformation::CheckIdIsFreshAndNotUsedByThisTransformation( - uint32_t id, opt::IRContext* ir_context, - std::set* ids_used_by_this_transformation) { - if (!fuzzerutil::IsFreshId(ir_context, id)) { - return false; - } - if (ids_used_by_this_transformation->count(id) != 0) { - return false; - } - ids_used_by_this_transformation->insert(id); - return true; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation.h b/3rdparty/spirv-tools/source/fuzz/transformation.h deleted file mode 100644 index dbd0fe283..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/transformation_context.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// Rules for transformations -// ------------------------- -// -// - Immutability: a transformation must be immutable. -// - Ability to copy and serialize: to ensure that a copy of a transformation, -// possibly saved out to disk and read back again, is indistinguishable -// from the original transformation, thus a transformation must depend -// only on well-defined pieces of state, such as instruction ids. It must -// not rely on state such as pointers to instructions and blocks. -// - Determinism: the effect of a transformation on a module be a deterministic -// function of the module and the transformation. Any randomization should -// be applied before creating the transformation, not during its -// application. -// - Well-defined and precondition: the 'IsApplicable' method should only -// return true if the transformation can be cleanly applied to the given -// module, to mutate it into a valid and semantically-equivalent module, as -// long as the module is initially valid. -// - Ability to test precondition on any valid module: 'IsApplicable' should be -// designed so that it is safe to ask whether a transformation is -// applicable to an arbitrary valid module. For example, if a -// transformation involves a block id, 'IsApplicable' should check whether -// the module indeed has a block with that id, and return false if not. It -// must not assume that there is such a block. -// - Documented precondition: while the implementation of 'IsApplicable' should -// should codify the precondition, the method should be commented in the -// header file for a transformation with a precise English description of -// the precondition. -// - Documented effect: while the implementation of 'Apply' should codify the -// effect of the transformation, the method should be commented in the -// header file for a transformation with a precise English description of -// the effect. - -class Transformation { - public: - // A precondition that determines whether the transformation can be cleanly - // applied in a semantics-preserving manner to the SPIR-V module given by - // |ir_context|, in the presence of facts and other contextual information - // captured by |transformation_context|. - // - // Preconditions for individual transformations must be documented in the - // associated header file using precise English. The transformation context - // provides access to facts about the module that are known to be true, on - // which the precondition may depend. - virtual bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const = 0; - - // Requires that IsApplicable(ir_context, *transformation_context) holds. - // Applies the transformation, mutating |ir_context| and possibly updating - // |transformation_context| with new facts established by the transformation. - virtual void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const = 0; - - // Turns the transformation into a protobuf message for serialization. - virtual protobufs::Transformation ToMessage() const = 0; - - virtual ~Transformation(); - - // Factory method to obtain a transformation object from the protobuf - // representation of a transformation given by |message|. - static std::unique_ptr FromMessage( - const protobufs::Transformation& message); - - // Helper that returns true if and only if (a) |id| is a fresh id for the - // module, and (b) |id| is not in |ids_used_by_this_transformation|, a set of - // ids already known to be in use by a transformation. This is useful when - // checking id freshness for a transformation that uses many ids, all of which - // must be distinct. - static bool CheckIdIsFreshAndNotUsedByThisTransformation( - uint32_t id, opt::IRContext* ir_context, - std::set* ids_used_by_this_transformation); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_access_chain.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_access_chain.cpp deleted file mode 100644 index 33668694f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_access_chain.cpp +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_access_chain.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationAccessChain::TransformationAccessChain( - const spvtools::fuzz::protobufs::TransformationAccessChain& message) - : message_(message) {} - -TransformationAccessChain::TransformationAccessChain( - uint32_t fresh_id, uint32_t pointer_id, - const std::vector& index_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before, - const std::vector>& fresh_ids_for_clamping) { - message_.set_fresh_id(fresh_id); - message_.set_pointer_id(pointer_id); - for (auto id : index_id) { - message_.add_index_id(id); - } - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; - for (auto clamping_ids_pair : fresh_ids_for_clamping) { - protobufs::UInt32Pair pair; - pair.set_first(clamping_ids_pair.first); - pair.set_second(clamping_ids_pair.second); - *message_.add_fresh_ids_for_clamping() = pair; - } -} - -bool TransformationAccessChain::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Keep track of the fresh ids used to make sure that they are distinct. - std::set fresh_ids_used; - - // The result id must be fresh. - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.fresh_id(), ir_context, &fresh_ids_used)) { - return false; - } - // The pointer id must exist and have a type. - auto pointer = ir_context->get_def_use_mgr()->GetDef(message_.pointer_id()); - if (!pointer || !pointer->type_id()) { - return false; - } - // The type must indeed be a pointer. - auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id()); - if (pointer_type->opcode() != SpvOpTypePointer) { - return false; - } - - // The described instruction to insert before must exist and be a suitable - // point where an OpAccessChain instruction could be inserted. - auto instruction_to_insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - if (!instruction_to_insert_before) { - return false; - } - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpAccessChain, instruction_to_insert_before)) { - return false; - } - - // Do not allow making an access chain from a null or undefined pointer, as - // we do not want to allow accessing such pointers. This might be acceptable - // in dead blocks, but we conservatively avoid it. - switch (pointer->opcode()) { - case SpvOpConstantNull: - case SpvOpUndef: - assert( - false && - "Access chains should not be created from null/undefined pointers"); - return false; - default: - break; - } - - // The pointer on which the access chain is to be based needs to be available - // (according to dominance rules) at the insertion point. - if (!fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, instruction_to_insert_before, message_.pointer_id())) { - return false; - } - - // We now need to use the given indices to walk the type structure of the - // base type of the pointer, making sure that (a) the indices correspond to - // integers, and (b) these integer values are in-bounds. - - // Start from the base type of the pointer. - uint32_t subobject_type_id = pointer_type->GetSingleWordInOperand(1); - - int id_pairs_used = 0; - - // Consider the given index ids in turn. - for (auto index_id : message_.index_id()) { - // The index value will correspond to the value of the index if the object - // is a struct, otherwise the value 0 will be used. - uint32_t index_value; - - // Check whether the object is a struct. - if (ir_context->get_def_use_mgr()->GetDef(subobject_type_id)->opcode() == - SpvOpTypeStruct) { - // It is a struct: we need to retrieve the integer value. - - bool successful; - std::tie(successful, index_value) = - GetIndexValue(ir_context, index_id, subobject_type_id); - - if (!successful) { - return false; - } - } else { - // It is not a struct: the index will need clamping. - - if (message_.fresh_ids_for_clamping().size() <= id_pairs_used) { - // We don't have enough ids - return false; - } - - // Get two new ids to use and update the amount used. - protobufs::UInt32Pair fresh_ids = - message_.fresh_ids_for_clamping()[id_pairs_used++]; - - // Valid ids need to have been given - if (fresh_ids.first() == 0 || fresh_ids.second() == 0) { - return false; - } - - // Check that the ids are actually fresh and not already used by this - // transformation. - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - fresh_ids.first(), ir_context, &fresh_ids_used) || - !CheckIdIsFreshAndNotUsedByThisTransformation( - fresh_ids.second(), ir_context, &fresh_ids_used)) { - return false; - } - - if (!ValidIndexToComposite(ir_context, index_id, subobject_type_id)) { - return false; - } - - // Perform the clamping using the fresh ids at our disposal. - auto index_instruction = ir_context->get_def_use_mgr()->GetDef(index_id); - - uint32_t bound = fuzzerutil::GetBoundForCompositeIndex( - *ir_context->get_def_use_mgr()->GetDef(subobject_type_id), - ir_context); - - // The module must have an integer constant of value bound-1 of the same - // type as the index. - if (!fuzzerutil::MaybeGetIntegerConstantFromValueAndType( - ir_context, bound - 1, index_instruction->type_id())) { - return false; - } - - // The module must have the definition of bool type to make a comparison. - if (!fuzzerutil::MaybeGetBoolType(ir_context)) { - return false; - } - - // The index is not necessarily a constant, so we may not know its value. - // We can use index 0 because the components of a non-struct composite - // all have the same type, and index 0 is always in bounds. - index_value = 0; - } - - // Try to walk down the type using this index. This will yield 0 if the - // type is not a composite or the index is out of bounds, and the id of - // the next type otherwise. - subobject_type_id = fuzzerutil::WalkOneCompositeTypeIndex( - ir_context, subobject_type_id, index_value); - if (!subobject_type_id) { - // Either the type was not a composite (so that too many indices were - // provided), or the index was out of bounds. - return false; - } - } - // At this point, |subobject_type_id| is the type of the value targeted by - // the new access chain. The result type of the access chain should be a - // pointer to this type, with the same storage class as for the original - // pointer. Such a pointer type needs to exist in the module. - // - // We do not use the type manager to look up this type, due to problems - // associated with pointers to isomorphic structs being regarded as the same. - return fuzzerutil::MaybeGetPointerType( - ir_context, subobject_type_id, - static_cast( - pointer_type->GetSingleWordInOperand(0))) != 0; -} - -void TransformationAccessChain::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // The operands to the access chain are the pointer followed by the indices. - // The result type of the access chain is determined by where the indices - // lead. We thus push the pointer to a sequence of operands, and then follow - // the indices, pushing each to the operand list and tracking the type - // obtained by following it. Ultimately this yields the type of the - // component reached by following all the indices, and the result type is - // a pointer to this component type. - opt::Instruction::OperandList operands; - - // Add the pointer id itself. - operands.push_back({SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}); - - // Start walking the indices, starting with the pointer's base type. - auto pointer_type = ir_context->get_def_use_mgr()->GetDef( - ir_context->get_def_use_mgr()->GetDef(message_.pointer_id())->type_id()); - uint32_t subobject_type_id = pointer_type->GetSingleWordInOperand(1); - - uint32_t id_pairs_used = 0; - - // Go through the index ids in turn. - for (auto index_id : message_.index_id()) { - uint32_t index_value; - - // Actual id to be used in the instruction: the original id - // or the clamped one. - uint32_t new_index_id; - - // Check whether the object is a struct. - if (ir_context->get_def_use_mgr()->GetDef(subobject_type_id)->opcode() == - SpvOpTypeStruct) { - // It is a struct: we need to retrieve the integer value. - - index_value = - GetIndexValue(ir_context, index_id, subobject_type_id).second; - - new_index_id = index_id; - - } else { - // It is not a struct: the index will need clamping. - - // Get two new ids to use and update the amount used. - protobufs::UInt32Pair fresh_ids = - message_.fresh_ids_for_clamping()[id_pairs_used++]; - - // Perform the clamping using the fresh ids at our disposal. - // The module will not be changed if |add_clamping_instructions| is not - // set. - auto index_instruction = ir_context->get_def_use_mgr()->GetDef(index_id); - - uint32_t bound = fuzzerutil::GetBoundForCompositeIndex( - *ir_context->get_def_use_mgr()->GetDef(subobject_type_id), - ir_context); - - auto bound_minus_one_id = - fuzzerutil::MaybeGetIntegerConstantFromValueAndType( - ir_context, bound - 1, index_instruction->type_id()); - - assert(bound_minus_one_id && - "A constant of value bound - 1 and the same type as the index " - "must exist as a precondition."); - - uint32_t bool_type_id = fuzzerutil::MaybeGetBoolType(ir_context); - - assert(bool_type_id && - "An OpTypeBool instruction must exist as a precondition."); - - auto int_type_inst = - ir_context->get_def_use_mgr()->GetDef(index_instruction->type_id()); - - // Clamp the integer and add the corresponding instructions in the module - // if |add_clamping_instructions| is set. - auto instruction_to_insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - - // Compare the index with the bound via an instruction of the form: - // %fresh_ids.first = OpULessThanEqual %bool %int_id %bound_minus_one. - fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.first()); - instruction_to_insert_before->InsertBefore(MakeUnique( - ir_context, SpvOpULessThanEqual, bool_type_id, fresh_ids.first(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}}, - {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); - - // Select the index if in-bounds, otherwise one less than the bound: - // %fresh_ids.second = OpSelect %int_type %fresh_ids.first %int_id - // %bound_minus_one - fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.second()); - instruction_to_insert_before->InsertBefore(MakeUnique( - ir_context, SpvOpSelect, int_type_inst->result_id(), - fresh_ids.second(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {fresh_ids.first()}}, - {SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}}, - {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); - - new_index_id = fresh_ids.second(); - - index_value = 0; - } - - // Add the correct index id to the operands. - operands.push_back({SPV_OPERAND_TYPE_ID, {new_index_id}}); - - // Walk to the next type in the composite object using this index. - subobject_type_id = fuzzerutil::WalkOneCompositeTypeIndex( - ir_context, subobject_type_id, index_value); - } - // The access chain's result type is a pointer to the composite component - // that was reached after following all indices. The storage class is that - // of the original pointer. - uint32_t result_type = fuzzerutil::MaybeGetPointerType( - ir_context, subobject_type_id, - static_cast(pointer_type->GetSingleWordInOperand(0))); - - // Add the access chain instruction to the module, and update the module's - // id bound. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpAccessChain, result_type, message_.fresh_id(), - operands)); - - // Conservatively invalidate all analyses. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - - // If the base pointer's pointee value was irrelevant, the same is true of - // the pointee value of the result of this access chain. - if (transformation_context->GetFactManager()->PointeeValueIsIrrelevant( - message_.pointer_id())) { - transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( - message_.fresh_id()); - } -} - -protobufs::Transformation TransformationAccessChain::ToMessage() const { - protobufs::Transformation result; - *result.mutable_access_chain() = message_; - return result; -} - -std::pair TransformationAccessChain::GetIndexValue( - opt::IRContext* ir_context, uint32_t index_id, - uint32_t object_type_id) const { - if (!ValidIndexToComposite(ir_context, index_id, object_type_id)) { - return {false, 0}; - } - auto index_instruction = ir_context->get_def_use_mgr()->GetDef(index_id); - - uint32_t bound = fuzzerutil::GetBoundForCompositeIndex( - *ir_context->get_def_use_mgr()->GetDef(object_type_id), ir_context); - - // The index must be a constant - if (!spvOpcodeIsConstant(index_instruction->opcode())) { - return {false, 0}; - } - - // The index must be in bounds. - uint32_t value = index_instruction->GetSingleWordInOperand(0); - - if (value >= bound) { - return {false, 0}; - } - - return {true, value}; -} - -bool TransformationAccessChain::ValidIndexToComposite( - opt::IRContext* ir_context, uint32_t index_id, uint32_t object_type_id) { - auto object_type_def = ir_context->get_def_use_mgr()->GetDef(object_type_id); - // The object being indexed must be a composite. - if (!spvOpcodeIsComposite(object_type_def->opcode())) { - return false; - } - - // Get the defining instruction of the index. - auto index_instruction = ir_context->get_def_use_mgr()->GetDef(index_id); - if (!index_instruction) { - return false; - } - - // The index type must be 32-bit integer. - auto index_type = - ir_context->get_def_use_mgr()->GetDef(index_instruction->type_id()); - if (index_type->opcode() != SpvOpTypeInt || - index_type->GetSingleWordInOperand(0) != 32) { - return false; - } - - // If the object being traversed is a struct, the id must correspond to an - // in-bound constant. - if (object_type_def->opcode() == SpvOpTypeStruct) { - if (!spvOpcodeIsConstant(index_instruction->opcode())) { - return false; - } - } - return true; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_access_chain.h b/3rdparty/spirv-tools/source/fuzz/transformation_access_chain.h deleted file mode 100644 index db5b8e675..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_access_chain.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ACCESS_CHAIN_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ACCESS_CHAIN_H_ - -#include - -#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 TransformationAccessChain : public Transformation { - public: - explicit TransformationAccessChain( - const protobufs::TransformationAccessChain& message); - - TransformationAccessChain( - uint32_t fresh_id, uint32_t pointer_id, - const std::vector& index_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before, - const std::vector>& fresh_ids_for_clamping = - {}); - - // - |message_.fresh_id| must be fresh. - // - |message_.instruction_to_insert_before| must identify an instruction - // before which it is legitimate to insert an OpAccessChain instruction. - // - |message_.pointer_id| must be a result id with pointer type that is - // available (according to dominance rules) at the insertion point. - // - The pointer must not be OpConstantNull or OpUndef. - // - |message_.index_id| must be a sequence of ids of 32-bit integers - // such that it is possible to walk the pointee type of - // |message_.pointer_id| using these indices. - // - All indices used to access a struct must be OpConstant. - // - The indices used to index non-struct composites will be clamped to be - // in bound. Enough fresh ids must be given in - // |message_.fresh_id_for_clamping| to perform clamping (2 for - // each index accessing a non-struct). This requires the bool type and - // a constant of value (bound - 1) to be declared in the module. - // - If type t is the final type reached by walking these indices, the module - // must include an instruction "OpTypePointer SC %t" where SC is the storage - // class associated with |message_.pointer_id|. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an instruction of the form: - // |message_.fresh_id| = OpAccessChain %ptr |message_.index_id| - // where %ptr is the result if of an instruction declaring a pointer to the - // type reached by walking the pointee type of |message_.pointer_id| using - // the indices in |message_.index_id|, and with the same storage class as - // |message_.pointer_id|. - // - // For each of the indices traversing non-struct composites, two clamping - // instructions are added using ids in |message_.fresh_id_for_clamping|. - // - // If the fact manager in |transformation_context| reports that - // |message_.pointer_id| has an irrelevant pointee value, then the fact that - // |message_.fresh_id| (the result of the access chain) also has an irrelevant - // pointee value is also recorded. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Returns {false, 0} in each of the following cases: - // - |index_id| does not correspond to a 32-bit integer constant - // - the object being indexed is not a composite type - // - the constant at |index_id| is out of bounds. - // Otherwise, returns {true, value}, where value is the value of the constant - // at |index_id|. - std::pair GetIndexValue(opt::IRContext* ir_context, - uint32_t index_id, - uint32_t object_type_id) const; - - // Returns true if |index_id| corresponds, in the given context, to a 32-bit - // integer which can be used to index an object of the type specified by - // |object_type_id|. Returns false otherwise. - static bool ValidIndexToComposite(opt::IRContext* ir_context, - uint32_t index_id, uint32_t object_type_id); - - protobufs::TransformationAccessChain message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ACCESS_CHAIN_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp deleted file mode 100644 index 904ad6104..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_constant_boolean.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/opt/types.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddConstantBoolean::TransformationAddConstantBoolean( - const protobufs::TransformationAddConstantBoolean& message) - : message_(message) {} - -TransformationAddConstantBoolean::TransformationAddConstantBoolean( - uint32_t fresh_id, bool is_true, bool is_irrelevant) { - message_.set_fresh_id(fresh_id); - message_.set_is_true(is_true); - message_.set_is_irrelevant(is_irrelevant); -} - -bool TransformationAddConstantBoolean::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - return fuzzerutil::MaybeGetBoolType(ir_context) != 0 && - fuzzerutil::IsFreshId(ir_context, message_.fresh_id()); -} - -void TransformationAddConstantBoolean::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Add the boolean constant to the module, ensuring the module's id bound is - // high enough. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - ir_context->module()->AddGlobalValue( - message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse, - message_.fresh_id(), fuzzerutil::MaybeGetBoolType(ir_context)); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - - if (message_.is_irrelevant()) { - transformation_context->GetFactManager()->AddFactIdIsIrrelevant( - message_.fresh_id()); - } -} - -protobufs::Transformation TransformationAddConstantBoolean::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_constant_boolean() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h deleted file mode 100644 index d2f9e9ad3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_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 TransformationAddConstantBoolean : public Transformation { - public: - explicit TransformationAddConstantBoolean( - const protobufs::TransformationAddConstantBoolean& message); - - TransformationAddConstantBoolean(uint32_t fresh_id, bool is_true, - bool is_irrelevant); - - // - |message_.fresh_id| must not be used by the module. - // - The module must already contain OpTypeBool. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - Adds OpConstantTrue (OpConstantFalse) to the module with id - // |message_.fresh_id| if |message_.is_true| holds (does not hold). - // - Also, creates an IdIsIrrelevant fact about |fresh_id| if |is_irrelevant| - // is true. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddConstantBoolean message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_composite.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_composite.cpp deleted file mode 100644 index 99d88b40b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_composite.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_constant_composite.h" - -#include - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddConstantComposite::TransformationAddConstantComposite( - const spvtools::fuzz::protobufs::TransformationAddConstantComposite& - message) - : message_(message) {} - -TransformationAddConstantComposite::TransformationAddConstantComposite( - uint32_t fresh_id, uint32_t type_id, - const std::vector& constituent_ids, bool is_irrelevant) { - message_.set_fresh_id(fresh_id); - message_.set_type_id(type_id); - message_.set_is_irrelevant(is_irrelevant); - for (auto constituent_id : constituent_ids) { - message_.add_constituent_id(constituent_id); - } -} - -bool TransformationAddConstantComposite::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Check that the given id is fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // Check that the composite type id is an instruction id. - auto composite_type_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.type_id()); - if (!composite_type_instruction) { - return false; - } - // Gather up the operands for the composite constant, in the process checking - // whether the given type really defines a composite. - std::vector constituent_type_ids; - switch (composite_type_instruction->opcode()) { - case SpvOpTypeArray: - for (uint32_t index = 0; - index < - fuzzerutil::GetArraySize(*composite_type_instruction, ir_context); - index++) { - constituent_type_ids.push_back( - composite_type_instruction->GetSingleWordInOperand(0)); - } - break; - case SpvOpTypeMatrix: - case SpvOpTypeVector: - for (uint32_t index = 0; - index < composite_type_instruction->GetSingleWordInOperand(1); - index++) { - constituent_type_ids.push_back( - composite_type_instruction->GetSingleWordInOperand(0)); - } - break; - case SpvOpTypeStruct: - composite_type_instruction->ForEachInOperand( - [&constituent_type_ids](const uint32_t* member_type_id) { - constituent_type_ids.push_back(*member_type_id); - }); - break; - default: - // Not a composite type. - return false; - } - - // Check that the number of provided operands matches the number of - // constituents required by the type. - if (constituent_type_ids.size() != - static_cast(message_.constituent_id().size())) { - return false; - } - - // Check that every provided operand refers to an instruction of the - // corresponding constituent type. - for (uint32_t index = 0; index < constituent_type_ids.size(); index++) { - auto constituent_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.constituent_id(index)); - if (!constituent_instruction) { - return false; - } - if (constituent_instruction->type_id() != constituent_type_ids.at(index)) { - return false; - } - } - return true; -} - -void TransformationAddConstantComposite::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - opt::Instruction::OperandList in_operands; - for (auto constituent_id : message_.constituent_id()) { - in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}}); - } - ir_context->module()->AddGlobalValue(MakeUnique( - ir_context, SpvOpConstantComposite, message_.type_id(), - message_.fresh_id(), in_operands)); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - - if (message_.is_irrelevant()) { - transformation_context->GetFactManager()->AddFactIdIsIrrelevant( - message_.fresh_id()); - } -} - -protobufs::Transformation TransformationAddConstantComposite::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_add_constant_composite() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_composite.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_composite.h deleted file mode 100644 index 2dddbfb5b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_composite.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_COMPOSITE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_COMPOSITE_H_ - -#include - -#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 TransformationAddConstantComposite : public Transformation { - public: - explicit TransformationAddConstantComposite( - const protobufs::TransformationAddConstantComposite& message); - - TransformationAddConstantComposite( - uint32_t fresh_id, uint32_t type_id, - const std::vector& constituent_ids, bool is_irrelevant); - - // - |message_.fresh_id| must be a fresh id - // - |message_.type_id| must be the id of a composite type - // - |message_.constituent_id| must refer to ids that match the constituent - // types of this composite type - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - Adds an OpConstantComposite instruction defining a constant of type - // |message_.type_id|, using |message_.constituent_id| as constituents, with - // result id |message_.fresh_id|. - // - Creates an IdIsIrrelevant fact about |fresh_id| if |is_irrelevant| is - // true. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddConstantComposite message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_COMPOSITE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_null.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_null.cpp deleted file mode 100644 index dedbc2109..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_null.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_constant_null.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddConstantNull::TransformationAddConstantNull( - const spvtools::fuzz::protobufs::TransformationAddConstantNull& message) - : message_(message) {} - -TransformationAddConstantNull::TransformationAddConstantNull(uint32_t fresh_id, - uint32_t type_id) { - message_.set_fresh_id(fresh_id); - message_.set_type_id(type_id); -} - -bool TransformationAddConstantNull::IsApplicable( - opt::IRContext* context, const TransformationContext& /*unused*/) const { - // A fresh id is required. - if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { - return false; - } - auto type = context->get_type_mgr()->GetType(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); -} - -void TransformationAddConstantNull::Apply( - opt::IRContext* context, TransformationContext* /*unused*/) const { - context->module()->AddGlobalValue(MakeUnique( - context, SpvOpConstantNull, message_.type_id(), message_.fresh_id(), - opt::Instruction::OperandList())); - fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddConstantNull::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_constant_null() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_null.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_null.h deleted file mode 100644 index 590fc0daa..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_null.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_NULL_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_NULL_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 TransformationAddConstantNull : public Transformation { - public: - explicit TransformationAddConstantNull( - const protobufs::TransformationAddConstantNull& message); - - TransformationAddConstantNull(uint32_t fresh_id, uint32_t type_id); - - // - |message_.fresh_id| must be fresh - // - |message_.type_id| must be the id of a type for which it is acceptable - // to create a null constant - bool IsApplicable( - opt::IRContext* context, - const TransformationContext& transformation_context) const override; - - // Adds an OpConstantNull instruction to the module, with |message_.type_id| - // as its type. The instruction has result id |message_.fresh_id|. - void Apply(opt::IRContext* context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddConstantNull message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_NULL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp deleted file mode 100644 index e0b4dfbad..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_constant_scalar.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddConstantScalar::TransformationAddConstantScalar( - const spvtools::fuzz::protobufs::TransformationAddConstantScalar& message) - : message_(message) {} - -TransformationAddConstantScalar::TransformationAddConstantScalar( - uint32_t fresh_id, uint32_t type_id, const std::vector& words, - bool is_irrelevant) { - message_.set_fresh_id(fresh_id); - message_.set_type_id(type_id); - message_.set_is_irrelevant(is_irrelevant); - for (auto word : words) { - message_.add_word(word); - } -} - -bool TransformationAddConstantScalar::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The id needs to be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // The type id for the scalar must exist and be a type. - auto type = ir_context->get_type_mgr()->GetType(message_.type_id()); - if (!type) { - return false; - } - uint32_t width; - if (type->AsFloat()) { - width = type->AsFloat()->width(); - } else if (type->AsInteger()) { - width = type->AsInteger()->width(); - } else { - return false; - } - // The number of words is the integer floor of the width. - auto words = (width + 32 - 1) / 32; - - // The number of words provided by the transformation needs to match the - // width of the type. - return static_cast(message_.word().size()) == words; -} - -void TransformationAddConstantScalar::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - ir_context->module()->AddGlobalValue(MakeUnique( - ir_context, SpvOpConstant, message_.type_id(), message_.fresh_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_LITERAL_INTEGER, - std::vector(message_.word().begin(), - message_.word().end())}}))); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - - if (message_.is_irrelevant()) { - transformation_context->GetFactManager()->AddFactIdIsIrrelevant( - message_.fresh_id()); - } -} - -protobufs::Transformation TransformationAddConstantScalar::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_constant_scalar() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h deleted file mode 100644 index 06a77fc7d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ - -#include - -#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 TransformationAddConstantScalar : public Transformation { - public: - explicit TransformationAddConstantScalar( - const protobufs::TransformationAddConstantScalar& message); - - TransformationAddConstantScalar(uint32_t fresh_id, uint32_t type_id, - const std::vector& words, - bool is_irrelevant); - - // - |message_.fresh_id| must not be used by the module - // - |message_.type_id| must be the id of a floating-point or integer type - // - The size of |message_.word| must be compatible with the width of this - // type - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds a new OpConstant instruction with the given type and words. - // Creates an IdIsIrrelevant fact about |fresh_id| if |is_irrelevant| is true. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddConstantScalar message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.cpp deleted file mode 100644 index e9c401d73..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.cpp +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_copy_memory.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/opt/instruction.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddCopyMemory::TransformationAddCopyMemory( - const protobufs::TransformationAddCopyMemory& message) - : message_(message) {} - -TransformationAddCopyMemory::TransformationAddCopyMemory( - const protobufs::InstructionDescriptor& instruction_descriptor, - uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class, - uint32_t initializer_id) { - *message_.mutable_instruction_descriptor() = instruction_descriptor; - message_.set_fresh_id(fresh_id); - message_.set_source_id(source_id); - message_.set_storage_class(storage_class); - message_.set_initializer_id(initializer_id); -} - -bool TransformationAddCopyMemory::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Check that target id is fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // Check that instruction descriptor is valid. This also checks that - // |message_.instruction_descriptor| is not a global instruction. - auto* inst = FindInstruction(message_.instruction_descriptor(), ir_context); - if (!inst) { - return false; - } - - // Check that we can insert OpCopyMemory before |instruction_descriptor|. - auto iter = fuzzerutil::GetIteratorForInstruction( - ir_context->get_instr_block(inst), inst); - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory, iter)) { - return false; - } - - // Check that source instruction exists and is valid. - auto* source_inst = - ir_context->get_def_use_mgr()->GetDef(message_.source_id()); - if (!source_inst || !IsInstructionSupported(ir_context, source_inst)) { - return false; - } - - // |storage_class| is either Function or Private. - if (message_.storage_class() != SpvStorageClassFunction && - message_.storage_class() != SpvStorageClassPrivate) { - return false; - } - - auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType( - ir_context, source_inst->type_id()); - - // OpTypePointer with |message_.storage_class| exists. - if (!fuzzerutil::MaybeGetPointerType( - ir_context, pointee_type_id, - static_cast(message_.storage_class()))) { - return false; - } - - // Check that |initializer_id| exists and has valid type. - const auto* initializer_inst = - ir_context->get_def_use_mgr()->GetDef(message_.initializer_id()); - if (!initializer_inst || initializer_inst->type_id() != pointee_type_id) { - return false; - } - - // Check that domination rules are satisfied. - return fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, inst, - message_.source_id()); -} - -void TransformationAddCopyMemory::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Insert OpCopyMemory before |instruction_descriptor|. - auto* insert_before_inst = - FindInstruction(message_.instruction_descriptor(), ir_context); - assert(insert_before_inst); - - auto insert_before_iter = fuzzerutil::GetIteratorForInstruction( - ir_context->get_instr_block(insert_before_inst), insert_before_inst); - - insert_before_iter.InsertBefore(MakeUnique( - ir_context, SpvOpCopyMemory, 0, 0, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.source_id()}}})); - - // Add global or local variable to copy memory into. - auto storage_class = static_cast(message_.storage_class()); - auto type_id = fuzzerutil::MaybeGetPointerType( - ir_context, - fuzzerutil::GetPointeeTypeIdFromPointerType( - ir_context, fuzzerutil::GetTypeId(ir_context, message_.source_id())), - storage_class); - - if (storage_class == SpvStorageClassPrivate) { - fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id, - storage_class, message_.initializer_id()); - } else { - assert(storage_class == SpvStorageClassFunction && - "Storage class can be either Private or Function"); - fuzzerutil::AddLocalVariable(ir_context, message_.fresh_id(), type_id, - ir_context->get_instr_block(insert_before_inst) - ->GetParent() - ->result_id(), - message_.initializer_id()); - } - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // Even though the copy memory instruction will - at least temporarily - lead - // to the destination and source pointers referring to identical values, this - // fact is not guaranteed to hold throughout execution of the SPIR-V code - // since the source pointer could be over-written. We thus assume nothing - // about the destination pointer, and record this fact so that the destination - // pointer can be used freely by other fuzzer passes. - transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( - message_.fresh_id()); - - // Make sure our changes are analyzed - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddCopyMemory::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_copy_memory() = message_; - return result; -} - -bool TransformationAddCopyMemory::IsInstructionSupported( - opt::IRContext* ir_context, opt::Instruction* inst) { - if (!inst->result_id() || !inst->type_id() || - inst->opcode() == SpvOpConstantNull || inst->opcode() == SpvOpUndef) { - return false; - } - - const auto* type = ir_context->get_type_mgr()->GetType(inst->type_id()); - assert(type && "Instruction must have a valid type"); - - return type->AsPointer() && - CanUsePointeeWithCopyMemory(*type->AsPointer()->pointee_type()); -} - -bool TransformationAddCopyMemory::CanUsePointeeWithCopyMemory( - const opt::analysis::Type& type) { - switch (type.kind()) { - case opt::analysis::Type::kBool: - case opt::analysis::Type::kInteger: - case opt::analysis::Type::kFloat: - case opt::analysis::Type::kArray: - return true; - case opt::analysis::Type::kVector: - return CanUsePointeeWithCopyMemory(*type.AsVector()->element_type()); - case opt::analysis::Type::kMatrix: - return CanUsePointeeWithCopyMemory(*type.AsMatrix()->element_type()); - case opt::analysis::Type::kStruct: - return std::all_of(type.AsStruct()->element_types().begin(), - type.AsStruct()->element_types().end(), - [](const opt::analysis::Type* element) { - return CanUsePointeeWithCopyMemory(*element); - }); - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.h deleted file mode 100644 index 138d9925b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_COPY_MEMORY_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_COPY_MEMORY_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 TransformationAddCopyMemory : public Transformation { - public: - explicit TransformationAddCopyMemory( - const protobufs::TransformationAddCopyMemory& message); - - TransformationAddCopyMemory( - const protobufs::InstructionDescriptor& instruction_descriptor, - uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class, - uint32_t initializer_id); - - // - |instruction_descriptor| must point to a valid instruction in the module. - // - it should be possible to insert OpCopyMemory before - // |instruction_descriptor| (i.e. the module remains valid after the - // insertion). - // - |source_id| must be a result id for some valid instruction in the module. - // - |fresh_id| must be a fresh id to copy memory into. - // - type of |source_id| must be OpTypePointer where pointee can be used with - // OpCopyMemory. - // - |storage_class| must be either Private or Function. - // - type ids of instructions with result ids |source_id| and |initialize_id| - // must be the same. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // A global or local variable with id |target_id| and |storage_class| class is - // created. An 'OpCopyMemory %fresh_id %source_id' instruction is inserted - // before the |instruction_descriptor|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if we can copy memory from |instruction| using OpCopyMemory. - static bool IsInstructionSupported(opt::IRContext* ir_context, - opt::Instruction* inst); - - private: - // Returns whether the type, pointed to by some OpTypePointer, can be used - // with OpCopyMemory instruction. - static bool CanUsePointeeWithCopyMemory(const opt::analysis::Type& type); - - protobufs::TransformationAddCopyMemory message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_COPY_MEMORY_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.cpp deleted file mode 100644 index 9b50ea79d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.cpp +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_dead_block.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddDeadBlock::TransformationAddDeadBlock( - const spvtools::fuzz::protobufs::TransformationAddDeadBlock& message) - : message_(message) {} - -TransformationAddDeadBlock::TransformationAddDeadBlock(uint32_t fresh_id, - uint32_t existing_block, - bool condition_value) { - message_.set_fresh_id(fresh_id); - message_.set_existing_block(existing_block); - message_.set_condition_value(condition_value); -} - -bool TransformationAddDeadBlock::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // The new block's id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // First, we check that a constant with the same value as - // |message_.condition_value| is present. - if (!fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.condition_value(), false)) { - // The required constant is not present, so the transformation cannot be - // applied. - return false; - } - - // The existing block must indeed exist. - auto existing_block = - fuzzerutil::MaybeFindBlock(ir_context, message_.existing_block()); - if (!existing_block) { - return false; - } - - // It must not head a loop. - if (existing_block->IsLoopHeader()) { - return false; - } - - // It must end with OpBranch. - if (existing_block->terminator()->opcode() != SpvOpBranch) { - return false; - } - - // Its successor must not be a merge block nor continue target. - auto successor_block_id = - existing_block->terminator()->GetSingleWordInOperand(0); - if (fuzzerutil::IsMergeOrContinue(ir_context, successor_block_id)) { - return false; - } - - // The successor must not be a loop header (i.e., |message_.existing_block| - // must not be a back-edge block. - if (ir_context->cfg()->block(successor_block_id)->IsLoopHeader()) { - return false; - } - - // |existing_block| must be reachable. - opt::DominatorAnalysis* dominator_analysis = - ir_context->GetDominatorAnalysis(existing_block->GetParent()); - if (!dominator_analysis->IsReachable(existing_block->id())) { - return false; - } - - assert(existing_block->id() != successor_block_id && - "|existing_block| must be different from |successor_block_id|"); - - // Even though we know |successor_block_id| is not a merge block, it might - // still have multiple predecessors because divergent control flow is allowed - // to converge early (before the merge block). In this case, when we create - // the selection construct, its header |existing_block| will not dominate the - // merge block |successor_block_id|, which is invalid. Thus, |existing_block| - // must dominate |successor_block_id|. - if (!dominator_analysis->Dominates(existing_block->id(), - successor_block_id)) { - return false; - } - - return true; -} - -void TransformationAddDeadBlock::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Update the module id bound so that it is at least the id of the new block. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // Get the existing block and its successor. - auto existing_block = ir_context->cfg()->block(message_.existing_block()); - auto successor_block_id = - existing_block->terminator()->GetSingleWordInOperand(0); - - // Get the id of the boolean value that will be used as the branch condition. - auto bool_id = fuzzerutil::MaybeGetBoolConstant( - ir_context, *transformation_context, message_.condition_value(), false); - - // Make a new block that unconditionally branches to the original successor - // block. - auto enclosing_function = existing_block->GetParent(); - std::unique_ptr new_block = - MakeUnique(MakeUnique( - ir_context, SpvOpLabel, 0, message_.fresh_id(), - opt::Instruction::OperandList())); - new_block->AddInstruction(MakeUnique( - ir_context, SpvOpBranch, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {successor_block_id}}}))); - - // Turn the original block into a selection merge, with its original successor - // as the merge block. - existing_block->terminator()->InsertBefore(MakeUnique( - ir_context, SpvOpSelectionMerge, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {successor_block_id}}, - {SPV_OPERAND_TYPE_SELECTION_CONTROL, - {SpvSelectionControlMaskNone}}}))); - - // Change the original block's terminator to be a conditional branch on the - // given boolean, with the original successor and the new successor as branch - // targets, and such that at runtime control will always transfer to the - // original successor. - existing_block->terminator()->SetOpcode(SpvOpBranchConditional); - existing_block->terminator()->SetInOperands( - {{SPV_OPERAND_TYPE_ID, {bool_id}}, - {SPV_OPERAND_TYPE_ID, - {message_.condition_value() ? successor_block_id - : message_.fresh_id()}}, - {SPV_OPERAND_TYPE_ID, - {message_.condition_value() ? message_.fresh_id() - : successor_block_id}}}); - - // Add the new block to the enclosing function. - new_block->SetParent(enclosing_function); - enclosing_function->InsertBasicBlockAfter(std::move(new_block), - existing_block); - - // Record the fact that the new block is dead. - transformation_context->GetFactManager()->AddFactBlockIsDead( - message_.fresh_id()); - - // Fix up OpPhi instructions in the successor block, so that the values they - // yield when control has transferred from the new block are the same as if - // control had transferred from |message_.existing_block|. This is guaranteed - // to be valid since |message_.existing_block| dominates the new block by - // construction. Other transformations can change these phi operands to more - // interesting values. - ir_context->cfg() - ->block(successor_block_id) - ->ForEachPhiInst([this](opt::Instruction* phi_inst) { - // Copy the operand that provides the phi value for the first of any - // existing predecessors. - opt::Operand copy_of_existing_operand = phi_inst->GetInOperand(0); - // Use this as the value associated with the new predecessor. - phi_inst->AddOperand(std::move(copy_of_existing_operand)); - phi_inst->AddOperand({SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}); - }); - - // Do not rely on any existing analysis results since the control flow graph - // of the module has changed. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationAddDeadBlock::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_dead_block() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.h deleted file mode 100644 index 7d0761647..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_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 TransformationAddDeadBlock : public Transformation { - public: - explicit TransformationAddDeadBlock( - const protobufs::TransformationAddDeadBlock& message); - - TransformationAddDeadBlock(uint32_t fresh_id, uint32_t existing_block, - bool condition_value); - - // - |message_.fresh_id| must be a fresh id - // - A constant with the same value as |message_.condition_value| must be - // available - // - |message_.existing_block| must be a block that is not a loop header, - // and that ends with OpBranch to a block that is not a merge block nor - // continue target - this is because the successor will become the merge - // block of a selection construct headed at |message_.existing_block| - // - |message_.existing_block| must not be a back-edge block, since in this - // case the newly-added block would lead to another back-edge to the - // associated loop header - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Changes the OpBranch from |message_.existing_block| to its successor 's' - // to an OpBranchConditional to either 's' or a new block, - // |message_.fresh_id|, which itself unconditionally branches to 's'. The - // conditional branch uses |message.condition_value| as its condition, and is - // arranged so that control will pass to 's' at runtime. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddDeadBlock message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp deleted file mode 100644 index 284174ad7..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_dead_break.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_context.h" -#include "source/opt/basic_block.h" -#include "source/opt/ir_context.h" -#include "source/opt/struct_cfg_analysis.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddDeadBreak::TransformationAddDeadBreak( - const spvtools::fuzz::protobufs::TransformationAddDeadBreak& message) - : message_(message) {} - -TransformationAddDeadBreak::TransformationAddDeadBreak( - uint32_t from_block, uint32_t to_block, bool break_condition_value, - std::vector phi_id) { - message_.set_from_block(from_block); - message_.set_to_block(to_block); - message_.set_break_condition_value(break_condition_value); - for (auto id : phi_id) { - message_.add_phi_id(id); - } -} - -bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow( - opt::IRContext* ir_context, opt::BasicBlock* bb_from) const { - // Look at the structured control flow associated with |from_block| and - // check whether it is contained in an appropriate construct with merge id - // |to_block| such that a break from |from_block| to |to_block| is legal. - - // There are three legal cases to consider: - // (1) |from_block| is a loop header and |to_block| is its merge - // (2) |from_block| is a non-header node of a construct, and |to_block| - // is the merge for that construct - // (3) |from_block| is a non-header node of a selection construct, and - // |to_block| is the merge for the innermost loop containing - // |from_block| - // - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2653) It may be - // possible to be more aggressive in breaking from switch constructs. - // - // The reason we need to distinguish between cases (1) and (2) is that the - // structured CFG analysis does not deem a header to be part of the construct - // that it heads. - - // Consider case (1) - if (bb_from->IsLoopHeader()) { - // Case (1) holds if |to_block| is the merge block for the loop; - // otherwise no case holds - return bb_from->MergeBlockId() == message_.to_block(); - } - - // Both cases (2) and (3) require that |from_block| is inside some - // structured control flow construct. - - auto containing_construct = - ir_context->GetStructuredCFGAnalysis()->ContainingConstruct( - message_.from_block()); - if (!containing_construct) { - // |from_block| is not in a construct from which we can break. - return false; - } - - // Consider case (2) - if (message_.to_block() == - ir_context->cfg()->block(containing_construct)->MergeBlockId()) { - // This looks like an instance of case (2). - // However, the structured CFG analysis regards the continue construct of a - // loop as part of the loop, but it is not legal to jump from a loop's - // continue construct to the loop's merge (except from the back-edge block), - // so we need to check for this case. - return !fuzzerutil::BlockIsInLoopContinueConstruct( - ir_context, message_.from_block(), containing_construct) || - fuzzerutil::BlockIsBackEdge(ir_context, message_.from_block(), - containing_construct); - } - - // Case (3) holds if and only if |to_block| is the merge block for this - // innermost loop that contains |from_block| - auto containing_loop_header = - ir_context->GetStructuredCFGAnalysis()->ContainingLoop( - message_.from_block()); - if (containing_loop_header && - message_.to_block() == - ir_context->cfg()->block(containing_loop_header)->MergeBlockId()) { - return !fuzzerutil::BlockIsInLoopContinueConstruct( - ir_context, message_.from_block(), containing_loop_header) || - fuzzerutil::BlockIsBackEdge(ir_context, message_.from_block(), - containing_loop_header); - } - return false; -} - -bool TransformationAddDeadBreak::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // First, we check that a constant with the same value as - // |message_.break_condition_value| is present. - if (!fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.break_condition_value(), - false)) { - // The required constant is not present, so the transformation cannot be - // applied. - return false; - } - - // Check that |message_.from_block| and |message_.to_block| really are block - // ids - opt::BasicBlock* bb_from = - fuzzerutil::MaybeFindBlock(ir_context, message_.from_block()); - if (bb_from == nullptr) { - return false; - } - opt::BasicBlock* bb_to = - fuzzerutil::MaybeFindBlock(ir_context, message_.to_block()); - if (bb_to == nullptr) { - return false; - } - - if (!fuzzerutil::BlockIsReachableInItsFunction(ir_context, bb_to)) { - // If the target of the break is unreachable, we conservatively do not - // allow adding a dead break, to avoid the compilations that arise due to - // the lack of sensible dominance information for unreachable blocks. - return false; - } - - // Check that |message_.from_block| ends with an unconditional branch. - if (bb_from->terminator()->opcode() != SpvOpBranch) { - // The block associated with the id does not end with an unconditional - // branch. - return false; - } - - assert(bb_from != nullptr && - "We should have found a block if this line of code is reached."); - assert( - bb_from->id() == message_.from_block() && - "The id of the block we found should match the source id for the break."); - assert(bb_to != nullptr && - "We should have found a block if this line of code is reached."); - assert( - bb_to->id() == message_.to_block() && - "The id of the block we found should match the target id for the break."); - - // Check whether the data passed to extend OpPhi instructions is appropriate. - if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, bb_from, bb_to, - message_.phi_id())) { - return false; - } - - // Check that adding the break would respect the rules of structured - // control flow. - if (!AddingBreakRespectsStructuredControlFlow(ir_context, bb_from)) { - return false; - } - - // Adding the dead break is only valid if SPIR-V rules related to dominance - // hold. Rather than checking these rules explicitly, we defer to the - // validator. We make a clone of the module, apply the transformation to the - // clone, and check whether the transformed clone is valid. - // - // In principle some of the above checks could be removed, with more reliance - // being places on the validator. This should be revisited if we are sure - // the validator is complete with respect to checking structured control flow - // rules. - auto cloned_context = fuzzerutil::CloneIRContext(ir_context); - ApplyImpl(cloned_context.get(), transformation_context); - return fuzzerutil::IsValid(cloned_context.get(), - transformation_context.GetValidatorOptions()); -} - -void TransformationAddDeadBreak::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - ApplyImpl(ir_context, *transformation_context); - // Invalidate all analyses - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddDeadBreak::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_dead_break() = message_; - return result; -} - -void TransformationAddDeadBreak::ApplyImpl( - spvtools::opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( - ir_context, ir_context->cfg()->block(message_.from_block()), - ir_context->cfg()->block(message_.to_block()), - fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.break_condition_value(), false), - message_.phi_id()); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h deleted file mode 100644 index f010b11ff..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ - -#include - -#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 TransformationAddDeadBreak : public Transformation { - public: - explicit TransformationAddDeadBreak( - const protobufs::TransformationAddDeadBreak& message); - - TransformationAddDeadBreak(uint32_t from_block, uint32_t to_block, - bool break_condition_value, - std::vector phi_id); - - // - |message_.from_block| must be the id of a block a in the given module. - // - |message_.to_block| must be the id of a block b in the given module. - // - if |message_.break_condition_value| holds (does not hold) then - // OpConstantTrue (OpConstantFalse) must be present in the module - // - |message_.phi_ids| must be a list of ids that are all available at - // |message_.from_block| - // - a and b must be in the same function. - // - b must be a merge block. - // - a must end with an unconditional branch to some block c. - // - replacing this branch with a conditional branch to b or c, with - // the boolean constant associated with |message_.break_condition_value| as - // the condition, and the ids in |message_.phi_ids| used to extend - // any OpPhi instructions at b as a result of the edge from a, must - // maintain validity of the module. - // In particular, the new branch must not lead to violations of the rule - // that a use must be dominated by its definition. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces the terminator of a with a conditional branch to b or c. - // The boolean constant associated with |message_.break_condition_value| is - // used as the condition, and the order of b and c is arranged such that - // control is guaranteed to jump to c. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Returns true if and only if adding an edge from |bb_from| to - // |message_.to_block| respects structured control flow. - bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* ir_context, - opt::BasicBlock* bb_from) const; - - // Used by 'Apply' to actually apply the transformation to the module of - // interest, and by 'IsApplicable' to do a dry-run of the transformation on a - // cloned module, in order to check that the transformation leads to a valid - // module. This is only invoked by 'IsApplicable' after certain basic - // applicability checks have been made, ensuring that the invocation of this - // method is legal. - void ApplyImpl(opt::IRContext* ir_context, - const TransformationContext& transformation_context) const; - - protobufs::TransformationAddDeadBreak message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp deleted file mode 100644 index b5b7ae3fe..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_dead_continue.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddDeadContinue::TransformationAddDeadContinue( - const spvtools::fuzz::protobufs::TransformationAddDeadContinue& message) - : message_(message) {} - -TransformationAddDeadContinue::TransformationAddDeadContinue( - uint32_t from_block, bool continue_condition_value, - std::vector phi_id) { - message_.set_from_block(from_block); - message_.set_continue_condition_value(continue_condition_value); - for (auto id : phi_id) { - message_.add_phi_id(id); - } -} - -bool TransformationAddDeadContinue::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // First, we check that a constant with the same value as - // |message_.continue_condition_value| is present. - if (!fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.continue_condition_value(), - false)) { - // The required constant is not present, so the transformation cannot be - // applied. - return false; - } - - // Check that |message_.from_block| really is a block id. - opt::BasicBlock* bb_from = - fuzzerutil::MaybeFindBlock(ir_context, message_.from_block()); - if (bb_from == nullptr) { - return false; - } - - // Check that |message_.from_block| ends with an unconditional branch. - if (bb_from->terminator()->opcode() != SpvOpBranch) { - // The block associated with the id does not end with an unconditional - // branch. - return false; - } - - assert(bb_from != nullptr && - "We should have found a block if this line of code is reached."); - assert( - bb_from->id() == message_.from_block() && - "The id of the block we found should match the source id for the break."); - - // Get the header for the innermost loop containing |message_.from_block|. - // Because the structured CFG analysis does not regard a loop header as part - // of the loop it heads, we check first whether bb_from is a loop header - // before using the structured CFG analysis. - auto loop_header = - bb_from->IsLoopHeader() - ? message_.from_block() - : ir_context->GetStructuredCFGAnalysis()->ContainingLoop( - message_.from_block()); - if (!loop_header) { - return false; - } - - auto continue_block = - ir_context->cfg()->block(loop_header)->ContinueBlockId(); - - if (!fuzzerutil::BlockIsReachableInItsFunction( - ir_context, ir_context->cfg()->block(continue_block))) { - // If the loop's continue block is unreachable, we conservatively do not - // allow adding a dead continue, to avoid the compilations that arise due to - // the lack of sensible dominance information for unreachable blocks. - return false; - } - - if (fuzzerutil::BlockIsInLoopContinueConstruct( - ir_context, message_.from_block(), loop_header)) { - // We cannot jump to the continue target from the continue construct. - return false; - } - - if (ir_context->GetStructuredCFGAnalysis()->IsMergeBlock(continue_block)) { - // A branch straight to the continue target that is also a merge block might - // break the property that a construct header must dominate its merge block - // (if the merge block is reachable). - return false; - } - - // Check whether the data passed to extend OpPhi instructions is appropriate. - if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, bb_from, - ir_context->cfg()->block(continue_block), - message_.phi_id())) { - return false; - } - - // Adding the dead break is only valid if SPIR-V rules related to dominance - // hold. Rather than checking these rules explicitly, we defer to the - // validator. We make a clone of the module, apply the transformation to the - // clone, and check whether the transformed clone is valid. - // - // In principle some of the above checks could be removed, with more reliance - // being placed on the validator. This should be revisited if we are sure - // the validator is complete with respect to checking structured control flow - // rules. - auto cloned_context = fuzzerutil::CloneIRContext(ir_context); - ApplyImpl(cloned_context.get(), transformation_context); - return fuzzerutil::IsValid(cloned_context.get(), - transformation_context.GetValidatorOptions()); -} - -void TransformationAddDeadContinue::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - ApplyImpl(ir_context, *transformation_context); - // Invalidate all analyses - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddDeadContinue::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_dead_continue() = message_; - return result; -} - -void TransformationAddDeadContinue::ApplyImpl( - spvtools::opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - auto bb_from = ir_context->cfg()->block(message_.from_block()); - auto continue_block = - bb_from->IsLoopHeader() - ? bb_from->ContinueBlockId() - : ir_context->GetStructuredCFGAnalysis()->LoopContinueBlock( - message_.from_block()); - assert(continue_block && "message_.from_block must be in a loop."); - fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( - ir_context, bb_from, ir_context->cfg()->block(continue_block), - fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.continue_condition_value(), - false), - message_.phi_id()); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.h deleted file mode 100644 index b977bb20f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_CONTINUE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_CONTINUE_H_ - -#include - -#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 TransformationAddDeadContinue : public Transformation { - public: - explicit TransformationAddDeadContinue( - const protobufs::TransformationAddDeadContinue& message); - - TransformationAddDeadContinue(uint32_t from_block, - bool continue_condition_value, - std::vector phi_id); - - // - |message_.from_block| must be the id of a block a in the given module. - // - a must be contained in a loop with continue target b - // - The continue target b must be dominated by the head of the loop in which - // it is contained - // - b must not be the merge block of a selection construct - // - if |message_.continue_condition_value| holds (does not hold) then - // OpConstantTrue (OpConstantFalse) must be present in the module - // - |message_.phi_ids| must be a list of ids that are all available at - // |message_.from_block| - // - a must end with an unconditional branch to some block c. - // - replacing this branch with a conditional branch to b or c, with - // the boolean constant associated with |message_.continue_condition_value| - // as the condition, and the ids in |message_.phi_ids| used to extend any - // OpPhi instructions at b as a result of the edge from a, must maintain - // validity of the module. - // In particular, adding an edge from somewhere in the loop to the continue - // target must not prevent uses of ids in the continue target from being - // dominated by the definitions of those ids. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces the terminator of a with a conditional branch to b or c. - // The boolean constant associated with |message_.continue_condition_value| is - // used as the condition, and the order of b and c is arranged such that - // control is guaranteed to jump to c. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Used by 'Apply' to actually apply the transformation to the module of - // interest, and by 'IsApplicable' to do a dry-run of the transformation on a - // cloned module, in order to check that the transformation leads to a valid - // module. This is only invoked by 'IsApplicable' after certain basic - // applicability checks have been made, ensuring that the invocation of this - // method is legal. - void ApplyImpl(opt::IRContext* ir_context, - const TransformationContext& transformation_context) const; - - protobufs::TransformationAddDeadContinue message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_CONTINUE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_function.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_function.cpp deleted file mode 100644 index 44c7d0539..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_function.cpp +++ /dev/null @@ -1,931 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_function.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_message.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddFunction::TransformationAddFunction( - const spvtools::fuzz::protobufs::TransformationAddFunction& message) - : message_(message) {} - -TransformationAddFunction::TransformationAddFunction( - const std::vector& instructions) { - for (auto& instruction : instructions) { - *message_.add_instruction() = instruction; - } - message_.set_is_livesafe(false); -} - -TransformationAddFunction::TransformationAddFunction( - const std::vector& instructions, - uint32_t loop_limiter_variable_id, uint32_t loop_limit_constant_id, - const std::vector& loop_limiters, - uint32_t kill_unreachable_return_value_id, - const std::vector& - access_chain_clampers) { - for (auto& instruction : instructions) { - *message_.add_instruction() = instruction; - } - message_.set_is_livesafe(true); - message_.set_loop_limiter_variable_id(loop_limiter_variable_id); - message_.set_loop_limit_constant_id(loop_limit_constant_id); - for (auto& loop_limiter : loop_limiters) { - *message_.add_loop_limiter_info() = loop_limiter; - } - message_.set_kill_unreachable_return_value_id( - kill_unreachable_return_value_id); - for (auto& access_clamper : access_chain_clampers) { - *message_.add_access_chain_clamping_info() = access_clamper; - } -} - -bool TransformationAddFunction::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // This transformation may use a lot of ids, all of which need to be fresh - // and distinct. This set tracks them. - std::set ids_used_by_this_transformation; - - // Ensure that all result ids in the new function are fresh and distinct. - for (auto& instruction : message_.instruction()) { - if (instruction.result_id()) { - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - instruction.result_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - } - } - - if (message_.is_livesafe()) { - // Ensure that all ids provided for making the function livesafe are fresh - // and distinct. - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.loop_limiter_variable_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - for (auto& loop_limiter_info : message_.loop_limiter_info()) { - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - loop_limiter_info.load_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - loop_limiter_info.increment_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - loop_limiter_info.compare_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - loop_limiter_info.logical_op_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - } - for (auto& access_chain_clamping_info : - message_.access_chain_clamping_info()) { - for (auto& pair : access_chain_clamping_info.compare_and_select_ids()) { - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - pair.first(), ir_context, &ids_used_by_this_transformation)) { - return false; - } - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - pair.second(), ir_context, &ids_used_by_this_transformation)) { - return false; - } - } - } - } - - // Because checking all the conditions for a function to be valid is a big - // job that the SPIR-V validator can already do, a "try it and see" approach - // is taken here. - - // We first clone the current module, so that we can try adding the new - // function without risking wrecking |ir_context|. - auto cloned_module = fuzzerutil::CloneIRContext(ir_context); - - // We try to add a function to the cloned module, which may fail if - // |message_.instruction| is not sufficiently well-formed. - if (!TryToAddFunction(cloned_module.get())) { - return false; - } - - // Check whether the cloned module is still valid after adding the function. - // If it is not, the transformation is not applicable. - if (!fuzzerutil::IsValid(cloned_module.get(), - transformation_context.GetValidatorOptions())) { - return false; - } - - if (message_.is_livesafe()) { - if (!TryToMakeFunctionLivesafe(cloned_module.get(), - transformation_context)) { - return false; - } - // After making the function livesafe, we check validity of the module - // again. This is because the turning of OpKill, OpUnreachable and OpReturn - // instructions into branches changes control flow graph reachability, which - // has the potential to make the module invalid when it was otherwise valid. - // It is simpler to rely on the validator to guard against this than to - // consider all scenarios when making a function livesafe. - if (!fuzzerutil::IsValid(cloned_module.get(), - transformation_context.GetValidatorOptions())) { - return false; - } - } - return true; -} - -void TransformationAddFunction::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Add the function to the module. As the transformation is applicable, this - // should succeed. - bool success = TryToAddFunction(ir_context); - assert(success && "The function should be successfully added."); - (void)(success); // Keep release builds happy (otherwise they may complain - // that |success| is not used). - - // Record the fact that all pointer parameters and variables declared in the - // function should be regarded as having irrelevant values. This allows other - // passes to store arbitrarily to such variables, and to pass them freely as - // parameters to other functions knowing that it is OK if they get - // over-written. - for (auto& instruction : message_.instruction()) { - switch (instruction.opcode()) { - case SpvOpFunctionParameter: - if (ir_context->get_def_use_mgr() - ->GetDef(instruction.result_type_id()) - ->opcode() == SpvOpTypePointer) { - transformation_context->GetFactManager() - ->AddFactValueOfPointeeIsIrrelevant(instruction.result_id()); - } - break; - case SpvOpVariable: - transformation_context->GetFactManager() - ->AddFactValueOfPointeeIsIrrelevant(instruction.result_id()); - break; - default: - break; - } - } - - if (message_.is_livesafe()) { - // Make the function livesafe, which also should succeed. - success = TryToMakeFunctionLivesafe(ir_context, *transformation_context); - assert(success && "It should be possible to make the function livesafe."); - (void)(success); // Keep release builds happy. - - // Inform the fact manager that the function is livesafe. - assert(message_.instruction(0).opcode() == SpvOpFunction && - "The first instruction of an 'add function' transformation must be " - "OpFunction."); - transformation_context->GetFactManager()->AddFactFunctionIsLivesafe( - message_.instruction(0).result_id()); - } else { - // Inform the fact manager that all blocks in the function are dead. - for (auto& inst : message_.instruction()) { - if (inst.opcode() == SpvOpLabel) { - transformation_context->GetFactManager()->AddFactBlockIsDead( - inst.result_id()); - } - } - } - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationAddFunction::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_function() = message_; - return result; -} - -bool TransformationAddFunction::TryToAddFunction( - opt::IRContext* ir_context) const { - // This function returns false if |message_.instruction| was not well-formed - // enough to actually create a function and add it to |ir_context|. - - // A function must have at least some instructions. - if (message_.instruction().empty()) { - return false; - } - - // A function must start with OpFunction. - auto function_begin = message_.instruction(0); - if (function_begin.opcode() != SpvOpFunction) { - return false; - } - - // Make a function, headed by the OpFunction instruction. - std::unique_ptr new_function = MakeUnique( - InstructionFromMessage(ir_context, function_begin)); - - // Keeps track of which instruction protobuf message we are currently - // considering. - uint32_t instruction_index = 1; - const auto num_instructions = - static_cast(message_.instruction().size()); - - // Iterate through all function parameter instructions, adding parameters to - // the new function. - while (instruction_index < num_instructions && - message_.instruction(instruction_index).opcode() == - SpvOpFunctionParameter) { - new_function->AddParameter(InstructionFromMessage( - ir_context, message_.instruction(instruction_index))); - instruction_index++; - } - - // After the parameters, there needs to be a label. - if (instruction_index == num_instructions || - message_.instruction(instruction_index).opcode() != SpvOpLabel) { - return false; - } - - // Iterate through the instructions block by block until the end of the - // function is reached. - while (instruction_index < num_instructions && - message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) { - // Invariant: we should always be at a label instruction at this point. - assert(message_.instruction(instruction_index).opcode() == SpvOpLabel); - - // Make a basic block using the label instruction, with the new function - // as its parent. - std::unique_ptr block = - MakeUnique(InstructionFromMessage( - ir_context, message_.instruction(instruction_index))); - block->SetParent(new_function.get()); - - // Consider successive instructions until we hit another label or the end - // of the function, adding each such instruction to the block. - instruction_index++; - while (instruction_index < num_instructions && - message_.instruction(instruction_index).opcode() != - SpvOpFunctionEnd && - message_.instruction(instruction_index).opcode() != SpvOpLabel) { - block->AddInstruction(InstructionFromMessage( - ir_context, message_.instruction(instruction_index))); - instruction_index++; - } - // Add the block to the new function. - new_function->AddBasicBlock(std::move(block)); - } - // Having considered all the blocks, we should be at the last instruction and - // it needs to be OpFunctionEnd. - if (instruction_index != num_instructions - 1 || - message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) { - return false; - } - // Set the function's final instruction, add the function to the module and - // report success. - new_function->SetFunctionEnd(InstructionFromMessage( - ir_context, message_.instruction(instruction_index))); - ir_context->AddFunction(std::move(new_function)); - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - - return true; -} - -bool TransformationAddFunction::TryToMakeFunctionLivesafe( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - assert(message_.is_livesafe() && "Precondition: is_livesafe must hold."); - - // Get a pointer to the added function. - opt::Function* added_function = nullptr; - for (auto& function : *ir_context->module()) { - if (function.result_id() == message_.instruction(0).result_id()) { - added_function = &function; - break; - } - } - assert(added_function && "The added function should have been found."); - - if (!TryToAddLoopLimiters(ir_context, added_function)) { - // Adding loop limiters did not work; bail out. - return false; - } - - // Consider all the instructions in the function, and: - // - attempt to replace OpKill and OpUnreachable with return instructions - // - attempt to clamp access chains to be within bounds - // - check that OpFunctionCall instructions are only to livesafe functions - for (auto& block : *added_function) { - for (auto& inst : block) { - switch (inst.opcode()) { - case SpvOpKill: - case SpvOpUnreachable: - if (!TryToTurnKillOrUnreachableIntoReturn(ir_context, added_function, - &inst)) { - return false; - } - break; - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - if (!TryToClampAccessChainIndices(ir_context, &inst)) { - return false; - } - break; - case SpvOpFunctionCall: - // A livesafe function my only call other livesafe functions. - if (!transformation_context.GetFactManager()->FunctionIsLivesafe( - inst.GetSingleWordInOperand(0))) { - return false; - } - default: - break; - } - } - } - return true; -} - -uint32_t TransformationAddFunction::GetBackEdgeBlockId( - opt::IRContext* ir_context, uint32_t loop_header_block_id) { - const auto* loop_header_block = - ir_context->cfg()->block(loop_header_block_id); - assert(loop_header_block && "|loop_header_block_id| is invalid"); - - for (auto pred : ir_context->cfg()->preds(loop_header_block_id)) { - if (ir_context->GetDominatorAnalysis(loop_header_block->GetParent()) - ->Dominates(loop_header_block_id, pred)) { - return pred; - } - } - - return 0; -} - -bool TransformationAddFunction::TryToAddLoopLimiters( - opt::IRContext* ir_context, opt::Function* added_function) const { - // Collect up all the loop headers so that we can subsequently add loop - // limiting logic. - std::vector loop_headers; - for (auto& block : *added_function) { - if (block.IsLoopHeader()) { - loop_headers.push_back(&block); - } - } - - if (loop_headers.empty()) { - // There are no loops, so no need to add any loop limiters. - return true; - } - - // Check that the module contains appropriate ingredients for declaring and - // manipulating a loop limiter. - - auto loop_limit_constant_id_instr = - ir_context->get_def_use_mgr()->GetDef(message_.loop_limit_constant_id()); - if (!loop_limit_constant_id_instr || - loop_limit_constant_id_instr->opcode() != SpvOpConstant) { - // The loop limit constant id instruction must exist and have an - // appropriate opcode. - return false; - } - - auto loop_limit_type = ir_context->get_def_use_mgr()->GetDef( - loop_limit_constant_id_instr->type_id()); - if (loop_limit_type->opcode() != SpvOpTypeInt || - loop_limit_type->GetSingleWordInOperand(0) != 32) { - // The type of the loop limit constant must be 32-bit integer. It - // doesn't actually matter whether the integer is signed or not. - return false; - } - - // Find the id of the "unsigned int" type. - opt::analysis::Integer unsigned_int_type(32, false); - uint32_t unsigned_int_type_id = - ir_context->get_type_mgr()->GetId(&unsigned_int_type); - if (!unsigned_int_type_id) { - // Unsigned int is not available; we need this type in order to add loop - // limiters. - return false; - } - auto registered_unsigned_int_type = - ir_context->get_type_mgr()->GetRegisteredType(&unsigned_int_type); - - // Look for 0 of type unsigned int. - opt::analysis::IntConstant zero(registered_unsigned_int_type->AsInteger(), - {0}); - auto registered_zero = ir_context->get_constant_mgr()->FindConstant(&zero); - if (!registered_zero) { - // We need 0 in order to be able to initialize loop limiters. - return false; - } - uint32_t zero_id = ir_context->get_constant_mgr() - ->GetDefiningInstruction(registered_zero) - ->result_id(); - - // Look for 1 of type unsigned int. - opt::analysis::IntConstant one(registered_unsigned_int_type->AsInteger(), - {1}); - auto registered_one = ir_context->get_constant_mgr()->FindConstant(&one); - if (!registered_one) { - // We need 1 in order to be able to increment loop limiters. - return false; - } - uint32_t one_id = ir_context->get_constant_mgr() - ->GetDefiningInstruction(registered_one) - ->result_id(); - - // Look for pointer-to-unsigned int type. - opt::analysis::Pointer pointer_to_unsigned_int_type( - registered_unsigned_int_type, SpvStorageClassFunction); - uint32_t pointer_to_unsigned_int_type_id = - ir_context->get_type_mgr()->GetId(&pointer_to_unsigned_int_type); - if (!pointer_to_unsigned_int_type_id) { - // We need pointer-to-unsigned int in order to declare the loop limiter - // variable. - return false; - } - - // Look for bool type. - opt::analysis::Bool bool_type; - uint32_t bool_type_id = ir_context->get_type_mgr()->GetId(&bool_type); - if (!bool_type_id) { - // We need bool in order to compare the loop limiter's value with the loop - // limit constant. - return false; - } - - // Declare the loop limiter variable at the start of the function's entry - // block, via an instruction of the form: - // %loop_limiter_var = SpvOpVariable %ptr_to_uint Function %zero - added_function->begin()->begin()->InsertBefore(MakeUnique( - ir_context, SpvOpVariable, pointer_to_unsigned_int_type_id, - message_.loop_limiter_variable_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}, - {SPV_OPERAND_TYPE_ID, {zero_id}}}))); - // Update the module's id bound since we have added the loop limiter - // variable id. - fuzzerutil::UpdateModuleIdBound(ir_context, - message_.loop_limiter_variable_id()); - - // Consider each loop in turn. - for (auto loop_header : loop_headers) { - // Look for the loop's back-edge block. This is a predecessor of the loop - // header that is dominated by the loop header. - const auto back_edge_block_id = - GetBackEdgeBlockId(ir_context, loop_header->id()); - if (!back_edge_block_id) { - // The loop's back-edge block must be unreachable. This means that the - // loop cannot iterate, so there is no need to make it lifesafe; we can - // move on from this loop. - continue; - } - - // If the loop's merge block is unreachable, then there are no constraints - // on where the merge block appears in relation to the blocks of the loop. - // This means we need to be careful when adding a branch from the back-edge - // block to the merge block: the branch might make the loop merge reachable, - // and it might then be dominated by the loop header and possibly by other - // blocks in the loop. Since a block needs to appear before those blocks it - // strictly dominates, this could make the module invalid. To avoid this - // problem we bail out in the case where the loop header does not dominate - // the loop merge. - if (!ir_context->GetDominatorAnalysis(added_function) - ->Dominates(loop_header->id(), loop_header->MergeBlockId())) { - return false; - } - - // Go through the sequence of loop limiter infos and find the one - // corresponding to this loop. - bool found = false; - protobufs::LoopLimiterInfo loop_limiter_info; - for (auto& info : message_.loop_limiter_info()) { - if (info.loop_header_id() == loop_header->id()) { - loop_limiter_info = info; - found = true; - break; - } - } - if (!found) { - // We don't have loop limiter info for this loop header. - return false; - } - - // The back-edge block either has the form: - // - // (1) - // - // %l = OpLabel - // ... instructions ... - // OpBranch %loop_header - // - // (2) - // - // %l = OpLabel - // ... instructions ... - // OpBranchConditional %c %loop_header %loop_merge - // - // (3) - // - // %l = OpLabel - // ... instructions ... - // OpBranchConditional %c %loop_merge %loop_header - // - // We turn these into the following: - // - // (1) - // - // %l = OpLabel - // ... instructions ... - // %t1 = OpLoad %uint32 %loop_limiter - // %t2 = OpIAdd %uint32 %t1 %one - // OpStore %loop_limiter %t2 - // %t3 = OpUGreaterThanEqual %bool %t1 %loop_limit - // OpBranchConditional %t3 %loop_merge %loop_header - // - // (2) - // - // %l = OpLabel - // ... instructions ... - // %t1 = OpLoad %uint32 %loop_limiter - // %t2 = OpIAdd %uint32 %t1 %one - // OpStore %loop_limiter %t2 - // %t3 = OpULessThan %bool %t1 %loop_limit - // %t4 = OpLogicalAnd %bool %c %t3 - // OpBranchConditional %t4 %loop_header %loop_merge - // - // (3) - // - // %l = OpLabel - // ... instructions ... - // %t1 = OpLoad %uint32 %loop_limiter - // %t2 = OpIAdd %uint32 %t1 %one - // OpStore %loop_limiter %t2 - // %t3 = OpUGreaterThanEqual %bool %t1 %loop_limit - // %t4 = OpLogicalOr %bool %c %t3 - // OpBranchConditional %t4 %loop_merge %loop_header - - auto back_edge_block = ir_context->cfg()->block(back_edge_block_id); - auto back_edge_block_terminator = back_edge_block->terminator(); - bool compare_using_greater_than_equal; - if (back_edge_block_terminator->opcode() == SpvOpBranch) { - compare_using_greater_than_equal = true; - } else { - assert(back_edge_block_terminator->opcode() == SpvOpBranchConditional); - assert(((back_edge_block_terminator->GetSingleWordInOperand(1) == - loop_header->id() && - back_edge_block_terminator->GetSingleWordInOperand(2) == - loop_header->MergeBlockId()) || - (back_edge_block_terminator->GetSingleWordInOperand(2) == - loop_header->id() && - back_edge_block_terminator->GetSingleWordInOperand(1) == - loop_header->MergeBlockId())) && - "A back edge edge block must branch to" - " either the loop header or merge"); - compare_using_greater_than_equal = - back_edge_block_terminator->GetSingleWordInOperand(1) == - loop_header->MergeBlockId(); - } - - std::vector> new_instructions; - - // Add a load from the loop limiter variable, of the form: - // %t1 = OpLoad %uint32 %loop_limiter - new_instructions.push_back(MakeUnique( - ir_context, SpvOpLoad, unsigned_int_type_id, - loop_limiter_info.load_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}}))); - - // Increment the loaded value: - // %t2 = OpIAdd %uint32 %t1 %one - new_instructions.push_back(MakeUnique( - ir_context, SpvOpIAdd, unsigned_int_type_id, - loop_limiter_info.increment_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}}, - {SPV_OPERAND_TYPE_ID, {one_id}}}))); - - // Store the incremented value back to the loop limiter variable: - // OpStore %loop_limiter %t2 - new_instructions.push_back(MakeUnique( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}, - {SPV_OPERAND_TYPE_ID, {loop_limiter_info.increment_id()}}}))); - - // Compare the loaded value with the loop limit; either: - // %t3 = OpUGreaterThanEqual %bool %t1 %loop_limit - // or - // %t3 = OpULessThan %bool %t1 %loop_limit - new_instructions.push_back(MakeUnique( - ir_context, - compare_using_greater_than_equal ? SpvOpUGreaterThanEqual - : SpvOpULessThan, - bool_type_id, loop_limiter_info.compare_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.loop_limit_constant_id()}}}))); - - if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) { - new_instructions.push_back(MakeUnique( - ir_context, - compare_using_greater_than_equal ? SpvOpLogicalOr : SpvOpLogicalAnd, - bool_type_id, loop_limiter_info.logical_op_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, - {back_edge_block_terminator->GetSingleWordInOperand(0)}}, - {SPV_OPERAND_TYPE_ID, {loop_limiter_info.compare_id()}}}))); - } - - // Add the new instructions at the end of the back edge block, before the - // terminator and any loop merge instruction (as the back edge block can - // be the loop header). - if (back_edge_block->GetLoopMergeInst()) { - back_edge_block->GetLoopMergeInst()->InsertBefore( - std::move(new_instructions)); - } else { - back_edge_block_terminator->InsertBefore(std::move(new_instructions)); - } - - if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) { - back_edge_block_terminator->SetInOperand( - 0, {loop_limiter_info.logical_op_id()}); - } else { - assert(back_edge_block_terminator->opcode() == SpvOpBranch && - "Back-edge terminator must be OpBranch or OpBranchConditional"); - - // Check that, if the merge block starts with OpPhi instructions, suitable - // ids have been provided to give these instructions a value corresponding - // to the new incoming edge from the back edge block. - auto merge_block = ir_context->cfg()->block(loop_header->MergeBlockId()); - if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, back_edge_block, - merge_block, - loop_limiter_info.phi_id())) { - return false; - } - - // Augment OpPhi instructions at the loop merge with the given ids. - uint32_t phi_index = 0; - for (auto& inst : *merge_block) { - if (inst.opcode() != SpvOpPhi) { - break; - } - assert(phi_index < - static_cast(loop_limiter_info.phi_id().size()) && - "There should be at least one phi id per OpPhi instruction."); - inst.AddOperand( - {SPV_OPERAND_TYPE_ID, {loop_limiter_info.phi_id(phi_index)}}); - inst.AddOperand({SPV_OPERAND_TYPE_ID, {back_edge_block_id}}); - phi_index++; - } - - // Add the new edge, by changing OpBranch to OpBranchConditional. - back_edge_block_terminator->SetOpcode(SpvOpBranchConditional); - back_edge_block_terminator->SetInOperands(opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.compare_id()}}, - {SPV_OPERAND_TYPE_ID, {loop_header->MergeBlockId()}}, - {SPV_OPERAND_TYPE_ID, {loop_header->id()}}})); - } - - // Update the module's id bound with respect to the various ids that - // have been used for loop limiter manipulation. - fuzzerutil::UpdateModuleIdBound(ir_context, loop_limiter_info.load_id()); - fuzzerutil::UpdateModuleIdBound(ir_context, - loop_limiter_info.increment_id()); - fuzzerutil::UpdateModuleIdBound(ir_context, loop_limiter_info.compare_id()); - fuzzerutil::UpdateModuleIdBound(ir_context, - loop_limiter_info.logical_op_id()); - } - return true; -} - -bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn( - opt::IRContext* ir_context, opt::Function* added_function, - opt::Instruction* kill_or_unreachable_inst) const { - assert((kill_or_unreachable_inst->opcode() == SpvOpKill || - kill_or_unreachable_inst->opcode() == SpvOpUnreachable) && - "Precondition: instruction must be OpKill or OpUnreachable."); - - // Get the function's return type. - auto function_return_type_inst = - ir_context->get_def_use_mgr()->GetDef(added_function->type_id()); - - if (function_return_type_inst->opcode() == SpvOpTypeVoid) { - // The function has void return type, so change this instruction to - // OpReturn. - kill_or_unreachable_inst->SetOpcode(SpvOpReturn); - } else { - // The function has non-void return type, so change this instruction - // to OpReturnValue, using the value id provided with the - // transformation. - - // We first check that the id, %id, provided with the transformation - // specifically to turn OpKill and OpUnreachable instructions into - // OpReturnValue %id has the same type as the function's return type. - if (ir_context->get_def_use_mgr() - ->GetDef(message_.kill_unreachable_return_value_id()) - ->type_id() != function_return_type_inst->result_id()) { - return false; - } - kill_or_unreachable_inst->SetOpcode(SpvOpReturnValue); - kill_or_unreachable_inst->SetInOperands( - {{SPV_OPERAND_TYPE_ID, {message_.kill_unreachable_return_value_id()}}}); - } - return true; -} - -bool TransformationAddFunction::TryToClampAccessChainIndices( - opt::IRContext* ir_context, opt::Instruction* access_chain_inst) const { - assert((access_chain_inst->opcode() == SpvOpAccessChain || - access_chain_inst->opcode() == SpvOpInBoundsAccessChain) && - "Precondition: instruction must be OpAccessChain or " - "OpInBoundsAccessChain."); - - // Find the AccessChainClampingInfo associated with this access chain. - const protobufs::AccessChainClampingInfo* access_chain_clamping_info = - nullptr; - for (auto& clamping_info : message_.access_chain_clamping_info()) { - if (clamping_info.access_chain_id() == access_chain_inst->result_id()) { - access_chain_clamping_info = &clamping_info; - break; - } - } - if (!access_chain_clamping_info) { - // No access chain clamping information was found; the function cannot be - // made livesafe. - return false; - } - - // Check that there is a (compare_id, select_id) pair for every - // index associated with the instruction. - if (static_cast( - access_chain_clamping_info->compare_and_select_ids().size()) != - access_chain_inst->NumInOperands() - 1) { - return false; - } - - // Walk the access chain, clamping each index to be within bounds if it is - // not a constant. - auto base_object = ir_context->get_def_use_mgr()->GetDef( - access_chain_inst->GetSingleWordInOperand(0)); - assert(base_object && "The base object must exist."); - auto pointer_type = - ir_context->get_def_use_mgr()->GetDef(base_object->type_id()); - assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer && - "The base object must have pointer type."); - auto should_be_composite_type = ir_context->get_def_use_mgr()->GetDef( - pointer_type->GetSingleWordInOperand(1)); - - // Consider each index input operand in turn (operand 0 is the base object). - for (uint32_t index = 1; index < access_chain_inst->NumInOperands(); - index++) { - // We are going to turn: - // - // %result = OpAccessChain %type %object ... %index ... - // - // into: - // - // %t1 = OpULessThanEqual %bool %index %bound_minus_one - // %t2 = OpSelect %int_type %t1 %index %bound_minus_one - // %result = OpAccessChain %type %object ... %t2 ... - // - // ... unless %index is already a constant. - - // Get the bound for the composite being indexed into; e.g. the number of - // columns of matrix or the size of an array. - uint32_t bound = fuzzerutil::GetBoundForCompositeIndex( - *should_be_composite_type, ir_context); - - // Get the instruction associated with the index and figure out its integer - // type. - const uint32_t index_id = access_chain_inst->GetSingleWordInOperand(index); - auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id); - auto index_type_inst = - ir_context->get_def_use_mgr()->GetDef(index_inst->type_id()); - assert(index_type_inst->opcode() == SpvOpTypeInt); - assert(index_type_inst->GetSingleWordInOperand(0) == 32); - opt::analysis::Integer* index_int_type = - ir_context->get_type_mgr() - ->GetType(index_type_inst->result_id()) - ->AsInteger(); - - if (index_inst->opcode() != SpvOpConstant || - index_inst->GetSingleWordInOperand(0) >= bound) { - // The index is either non-constant or an out-of-bounds constant, so we - // need to clamp it. - assert(should_be_composite_type->opcode() != SpvOpTypeStruct && - "Access chain indices into structures are required to be " - "constants."); - opt::analysis::IntConstant bound_minus_one(index_int_type, {bound - 1}); - if (!ir_context->get_constant_mgr()->FindConstant(&bound_minus_one)) { - // We do not have an integer constant whose value is |bound| -1. - return false; - } - - opt::analysis::Bool bool_type; - uint32_t bool_type_id = ir_context->get_type_mgr()->GetId(&bool_type); - if (!bool_type_id) { - // Bool type is not declared; we cannot do a comparison. - return false; - } - - uint32_t bound_minus_one_id = - ir_context->get_constant_mgr() - ->GetDefiningInstruction(&bound_minus_one) - ->result_id(); - - uint32_t compare_id = - access_chain_clamping_info->compare_and_select_ids(index - 1).first(); - uint32_t select_id = - access_chain_clamping_info->compare_and_select_ids(index - 1) - .second(); - std::vector> new_instructions; - - // Compare the index with the bound via an instruction of the form: - // %t1 = OpULessThanEqual %bool %index %bound_minus_one - new_instructions.push_back(MakeUnique( - ir_context, SpvOpULessThanEqual, bool_type_id, compare_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}}, - {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); - - // Select the index if in-bounds, otherwise one less than the bound: - // %t2 = OpSelect %int_type %t1 %index %bound_minus_one - new_instructions.push_back(MakeUnique( - ir_context, SpvOpSelect, index_type_inst->result_id(), select_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {compare_id}}, - {SPV_OPERAND_TYPE_ID, {index_inst->result_id()}}, - {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); - - // Add the new instructions before the access chain - access_chain_inst->InsertBefore(std::move(new_instructions)); - - // Replace %index with %t2. - access_chain_inst->SetInOperand(index, {select_id}); - fuzzerutil::UpdateModuleIdBound(ir_context, compare_id); - fuzzerutil::UpdateModuleIdBound(ir_context, select_id); - } - should_be_composite_type = - FollowCompositeIndex(ir_context, *should_be_composite_type, index_id); - } - return true; -} - -opt::Instruction* TransformationAddFunction::FollowCompositeIndex( - opt::IRContext* ir_context, const opt::Instruction& composite_type_inst, - uint32_t index_id) { - uint32_t sub_object_type_id; - switch (composite_type_inst.opcode()) { - case SpvOpTypeArray: - case SpvOpTypeRuntimeArray: - sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0); - break; - case SpvOpTypeMatrix: - case SpvOpTypeVector: - sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0); - break; - case SpvOpTypeStruct: { - auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id); - assert(index_inst->opcode() == SpvOpConstant); - assert(ir_context->get_def_use_mgr() - ->GetDef(index_inst->type_id()) - ->opcode() == SpvOpTypeInt); - assert(ir_context->get_def_use_mgr() - ->GetDef(index_inst->type_id()) - ->GetSingleWordInOperand(0) == 32); - uint32_t index_value = index_inst->GetSingleWordInOperand(0); - sub_object_type_id = - composite_type_inst.GetSingleWordInOperand(index_value); - break; - } - default: - assert(false && "Unknown composite type."); - sub_object_type_id = 0; - break; - } - assert(sub_object_type_id && "No sub-object found."); - return ir_context->get_def_use_mgr()->GetDef(sub_object_type_id); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_function.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_function.h deleted file mode 100644 index 4ebf171c8..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_function.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_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 TransformationAddFunction : public Transformation { - public: - explicit TransformationAddFunction( - const protobufs::TransformationAddFunction& message); - - // Creates a transformation to add a non live-safe function. - explicit TransformationAddFunction( - const std::vector& instructions); - - // Creates a transformation to add a live-safe function. - TransformationAddFunction( - const std::vector& instructions, - uint32_t loop_limiter_variable_id, uint32_t loop_limit_constant_id, - const std::vector& loop_limiters, - uint32_t kill_unreachable_return_value_id, - const std::vector& - access_chain_clampers); - - // - |message_.instruction| must correspond to a sufficiently well-formed - // sequence of instructions that a function can be created from them - // - If |message_.is_livesafe| holds then |message_| must contain suitable - // ingredients to make the function livesafe, and the function must only - // invoke other livesafe functions - // - Adding the created function to the module must lead to a valid module. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds the function defined by |message_.instruction| to the module, making - // it livesafe if |message_.is_livesafe| holds. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Helper method that, given composite type |composite_type_inst|, returns the - // type of the sub-object at index |index_id|, which is required to be in- - // bounds. - static opt::Instruction* FollowCompositeIndex( - opt::IRContext* ir_context, const opt::Instruction& composite_type_inst, - uint32_t index_id); - - // Returns id of the back-edge block, given the corresponding - // |loop_header_block_id|. |loop_header_block_id| must be the id of a loop - // header block. Returns 0 if the loop has no back-edge block. - static uint32_t GetBackEdgeBlockId(opt::IRContext* ir_context, - uint32_t loop_header_block_id); - - private: - // Attempts to create a function from the series of instructions in - // |message_.instruction| and add it to |ir_context|. - // - // Returns false if adding the function is not possible due to the messages - // not respecting the basic structure of a function, e.g. if there is no - // OpFunction instruction or no blocks; in this case |ir_context| is left in - // an indeterminate state. - // - // Otherwise returns true. Whether |ir_context| is valid after addition of - // the function depends on the contents of |message_.instruction|. - // - // Intended usage: - // - Perform a dry run of this method on a clone of a module, and use - // the validator to check whether the resulting module is valid. Working - // on a clone means it does not matter if the function fails to be cleanly - // added, or leads to an invalid module. - // - If the dry run succeeds, run the method on the real module of interest, - // to add the function. - bool TryToAddFunction(opt::IRContext* ir_context) const; - - // Should only be called if |message_.is_livesafe| holds. Attempts to make - // the function livesafe (see FactFunctionIsLivesafe for a definition). - // Returns false if this is not possible, due to |message_| or |ir_context| - // not containing sufficient ingredients (such as types and fresh ids) to add - // the instrumentation necessary to make the function livesafe. - bool TryToMakeFunctionLivesafe( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const; - - // A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting - // logic. - bool TryToAddLoopLimiters(opt::IRContext* ir_context, - opt::Function* added_function) const; - - // A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and - // OpUnreachable instructions into return instructions. - bool TryToTurnKillOrUnreachableIntoReturn( - opt::IRContext* ir_context, opt::Function* added_function, - opt::Instruction* kill_or_unreachable_inst) const; - - // A helper for TryToMakeFunctionLivesafe that tries to clamp access chain - // indices so that they are guaranteed to be in-bounds. - bool TryToClampAccessChainIndices(opt::IRContext* ir_context, - opt::Instruction* access_chain_inst) const; - - protobufs::TransformationAddFunction message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_undef.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_global_undef.cpp deleted file mode 100644 index ba45f220a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_undef.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_global_undef.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddGlobalUndef::TransformationAddGlobalUndef( - const spvtools::fuzz::protobufs::TransformationAddGlobalUndef& message) - : message_(message) {} - -TransformationAddGlobalUndef::TransformationAddGlobalUndef(uint32_t fresh_id, - uint32_t type_id) { - message_.set_fresh_id(fresh_id); - message_.set_type_id(type_id); -} - -bool TransformationAddGlobalUndef::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // A fresh id is required. - 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(); -} - -void TransformationAddGlobalUndef::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - ir_context->module()->AddGlobalValue(MakeUnique( - ir_context, SpvOpUndef, message_.type_id(), message_.fresh_id(), - opt::Instruction::OperandList())); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddGlobalUndef::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_global_undef() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_undef.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_global_undef.h deleted file mode 100644 index c89fe9d5c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_undef.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_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 TransformationAddGlobalUndef : public Transformation { - public: - explicit TransformationAddGlobalUndef( - const protobufs::TransformationAddGlobalUndef& message); - - 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 - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpUndef instruction to the module, with |message_.type_id| as its - // type. The instruction has result id |message_.fresh_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddGlobalUndef message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.cpp deleted file mode 100644 index 303c4d977..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_global_variable.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddGlobalVariable::TransformationAddGlobalVariable( - const spvtools::fuzz::protobufs::TransformationAddGlobalVariable& message) - : message_(message) {} - -TransformationAddGlobalVariable::TransformationAddGlobalVariable( - uint32_t fresh_id, uint32_t type_id, SpvStorageClass storage_class, - uint32_t initializer_id, bool value_is_irrelevant) { - message_.set_fresh_id(fresh_id); - message_.set_type_id(type_id); - message_.set_storage_class(storage_class); - message_.set_initializer_id(initializer_id); - message_.set_value_is_irrelevant(value_is_irrelevant); -} - -bool TransformationAddGlobalVariable::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The result id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // The storage class must be Private or Workgroup. - auto storage_class = static_cast(message_.storage_class()); - switch (storage_class) { - case SpvStorageClassPrivate: - case SpvStorageClassWorkgroup: - break; - default: - assert(false && "Unsupported storage class."); - return false; - } - // The type id must correspond to a type. - auto type = ir_context->get_type_mgr()->GetType(message_.type_id()); - if (!type) { - return false; - } - // That type must be a pointer type ... - auto pointer_type = type->AsPointer(); - if (!pointer_type) { - return false; - } - // ... with the right storage class. - if (pointer_type->storage_class() != storage_class) { - return false; - } - if (message_.initializer_id()) { - // An initializer is not allowed if the storage class is Workgroup. - if (storage_class == SpvStorageClassWorkgroup) { - assert(false && - "By construction this transformation should not have an " - "initializer when Workgroup storage class is used."); - return false; - } - // The initializer id must be the id of a constant. Check this with the - // constant manager. - auto constant_id = ir_context->get_constant_mgr()->GetConstantsFromIds( - {message_.initializer_id()}); - if (constant_id.empty()) { - return false; - } - assert(constant_id.size() == 1 && - "We asked for the constant associated with a single id; we should " - "get a single constant."); - // The type of the constant must match the pointee type of the pointer. - if (pointer_type->pointee_type() != constant_id[0]->type()) { - return false; - } - } - return true; -} - -void TransformationAddGlobalVariable::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - fuzzerutil::AddGlobalVariable( - ir_context, message_.fresh_id(), message_.type_id(), - static_cast(message_.storage_class()), - message_.initializer_id()); - - if (message_.value_is_irrelevant()) { - transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( - message_.fresh_id()); - } - - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_global_variable() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.h deleted file mode 100644 index 89bd044fd..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_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 TransformationAddGlobalVariable : public Transformation { - public: - explicit TransformationAddGlobalVariable( - const protobufs::TransformationAddGlobalVariable& message); - - TransformationAddGlobalVariable(uint32_t fresh_id, uint32_t type_id, - SpvStorageClass storage_class, - uint32_t initializer_id, - bool value_is_irrelevant); - - // - |message_.fresh_id| must be fresh - // - |message_.type_id| must be the id of a pointer type with the same storage - // class as |message_.storage_class| - // - |message_.storage_class| must be Private or Workgroup - // - |message_.initializer_id| must be 0 if |message_.storage_class| is - // Workgroup, and otherwise may either be 0 or the id of a constant whose - // type is the pointee type of |message_.type_id| - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds a global variable with storage class |message_.storage_class| to the - // module, with type |message_.type_id| and either no initializer or - // |message_.initializer_id| as an initializer, depending on whether - // |message_.initializer_id| is 0. The global variable has result id - // |message_.fresh_id|. - // - // If |message_.value_is_irrelevant| holds, adds a corresponding fact to the - // fact manager in |transformation_context|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddGlobalVariable message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.cpp deleted file mode 100644 index 1be1d4378..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_image_sample_unused_components.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddImageSampleUnusedComponents:: - TransformationAddImageSampleUnusedComponents( - const spvtools::fuzz::protobufs:: - TransformationAddImageSampleUnusedComponents& message) - : message_(message) {} - -TransformationAddImageSampleUnusedComponents:: - TransformationAddImageSampleUnusedComponents( - uint32_t coordinate_with_unused_components_id, - const protobufs::InstructionDescriptor& instruction_descriptor) { - message_.set_coordinate_with_unused_components_id( - coordinate_with_unused_components_id); - *message_.mutable_instruction_descriptor() = instruction_descriptor; -} - -bool TransformationAddImageSampleUnusedComponents::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - auto image_sample_instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - - // The image sample instruction must be defined. - if (image_sample_instruction == nullptr) { - return false; - } - - // The instruction must be an image sample instruction. - if (!spvOpcodeIsImageSample(image_sample_instruction->opcode())) { - return false; - } - - uint32_t coordinate_id = image_sample_instruction->GetSingleWordInOperand(1); - auto coordinate_instruction = - ir_context->get_def_use_mgr()->GetDef(coordinate_id); - auto coordinate_type = - ir_context->get_type_mgr()->GetType(coordinate_instruction->type_id()); - - // It must be possible to add unused components. - if (coordinate_type->AsVector() && - coordinate_type->AsVector()->element_count() == 4) { - return false; - } - - auto coordinate_with_unused_components_instruction = - ir_context->get_def_use_mgr()->GetDef( - message_.coordinate_with_unused_components_id()); - - // The coordinate with unused components instruction must be defined. - if (coordinate_with_unused_components_instruction == nullptr) { - return false; - } - - // It must be an OpCompositeConstruct instruction such that it can be checked - // that the original components are present. - if (coordinate_with_unused_components_instruction->opcode() != - SpvOpCompositeConstruct) { - return false; - } - - // The first constituent must be the original coordinate. - if (coordinate_with_unused_components_instruction->GetSingleWordInOperand( - 0) != coordinate_id) { - return false; - } - - auto coordinate_with_unused_components_type = - ir_context->get_type_mgr()->GetType( - coordinate_with_unused_components_instruction->type_id()); - - // |coordinate_with_unused_components_type| must be a vector. - if (!coordinate_with_unused_components_type->AsVector()) { - return false; - } - - return true; -} - -void TransformationAddImageSampleUnusedComponents::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Sets the coordinate operand. - auto image_sample_instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - image_sample_instruction->SetInOperand( - 1, {message_.coordinate_with_unused_components_id()}); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation -TransformationAddImageSampleUnusedComponents::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_image_sample_unused_components() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.h deleted file mode 100644 index 749348121..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_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 TransformationAddImageSampleUnusedComponents : public Transformation { - public: - explicit TransformationAddImageSampleUnusedComponents( - const protobufs::TransformationAddImageSampleUnusedComponents& message); - - TransformationAddImageSampleUnusedComponents( - uint32_t coordinate_with_unused_components_id, - const protobufs::InstructionDescriptor& instruction_descriptor); - - // - |coordinate_with_unused_components_id| must identify a vector such that - // the first components match the components of the image sample coordinate. - // - |message_.instruction_descriptor| must identify an image sample - // instruction - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Add unused components to an image sample coordinate by replacing the - // coordinate with |coordinate_with_unused_components_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddImageSampleUnusedComponents message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.cpp deleted file mode 100644 index a6b31b491..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_local_variable.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddLocalVariable::TransformationAddLocalVariable( - const spvtools::fuzz::protobufs::TransformationAddLocalVariable& message) - : message_(message) {} - -TransformationAddLocalVariable::TransformationAddLocalVariable( - uint32_t fresh_id, uint32_t type_id, uint32_t function_id, - uint32_t initializer_id, bool value_is_irrelevant) { - message_.set_fresh_id(fresh_id); - message_.set_type_id(type_id); - message_.set_function_id(function_id); - message_.set_initializer_id(initializer_id); - message_.set_value_is_irrelevant(value_is_irrelevant); -} - -bool TransformationAddLocalVariable::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The provided id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // The pointer type id must indeed correspond to a pointer, and it must have - // function storage class. - auto type_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.type_id()); - if (!type_instruction || type_instruction->opcode() != SpvOpTypePointer || - type_instruction->GetSingleWordInOperand(0) != SpvStorageClassFunction) { - return false; - } - // The initializer must... - auto initializer_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.initializer_id()); - // ... exist, ... - if (!initializer_instruction) { - return false; - } - // ... be a constant, ... - if (!spvOpcodeIsConstant(initializer_instruction->opcode())) { - return false; - } - // ... and have the same type as the pointee type. - if (initializer_instruction->type_id() != - type_instruction->GetSingleWordInOperand(1)) { - return false; - } - // The function to which the local variable is to be added must exist. - return fuzzerutil::FindFunction(ir_context, message_.function_id()); -} - -void TransformationAddLocalVariable::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - fuzzerutil::AddLocalVariable(ir_context, message_.fresh_id(), - message_.type_id(), message_.function_id(), - message_.initializer_id()); - - if (message_.value_is_irrelevant()) { - transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( - message_.fresh_id()); - } - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationAddLocalVariable::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_local_variable() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.h deleted file mode 100644 index 646090412..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_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 TransformationAddLocalVariable : public Transformation { - public: - explicit TransformationAddLocalVariable( - const protobufs::TransformationAddLocalVariable& message); - - TransformationAddLocalVariable(uint32_t fresh_id, uint32_t type_id, - uint32_t function_id, uint32_t initializer_id, - bool value_is_irrelevant); - - // - |message_.fresh_id| must not be used by the module - // - |message_.type_id| must be the id of a pointer type with Function - // storage class - // - |message_.initializer_id| must be the id of a constant with the same - // type as the pointer's pointee type - // - |message_.function_id| must be the id of a function - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an instruction to the start of |message_.function_id|, of the form: - // |message_.fresh_id| = OpVariable |message_.type_id| Function - // |message_.initializer_id| - // If |message_.value_is_irrelevant| holds, adds a corresponding fact to the - // fact manager in |transformation_context|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddLocalVariable message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_loop_preheader.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_loop_preheader.cpp deleted file mode 100644 index eec71da49..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_loop_preheader.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) 2020 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 "transformation_add_loop_preheader.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/opt/instruction.h" - -namespace spvtools { -namespace fuzz { -TransformationAddLoopPreheader::TransformationAddLoopPreheader( - const protobufs::TransformationAddLoopPreheader& message) - : message_(message) {} - -TransformationAddLoopPreheader::TransformationAddLoopPreheader( - uint32_t loop_header_block, uint32_t fresh_id, - std::vector phi_id) { - message_.set_loop_header_block(loop_header_block); - message_.set_fresh_id(fresh_id); - for (auto id : phi_id) { - message_.add_phi_id(id); - } -} - -bool TransformationAddLoopPreheader::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& /* unused */) const { - // |message_.loop_header_block()| must be the id of a loop header block. - opt::BasicBlock* loop_header_block = - fuzzerutil::MaybeFindBlock(ir_context, message_.loop_header_block()); - if (!loop_header_block || !loop_header_block->IsLoopHeader()) { - return false; - } - - // The id for the preheader must actually be fresh. - std::set used_ids; - if (!CheckIdIsFreshAndNotUsedByThisTransformation(message_.fresh_id(), - ir_context, &used_ids)) { - return false; - } - - size_t num_predecessors = - ir_context->cfg()->preds(message_.loop_header_block()).size(); - - // The block must have at least 2 predecessors (the back-edge block and - // another predecessor outside of the loop) - if (num_predecessors < 2) { - return false; - } - - // If the block only has one predecessor outside of the loop (and thus 2 in - // total), then no additional fresh ids are necessary. - if (num_predecessors == 2) { - return true; - } - - // Count the number of OpPhi instructions. - int32_t num_phi_insts = 0; - loop_header_block->ForEachPhiInst( - [&num_phi_insts](opt::Instruction* /* unused */) { num_phi_insts++; }); - - // There must be enough fresh ids for the OpPhi instructions. - if (num_phi_insts > message_.phi_id_size()) { - return false; - } - - // Check that the needed ids are fresh and distinct. - for (int32_t i = 0; i < num_phi_insts; i++) { - if (!CheckIdIsFreshAndNotUsedByThisTransformation(message_.phi_id(i), - ir_context, &used_ids)) { - return false; - } - } - - return true; -} - -void TransformationAddLoopPreheader::Apply( - opt::IRContext* ir_context, - TransformationContext* /* transformation_context */) const { - // Find the loop header. - opt::BasicBlock* loop_header = - fuzzerutil::MaybeFindBlock(ir_context, message_.loop_header_block()); - - auto dominator_analysis = - ir_context->GetDominatorAnalysis(loop_header->GetParent()); - - uint32_t back_edge_block_id = 0; - - // Update the branching instructions of the out-of-loop predecessors of the - // header. Set |back_edge_block_id| to be the id of the back-edge block. - ir_context->get_def_use_mgr()->ForEachUse( - loop_header->id(), - [this, &ir_context, &dominator_analysis, &loop_header, - &back_edge_block_id](opt::Instruction* use_inst, uint32_t use_index) { - - if (dominator_analysis->Dominates(loop_header->GetLabelInst(), - use_inst)) { - // If |use_inst| is a branch instruction dominated by the header, the - // block containing it is the back-edge block. - if (use_inst->IsBranch()) { - assert(back_edge_block_id == 0 && - "There should only be one back-edge block"); - back_edge_block_id = ir_context->get_instr_block(use_inst)->id(); - } - // References to the header inside the loop should not be updated - return; - } - - // If |use_inst| is not a branch or merge instruction, it should not be - // changed. - if (!use_inst->IsBranch() && - use_inst->opcode() != SpvOpSelectionMerge && - use_inst->opcode() != SpvOpLoopMerge) { - return; - } - - // Update the reference. - use_inst->SetOperand(use_index, {message_.fresh_id()}); - }); - - assert(back_edge_block_id && "The back-edge block should have been found"); - - // Make a new block for the preheader. - std::unique_ptr preheader = MakeUnique( - std::unique_ptr(new opt::Instruction( - ir_context, SpvOpLabel, 0, message_.fresh_id(), {}))); - - uint32_t phi_ids_used = 0; - - // Update the OpPhi instructions and, if there is more than one out-of-loop - // predecessor, add necessary OpPhi instructions so the preheader. - loop_header->ForEachPhiInst([this, &ir_context, &preheader, - &back_edge_block_id, - &phi_ids_used](opt::Instruction* phi_inst) { - - // The loop header must have at least 2 incoming edges (the back edge, and - // at least one from outside the loop). - assert(phi_inst->NumInOperands() >= 4); - - if (phi_inst->NumInOperands() == 4) { - // There is just one out-of-loop predecessor, so no additional - // instructions in the preheader are necessary. The reference to the - // original out-of-loop predecessor needs to be updated so that it refers - // to the preheader. - uint32_t index_of_out_of_loop_pred_id = - phi_inst->GetInOperand(1).words[0] == back_edge_block_id ? 3 : 1; - phi_inst->SetInOperand(index_of_out_of_loop_pred_id, {preheader->id()}); - } else { - // There is more than one out-of-loop predecessor, so an OpPhi instruction - // needs to be added to the preheader, and its value will depend on all - // the current out-of-loop predecessors of the header. - - // Get the operand list and the value corresponding to the back-edge - // block. - std::vector preheader_in_operands; - uint32_t back_edge_val = 0; - - for (uint32_t i = 0; i < phi_inst->NumInOperands(); i += 2) { - // Only add operands if they don't refer to the back-edge block. - if (phi_inst->GetInOperand(i + 1).words[0] == back_edge_block_id) { - back_edge_val = phi_inst->GetInOperand(i).words[0]; - } else { - preheader_in_operands.push_back(std::move(phi_inst->GetInOperand(i))); - preheader_in_operands.push_back( - std::move(phi_inst->GetInOperand(i + 1))); - } - } - - // Add the new instruction to the preheader. - uint32_t fresh_phi_id = message_.phi_id(phi_ids_used++); - - // Update id bound. - fuzzerutil::UpdateModuleIdBound(ir_context, fresh_phi_id); - - preheader->AddInstruction(std::unique_ptr( - new opt::Instruction(ir_context, SpvOpPhi, phi_inst->type_id(), - fresh_phi_id, preheader_in_operands))); - - // Update the OpPhi instruction in the header so that it refers to the - // back edge block and the preheader as the predecessors, and it uses the - // newly-defined OpPhi in the preheader for the corresponding value. - phi_inst->SetInOperands( - {{SPV_OPERAND_TYPE_RESULT_ID, {fresh_phi_id}}, - {SPV_OPERAND_TYPE_RESULT_ID, {preheader->id()}}, - {SPV_OPERAND_TYPE_RESULT_ID, {back_edge_val}}, - {SPV_OPERAND_TYPE_RESULT_ID, {back_edge_block_id}}}); - } - }); - - // Update id bound. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // Add an unconditional branch from the preheader to the header. - preheader->AddInstruction(std::unique_ptr( - new opt::Instruction(ir_context, SpvOpBranch, 0, 0, - std::initializer_list{opt::Operand( - spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID, - {loop_header->id()})}))); - - // Insert the preheader in the module. - loop_header->GetParent()->InsertBasicBlockBefore(std::move(preheader), - loop_header); - - // Invalidate analyses because the structure of the program changed. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationAddLoopPreheader::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_loop_preheader() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_loop_preheader.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_loop_preheader.h deleted file mode 100644 index 2143e3f7f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_loop_preheader.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_LOOP_PREHEADER_H -#define SOURCE_FUZZ_TRANSFORMATION_ADD_LOOP_PREHEADER_H - -#include "source/fuzz/transformation.h" - -namespace spvtools { -namespace fuzz { - -class TransformationAddLoopPreheader : public Transformation { - public: - explicit TransformationAddLoopPreheader( - const protobufs::TransformationAddLoopPreheader& message); - - TransformationAddLoopPreheader(uint32_t loop_header_block, uint32_t fresh_id, - std::vector phi_id); - - // - |message_.loop_header_block| must be the id of a loop header block in - // the given module. - // - |message_.fresh_id| must be an available id. - // - |message_.phi_ids| must be a list of available ids. - // It can be empty if the loop header only has one predecessor outside of - // the loop. Otherwise, it must contain at least as many ids as OpPhi - // instructions in the loop header block. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds a preheader block as the unique out-of-loop predecessor of the given - // loop header block. All of the existing out-of-loop predecessors of the - // header are changed so that they branch to the preheader instead. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddLoopPreheader message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_LOOP_PREHEADER_H diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.cpp deleted file mode 100644 index 4668534b6..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_no_contraction_decoration.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddNoContractionDecoration:: - TransformationAddNoContractionDecoration( - const spvtools::fuzz::protobufs:: - TransformationAddNoContractionDecoration& message) - : message_(message) {} - -TransformationAddNoContractionDecoration:: - TransformationAddNoContractionDecoration(uint32_t result_id) { - message_.set_result_id(result_id); -} - -bool TransformationAddNoContractionDecoration::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |message_.result_id| must be the id of an instruction. - auto instr = ir_context->get_def_use_mgr()->GetDef(message_.result_id()); - if (!instr) { - return false; - } - // The instruction must be arithmetic. - return IsArithmetic(instr->opcode()); -} - -void TransformationAddNoContractionDecoration::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Add a NoContraction decoration targeting |message_.result_id|. - ir_context->get_decoration_mgr()->AddDecoration(message_.result_id(), - SpvDecorationNoContraction); -} - -protobufs::Transformation TransformationAddNoContractionDecoration::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_add_no_contraction_decoration() = message_; - return result; -} - -bool TransformationAddNoContractionDecoration::IsArithmetic(uint32_t opcode) { - switch (opcode) { - case SpvOpSNegate: - case SpvOpFNegate: - case SpvOpIAdd: - case SpvOpFAdd: - case SpvOpISub: - case SpvOpFSub: - case SpvOpIMul: - case SpvOpFMul: - case SpvOpUDiv: - case SpvOpSDiv: - case SpvOpFDiv: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSMod: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpVectorTimesScalar: - case SpvOpMatrixTimesScalar: - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - case SpvOpOuterProduct: - case SpvOpDot: - case SpvOpIAddCarry: - case SpvOpISubBorrow: - case SpvOpUMulExtended: - case SpvOpSMulExtended: - case SpvOpAny: - case SpvOpAll: - case SpvOpIsNan: - case SpvOpIsInf: - case SpvOpIsFinite: - case SpvOpIsNormal: - case SpvOpSignBitSet: - case SpvOpLessOrGreater: - case SpvOpOrdered: - case SpvOpUnordered: - case SpvOpLogicalEqual: - case SpvOpLogicalNotEqual: - case SpvOpLogicalOr: - case SpvOpLogicalAnd: - case SpvOpLogicalNot: - return true; - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.h deleted file mode 100644 index 27c3a8021..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_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 TransformationAddNoContractionDecoration : public Transformation { - public: - explicit TransformationAddNoContractionDecoration( - const protobufs::TransformationAddNoContractionDecoration& message); - - explicit TransformationAddNoContractionDecoration(uint32_t fresh_id); - - // - |message_.result_id| must be the result id of an arithmetic instruction, - // as defined by the SPIR-V specification. - // - It does not matter whether this instruction is already annotated with the - // NoContraction decoration. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds a decoration of the form: - // 'OpDecoration |message_.result_id| NoContraction' - // to the module. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if and only if |opcode| is the opcode of an arithmetic - // instruction, as defined by the SPIR-V specification. - static bool IsArithmetic(uint32_t opcode); - - private: - protobufs::TransformationAddNoContractionDecoration message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_opphi_synonym.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_opphi_synonym.cpp deleted file mode 100644 index 3436dd7e2..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_opphi_synonym.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_opphi_synonym.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { -TransformationAddOpPhiSynonym::TransformationAddOpPhiSynonym( - const protobufs::TransformationAddOpPhiSynonym& message) - : message_(message) {} - -TransformationAddOpPhiSynonym::TransformationAddOpPhiSynonym( - uint32_t block_id, const std::map& preds_to_ids, - uint32_t fresh_id) { - message_.set_block_id(block_id); - *message_.mutable_pred_to_id() = - fuzzerutil::MapToRepeatedUInt32Pair(preds_to_ids); - message_.set_fresh_id(fresh_id); -} - -bool TransformationAddOpPhiSynonym::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // Check that |message_.block_id| is a block label id. - auto block = fuzzerutil::MaybeFindBlock(ir_context, message_.block_id()); - if (!block) { - return false; - } - - // Check that |message_.fresh_id| is actually fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // Check that |message_.pred_to_id| contains a mapping for all of the block's - // predecessors. - std::vector predecessors = ir_context->cfg()->preds(block->id()); - - // There must be at least one predecessor. - if (predecessors.empty()) { - return false; - } - - std::map preds_to_ids = - fuzzerutil::RepeatedUInt32PairToMap(message_.pred_to_id()); - - // There must not be repeated key values in |message_.pred_to_id|. - if (preds_to_ids.size() != static_cast(message_.pred_to_id_size())) { - return false; - } - - // Check that each predecessor has a corresponding mapping and all of the - // corresponding ids exist. - for (uint32_t pred : predecessors) { - if (preds_to_ids.count(pred) == 0) { - return false; - } - - // Check that the id exists in the module. - if (!ir_context->get_def_use_mgr()->GetDef(preds_to_ids[pred])) { - return false; - } - } - - // Get the first id and its type (which should be the same as all the other - // ones) and check that the transformation supports this type. - uint32_t first_id = preds_to_ids[predecessors[0]]; - uint32_t type_id = ir_context->get_def_use_mgr()->GetDef(first_id)->type_id(); - if (!CheckTypeIsAllowed(ir_context, type_id)) { - return false; - } - - // Check that the ids corresponding to predecessors are all synonymous, have - // the same type and are available to use at the end of the predecessor. - for (uint32_t pred : predecessors) { - auto id = preds_to_ids[pred]; - - // Check that the id has the same type as the other ones. - if (ir_context->get_def_use_mgr()->GetDef(id)->type_id() != type_id) { - return false; - } - - // Check that the id is synonymous with the others by checking that it is - // synonymous with the first one (or it is the same id). - if (id != first_id && - !transformation_context.GetFactManager()->IsSynonymous( - MakeDataDescriptor(id, {}), MakeDataDescriptor(first_id, {}))) { - return false; - } - - // Check that the id is available at the end of the corresponding - // predecessor block. - - auto pred_block = ir_context->get_instr_block(pred); - - // We should always be able to find the predecessor block, since it is in - // the predecessors list of |block|. - assert(pred_block && "Could not find one of the predecessor blocks."); - - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3722): This - // function always returns false if the block is unreachable, so it may - // need to be refactored. - if (!fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, pred_block->terminator(), id)) { - return false; - } - } - - return true; -} - -void TransformationAddOpPhiSynonym::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Get the type id from one of the ids. - uint32_t first_id = message_.pred_to_id(0).second(); - uint32_t type_id = ir_context->get_def_use_mgr()->GetDef(first_id)->type_id(); - - // Define the operand list. - opt::Instruction::OperandList operand_list; - - // For each predecessor, add the corresponding operands. - for (auto& pair : message_.pred_to_id()) { - operand_list.emplace_back( - opt::Operand{SPV_OPERAND_TYPE_ID, {pair.second()}}); - operand_list.emplace_back( - opt::Operand{SPV_OPERAND_TYPE_ID, {pair.first()}}); - } - - // Add a new OpPhi instructions at the beginning of the block. - ir_context->get_instr_block(message_.block_id()) - ->begin() - .InsertBefore(MakeUnique(ir_context, SpvOpPhi, type_id, - message_.fresh_id(), - std::move(operand_list))); - - // Update the module id bound. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // Invalidate all analyses, since we added an instruction to the module. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - - // Record the fact that the new id is synonym with the other ones by declaring - // that it is a synonym of the first one. - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(message_.fresh_id(), {}), - MakeDataDescriptor(first_id, {}), ir_context); -} - -protobufs::Transformation TransformationAddOpPhiSynonym::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_opphi_synonym() = message_; - return result; -} - -bool TransformationAddOpPhiSynonym::CheckTypeIsAllowed( - opt::IRContext* ir_context, uint32_t type_id) { - auto type = ir_context->get_type_mgr()->GetType(type_id); - if (!type) { - return false; - } - - // We allow the following types: Bool, Integer, Float, Vector, Matrix, Array, - // Struct. - if (type->AsBool() || type->AsInteger() || type->AsFloat() || - type->AsVector() || type->AsMatrix() || type->AsArray() || - type->AsStruct()) { - return true; - } - - // We allow pointer types if the VariablePointers capability is enabled and - // the pointer has the correct storage class (Workgroup or StorageBuffer). - if (type->AsPointer()) { - auto storage_class = type->AsPointer()->storage_class(); - return ir_context->get_feature_mgr()->HasCapability( - SpvCapabilityVariablePointers) && - (storage_class == SpvStorageClassWorkgroup || - storage_class == SpvStorageClassStorageBuffer); - } - - // We do not allow other types. - return false; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_opphi_synonym.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_opphi_synonym.h deleted file mode 100644 index dc0e6d9b8..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_opphi_synonym.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_OPPHI_SYNONYM_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_OPPHI_SYNONYM_H_ - -#include "source/fuzz/transformation.h" - -namespace spvtools { -namespace fuzz { -class TransformationAddOpPhiSynonym : public Transformation { - public: - explicit TransformationAddOpPhiSynonym( - const protobufs::TransformationAddOpPhiSynonym& message); - - TransformationAddOpPhiSynonym( - uint32_t block_id, const std::map& preds_to_ids, - uint32_t fresh_id); - - // - |message_.block_id| is the label of a block with at least one - // predecessor. - // - |message_.pred_to_id| contains a mapping from each of the predecessors of - // the block to an id that is available at the end of the predecessor. - // - All the ids corresponding to a predecessor in |message_.pred_to_id|: - // - have been recorded as synonymous and all have the same type. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3726): if a - // predecessor is a dead block, any id of the right type could be used, - // even if it is not synonym with the others. - // - have one of the following types: Bool, Integer, Float, Vector, Matrix, - // Array, Struct. Pointer types are also allowed if the VariablePointers - // capability is enabled and the storage class is Workgroup or - // StorageBuffer. - // - |message_.fresh_id| is a fresh id. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Given a block with n predecessors, with n >= 1, and n corresponding - // synonymous ids of the same type, each available to use at the end of the - // corresponding predecessor, adds an OpPhi instruction at the beginning of - // the block of the form: - // %fresh_id = OpPhi %type %id_1 %pred_1 %id_2 %pred_2 ... %id_n %pred_n - // This instruction is then marked as synonymous with the ids. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - // Returns true if |type_id| is the id of a type in the module, which is one - // of the following: Bool, Integer, Float, Vector, Matrix, Array, Struct. - // Pointer types are also allowed if the VariablePointers capability is - // enabled and the storage class is Workgroup or StorageBuffer. - static bool CheckTypeIsAllowed(opt::IRContext* ir_context, uint32_t type_id); - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddOpPhiSynonym message_; -}; -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_OPPHI_SYNONYM_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.cpp deleted file mode 100644 index 99bbbdb1c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_parameter.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddParameter::TransformationAddParameter( - const protobufs::TransformationAddParameter& message) - : message_(message) {} - -TransformationAddParameter::TransformationAddParameter( - uint32_t function_id, uint32_t parameter_fresh_id, - uint32_t parameter_type_id, std::map call_parameter_ids, - uint32_t function_type_fresh_id) { - message_.set_function_id(function_id); - message_.set_parameter_fresh_id(parameter_fresh_id); - message_.set_parameter_type_id(parameter_type_id); - *message_.mutable_call_parameter_ids() = - fuzzerutil::MapToRepeatedUInt32Pair(call_parameter_ids); - message_.set_function_type_fresh_id(function_type_fresh_id); -} - -bool TransformationAddParameter::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Check that function exists. - const auto* function = - fuzzerutil::FindFunction(ir_context, message_.function_id()); - if (!function || - fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) { - return false; - } - - // The type must be supported. - uint32_t new_parameter_type_id = message_.parameter_type_id(); - auto new_parameter_type = - ir_context->get_type_mgr()->GetType(new_parameter_type_id); - if (!new_parameter_type) { - return false; - } - if (!IsParameterTypeSupported(*new_parameter_type)) { - return false; - } - - // Iterate over all callers. - std::map call_parameter_ids_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.call_parameter_ids()); - for (auto* instr : - fuzzerutil::GetCallers(ir_context, message_.function_id())) { - uint32_t caller_id = instr->result_id(); - - // If there is no entry for this caller, return false. - if (call_parameter_ids_map.find(caller_id) == - call_parameter_ids_map.end()) { - return false; - } - uint32_t value_id = call_parameter_ids_map[caller_id]; - - auto value_instr = ir_context->get_def_use_mgr()->GetDef(value_id); - if (!value_instr) { - return false; - } - // If the id of the value of the map is not available before the caller, - // return false. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3722): - // This can potentially trigger a bug if the caller is in an - // unreachable block. fuzzerutil::IdIsAvailableBeforeInstruction uses - // dominator analysis to check that value_id is available and the - // domination rules are not defined for unreachable blocks. - // The following code should be refactored. - if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, instr, - value_id)) { - return false; - } - - // The type of the value must be defined. - uint32_t value_type_id = fuzzerutil::GetTypeId(ir_context, value_id); - if (!value_type_id) { - return false; - } - - // Type of every value of the map must be the same for all callers. - if (new_parameter_type_id != value_type_id) { - return false; - } - } - return fuzzerutil::IsFreshId(ir_context, message_.parameter_fresh_id()) && - fuzzerutil::IsFreshId(ir_context, message_.function_type_fresh_id()) && - message_.parameter_fresh_id() != message_.function_type_fresh_id(); -} - -void TransformationAddParameter::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Find the function that will be transformed. - auto* function = fuzzerutil::FindFunction(ir_context, message_.function_id()); - assert(function && "Can't find the function"); - - std::map call_parameter_ids_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.call_parameter_ids()); - - uint32_t new_parameter_type_id = message_.parameter_type_id(); - auto new_parameter_type = - ir_context->get_type_mgr()->GetType(new_parameter_type_id); - assert(new_parameter_type && "New parameter has invalid type."); - - // Add new parameters to the function. - function->AddParameter(MakeUnique( - ir_context, SpvOpFunctionParameter, new_parameter_type_id, - message_.parameter_fresh_id(), opt::Instruction::OperandList())); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.parameter_fresh_id()); - - // If the |new_parameter_type_id| is not a pointer type, mark id as - // irrelevant so that we can replace its use with some other id. If the - // |new_parameter_type_id| is a pointer type, we cannot mark it with - // IdIsIrrelevant, because this pointer might be replaced by a pointer from - // original shader. This would change the semantics of the module. In the case - // of a pointer type we mark it with PointeeValueIsIrrelevant. - if (new_parameter_type->kind() != opt::analysis::Type::kPointer) { - transformation_context->GetFactManager()->AddFactIdIsIrrelevant( - message_.parameter_fresh_id()); - } else { - transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( - message_.parameter_fresh_id()); - } - - // Fix all OpFunctionCall instructions. - for (auto* inst : fuzzerutil::GetCallers(ir_context, function->result_id())) { - inst->AddOperand( - {SPV_OPERAND_TYPE_ID, {call_parameter_ids_map[inst->result_id()]}}); - } - - // Update function's type. - { - // We use a separate scope here since |old_function_type| might become a - // dangling pointer after the call to the fuzzerutil::UpdateFunctionType. - - const auto* old_function_type = - fuzzerutil::GetFunctionType(ir_context, function); - assert(old_function_type && "Function must have a valid type"); - - std::vector parameter_type_ids; - for (uint32_t i = 1; i < old_function_type->NumInOperands(); ++i) { - parameter_type_ids.push_back( - old_function_type->GetSingleWordInOperand(i)); - } - - parameter_type_ids.push_back(new_parameter_type_id); - - fuzzerutil::UpdateFunctionType( - ir_context, function->result_id(), message_.function_type_fresh_id(), - old_function_type->GetSingleWordInOperand(0), parameter_type_ids); - } - - // Make sure our changes are analyzed. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddParameter::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_parameter() = message_; - return result; -} - -bool TransformationAddParameter::IsParameterTypeSupported( - const opt::analysis::Type& type) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403): - // Think about other type instructions we can add here. - switch (type.kind()) { - case opt::analysis::Type::kBool: - case opt::analysis::Type::kInteger: - case opt::analysis::Type::kFloat: - case opt::analysis::Type::kArray: - case opt::analysis::Type::kMatrix: - case opt::analysis::Type::kVector: - return true; - case opt::analysis::Type::kStruct: - return std::all_of(type.AsStruct()->element_types().begin(), - type.AsStruct()->element_types().end(), - [](const opt::analysis::Type* element_type) { - return IsParameterTypeSupported(*element_type); - }); - case opt::analysis::Type::kPointer: { - auto storage_class = type.AsPointer()->storage_class(); - switch (storage_class) { - case SpvStorageClassPrivate: - case SpvStorageClassFunction: - case SpvStorageClassWorkgroup: { - auto pointee_type = type.AsPointer()->pointee_type(); - return IsParameterTypeSupported(*pointee_type); - } - default: - return false; - } - } - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.h deleted file mode 100644 index 361c01a8a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_PARAMETER_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_PARAMETER_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 TransformationAddParameter : public Transformation { - public: - explicit TransformationAddParameter( - const protobufs::TransformationAddParameter& message); - - TransformationAddParameter(uint32_t function_id, uint32_t parameter_fresh_id, - uint32_t parameter_type_id, - std::map call_parameter_ids, - uint32_t function_type_fresh_id); - - // - |function_id| must be a valid result id of some non-entry-point function - // in the module. - // - |parameter_type_id| is a type id of the new parameter. The type must be - // supported by this transformation as specified by IsParameterTypeSupported - // function. - // - |call_parameter_id| must map from every id of an OpFunctionCall - // instruction of this function to the id that will be passed as the new - // parameter at that call site. There could be no callers, therefore this - // map can be empty. - // - |parameter_fresh_id| and |function_type_fresh_id| are fresh ids and are - // not equal. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - Creates a new OpFunctionParameter instruction with result id - // |parameter_fresh_id| for the function with |function_id|. - // - Adjusts function's type to include a new parameter. - // - Adds an argument to every caller of the function to account for the added - // parameter. The argument is the value in |call_parameter_id| map. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if the type of the parameter is supported by this - // transformation. - static bool IsParameterTypeSupported(const opt::analysis::Type& type); - - private: - protobufs::TransformationAddParameter message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_PARAMETER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_relaxed_decoration.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_relaxed_decoration.cpp deleted file mode 100644 index effa71db2..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_relaxed_decoration.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_relaxed_decoration.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddRelaxedDecoration::TransformationAddRelaxedDecoration( - const spvtools::fuzz::protobufs::TransformationAddRelaxedDecoration& - message) - : message_(message) {} - -TransformationAddRelaxedDecoration::TransformationAddRelaxedDecoration( - uint32_t result_id) { - message_.set_result_id(result_id); -} - -bool TransformationAddRelaxedDecoration::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // |message_.result_id| must be the id of an instruction. - auto instr = ir_context->get_def_use_mgr()->GetDef(message_.result_id()); - if (!instr) { - return false; - } - opt::BasicBlock* cur_block = ir_context->get_instr_block(instr); - // The instruction must have a block. - if (cur_block == nullptr) { - return false; - } - // |cur_block| must be a dead block. - if (!(transformation_context.GetFactManager()->BlockIsDead( - cur_block->id()))) { - return false; - } - // The instruction must be numeric. - return IsNumeric(instr->opcode()); -} - -void TransformationAddRelaxedDecoration::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Add a RelaxedPrecision decoration targeting |message_.result_id|. - ir_context->get_decoration_mgr()->AddDecoration( - message_.result_id(), SpvDecorationRelaxedPrecision); -} - -protobufs::Transformation TransformationAddRelaxedDecoration::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_add_relaxed_decoration() = message_; - return result; -} - -bool TransformationAddRelaxedDecoration::IsNumeric(uint32_t opcode) { - switch (opcode) { - case SpvOpConvertFToU: - case SpvOpConvertFToS: - case SpvOpConvertSToF: - case SpvOpConvertUToF: - case SpvOpUConvert: - case SpvOpSConvert: - case SpvOpFConvert: - case SpvOpConvertPtrToU: - case SpvOpSatConvertSToU: - case SpvOpSatConvertUToS: - case SpvOpVectorExtractDynamic: - case SpvOpVectorInsertDynamic: - case SpvOpVectorShuffle: - case SpvOpTranspose: - case SpvOpSNegate: - case SpvOpFNegate: - case SpvOpIAdd: - case SpvOpFAdd: - case SpvOpISub: - case SpvOpFSub: - case SpvOpIMul: - case SpvOpFMul: - case SpvOpUDiv: - case SpvOpSDiv: - case SpvOpFDiv: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSMod: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpVectorTimesScalar: - case SpvOpMatrixTimesScalar: - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - case SpvOpOuterProduct: - case SpvOpDot: - case SpvOpIAddCarry: - case SpvOpISubBorrow: - case SpvOpUMulExtended: - case SpvOpSMulExtended: - case SpvOpShiftRightLogical: - case SpvOpShiftRightArithmetic: - case SpvOpShiftLeftLogical: - case SpvOpBitwiseOr: - case SpvOpBitwiseXor: - case SpvOpBitwiseAnd: - case SpvOpNot: - case SpvOpBitFieldInsert: - case SpvOpBitFieldSExtract: - case SpvOpBitFieldUExtract: - case SpvOpBitReverse: - case SpvOpBitCount: - case SpvOpAtomicLoad: - case SpvOpAtomicStore: - case SpvOpAtomicExchange: - case SpvOpAtomicCompareExchange: - case SpvOpAtomicCompareExchangeWeak: - case SpvOpAtomicIIncrement: - case SpvOpAtomicIDecrement: - case SpvOpAtomicIAdd: - case SpvOpAtomicISub: - case SpvOpAtomicSMin: - case SpvOpAtomicUMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMax: - case SpvOpAtomicAnd: - case SpvOpAtomicOr: - case SpvOpAtomicXor: - return true; - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools \ No newline at end of file diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_relaxed_decoration.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_relaxed_decoration.h deleted file mode 100644 index 30c1abfa3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_relaxed_decoration.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_TRANSFORMATION_ADD_RELAXED_DECORATION_H -#define SPIRV_TOOLS_TRANSFORMATION_ADD_RELAXED_DECORATION_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 TransformationAddRelaxedDecoration : public Transformation { - public: - explicit TransformationAddRelaxedDecoration( - const protobufs::TransformationAddRelaxedDecoration& message); - - explicit TransformationAddRelaxedDecoration(uint32_t fresh_id); - - // - |message_.result_id| must be the result id of an instruction, which is - // located in a dead block and Relaxed decoration can be applied. - // - It does not matter whether this instruction is already annotated with the - // Relaxed decoration. - bool IsApplicable( - - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds a decoration of the form: - // 'OpDecoration |message_.result_id| RelaxedPrecision' - // to the module. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if and only if |opcode| is the opcode of an instruction - // that operates on 32-bit integers and 32-bit floats - // as defined by the SPIR-V specification. - static bool IsNumeric(uint32_t opcode); - - private: - protobufs::TransformationAddRelaxedDecoration message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_TRANSFORMATION_ADD_RELAXED_DECORATION_H diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.cpp deleted file mode 100644 index d6a7083f5..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_add_spec_constant_op.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddSpecConstantOp::TransformationAddSpecConstantOp( - spvtools::fuzz::protobufs::TransformationAddSpecConstantOp message) - : message_(std::move(message)) {} - -TransformationAddSpecConstantOp::TransformationAddSpecConstantOp( - uint32_t fresh_id, uint32_t type_id, SpvOp opcode, - const opt::Instruction::OperandList& operands) { - message_.set_fresh_id(fresh_id); - message_.set_type_id(type_id); - message_.set_opcode(opcode); - for (const auto& operand : operands) { - auto* op = message_.add_operand(); - op->set_operand_type(operand.type); - for (auto word : operand.words) { - op->add_operand_data(word); - } - } -} - -bool TransformationAddSpecConstantOp::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - auto clone = fuzzerutil::CloneIRContext(ir_context); - ApplyImpl(clone.get()); - return fuzzerutil::IsValid(clone.get(), - transformation_context.GetValidatorOptions()); -} - -void TransformationAddSpecConstantOp::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - ApplyImpl(ir_context); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -void TransformationAddSpecConstantOp::ApplyImpl( - opt::IRContext* ir_context) const { - opt::Instruction::OperandList operands = { - {SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER, {message_.opcode()}}}; - - for (const auto& operand : message_.operand()) { - std::vector words(operand.operand_data().begin(), - operand.operand_data().end()); - operands.push_back({static_cast(operand.operand_type()), - std::move(words)}); - } - - ir_context->AddGlobalValue(MakeUnique( - ir_context, SpvOpSpecConstantOp, message_.type_id(), message_.fresh_id(), - std::move(operands))); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); -} - -protobufs::Transformation TransformationAddSpecConstantOp::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_spec_constant_op() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.h deleted file mode 100644 index c0f7154c9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_SPEC_CONSTANT_OP_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_SPEC_CONSTANT_OP_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 TransformationAddSpecConstantOp : public Transformation { - public: - explicit TransformationAddSpecConstantOp( - protobufs::TransformationAddSpecConstantOp message); - - TransformationAddSpecConstantOp( - uint32_t fresh_id, uint32_t type_id, SpvOp opcode, - const opt::Instruction::OperandList& operands); - - // - |fresh_id| is a fresh result id in the module. - // - |type_id| is a valid result id of some OpType* instruction in the - // module. It is also a valid type id with respect to |opcode|. - // - |opcode| is one of the opcodes supported by OpSpecConstantOp. - // - |operands| are valid with respect to |opcode| - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // |%fresh_id = OpSpecConstantOp %type_id opcode operands...| is added to the - // module. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - void ApplyImpl(opt::IRContext* ir_context) const; - - protobufs::TransformationAddSpecConstantOp message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_SPEC_CONSTANT_OP_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_synonym.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_synonym.cpp deleted file mode 100644 index 6a93e61b9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_synonym.cpp +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_synonym.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddSynonym::TransformationAddSynonym( - protobufs::TransformationAddSynonym message) - : message_(std::move(message)) {} - -TransformationAddSynonym::TransformationAddSynonym( - uint32_t result_id, - protobufs::TransformationAddSynonym::SynonymType synonym_type, - uint32_t synonym_fresh_id, - const protobufs::InstructionDescriptor& insert_before) { - message_.set_result_id(result_id); - message_.set_synonym_type(synonym_type); - message_.set_synonym_fresh_id(synonym_fresh_id); - *message_.mutable_insert_before() = insert_before; -} - -bool TransformationAddSynonym::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - assert(protobufs::TransformationAddSynonym::SynonymType_IsValid( - message_.synonym_type()) && - "Synonym type is invalid"); - - // |synonym_fresh_id| must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.synonym_fresh_id())) { - return false; - } - - // Check that |message_.result_id| is valid. - auto* synonym = ir_context->get_def_use_mgr()->GetDef(message_.result_id()); - if (!synonym) { - return false; - } - - // Check that we can apply |synonym_type| to |result_id|. - if (!IsInstructionValid(ir_context, transformation_context, synonym, - message_.synonym_type())) { - return false; - } - - // Check that |insert_before| is valid. - auto* insert_before_inst = - FindInstruction(message_.insert_before(), ir_context); - if (!insert_before_inst) { - return false; - } - - // Check that we can insert |message._synonymous_instruction| before - // |message_.insert_before| instruction. We use OpIAdd to represent some - // instruction that can produce a synonym. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, - insert_before_inst)) { - return false; - } - - // A constant instruction must be present in the module if required. - if (IsAdditionalConstantRequired(message_.synonym_type()) && - MaybeGetConstantId(ir_context, transformation_context) == 0) { - return false; - } - - // Domination rules must be satisfied. - return fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, insert_before_inst, message_.result_id()); -} - -void TransformationAddSynonym::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Add a synonymous instruction. - FindInstruction(message_.insert_before(), ir_context) - ->InsertBefore( - MakeSynonymousInstruction(ir_context, *transformation_context)); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.synonym_fresh_id()); - - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - - // Propagate PointeeValueIsIrrelevant fact. - const auto* new_synonym_type = ir_context->get_type_mgr()->GetType( - fuzzerutil::GetTypeId(ir_context, message_.synonym_fresh_id())); - assert(new_synonym_type && "New synonym should have a valid type"); - - if (transformation_context->GetFactManager()->PointeeValueIsIrrelevant( - message_.result_id()) && - new_synonym_type->AsPointer()) { - transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( - message_.synonym_fresh_id()); - } - - // Mark two ids as synonymous. - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(message_.result_id(), {}), - MakeDataDescriptor(message_.synonym_fresh_id(), {}), ir_context); -} - -protobufs::Transformation TransformationAddSynonym::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_synonym() = message_; - return result; -} - -bool TransformationAddSynonym::IsInstructionValid( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, opt::Instruction* inst, - protobufs::TransformationAddSynonym::SynonymType synonym_type) { - // Instruction must have a result id, type id. We skip OpUndef and - // OpConstantNull. - if (!inst || !inst->result_id() || !inst->type_id() || - inst->opcode() == SpvOpUndef || inst->opcode() == SpvOpConstantNull) { - return false; - } - - if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, inst)) { - return false; - } - - switch (synonym_type) { - case protobufs::TransformationAddSynonym::ADD_ZERO: - case protobufs::TransformationAddSynonym::SUB_ZERO: - case protobufs::TransformationAddSynonym::MUL_ONE: { - // The instruction must be either scalar or vector of integers or floats. - const auto* type = ir_context->get_type_mgr()->GetType(inst->type_id()); - assert(type && "Instruction's result id is invalid"); - - if (const auto* vector = type->AsVector()) { - return vector->element_type()->AsInteger() || - vector->element_type()->AsFloat(); - } - - return type->AsInteger() || type->AsFloat(); - } - case protobufs::TransformationAddSynonym::COPY_OBJECT: - // All checks for OpCopyObject are handled by - // fuzzerutil::CanMakeSynonymOf. - return true; - case protobufs::TransformationAddSynonym::LOGICAL_AND: - case protobufs::TransformationAddSynonym::LOGICAL_OR: { - // The instruction must be either a scalar or a vector of booleans. - const auto* type = ir_context->get_type_mgr()->GetType(inst->type_id()); - assert(type && "Instruction's result id is invalid"); - return (type->AsVector() && type->AsVector()->element_type()->AsBool()) || - type->AsBool(); - } - default: - assert(false && "Synonym type is not supported"); - return false; - } -} - -std::unique_ptr -TransformationAddSynonym::MakeSynonymousInstruction( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - auto synonym_type_id = - fuzzerutil::GetTypeId(ir_context, message_.result_id()); - assert(synonym_type_id && "Synonym has invalid type id"); - - switch (message_.synonym_type()) { - case protobufs::TransformationAddSynonym::SUB_ZERO: - case protobufs::TransformationAddSynonym::MUL_ONE: - case protobufs::TransformationAddSynonym::ADD_ZERO: { - const auto* synonym_type = - ir_context->get_type_mgr()->GetType(synonym_type_id); - assert(synonym_type && "Synonym has invalid type"); - - // Compute instruction's opcode based on the type of the operand. - // We have already checked that the operand is either a scalar or a vector - // of either integers or floats. - auto is_integral = - (synonym_type->AsVector() && - synonym_type->AsVector()->element_type()->AsInteger()) || - synonym_type->AsInteger(); - auto opcode = SpvOpNop; - switch (message_.synonym_type()) { - case protobufs::TransformationAddSynonym::SUB_ZERO: - opcode = is_integral ? SpvOpISub : SpvOpFSub; - break; - case protobufs::TransformationAddSynonym::MUL_ONE: - opcode = is_integral ? SpvOpIMul : SpvOpFMul; - break; - case protobufs::TransformationAddSynonym::ADD_ZERO: - opcode = is_integral ? SpvOpIAdd : SpvOpFAdd; - break; - default: - assert(false && "Unreachable"); - break; - } - - return MakeUnique( - ir_context, opcode, synonym_type_id, message_.synonym_fresh_id(), - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.result_id()}}, - {SPV_OPERAND_TYPE_ID, - {MaybeGetConstantId(ir_context, transformation_context)}}}); - } - case protobufs::TransformationAddSynonym::COPY_OBJECT: - return MakeUnique( - ir_context, SpvOpCopyObject, synonym_type_id, - message_.synonym_fresh_id(), - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.result_id()}}}); - case protobufs::TransformationAddSynonym::LOGICAL_OR: - case protobufs::TransformationAddSynonym::LOGICAL_AND: { - auto opcode = message_.synonym_type() == - protobufs::TransformationAddSynonym::LOGICAL_OR - ? SpvOpLogicalOr - : SpvOpLogicalAnd; - return MakeUnique( - ir_context, opcode, synonym_type_id, message_.synonym_fresh_id(), - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.result_id()}}, - {SPV_OPERAND_TYPE_ID, - {MaybeGetConstantId(ir_context, transformation_context)}}}); - } - default: - assert(false && "Unhandled synonym type"); - return nullptr; - } -} - -uint32_t TransformationAddSynonym::MaybeGetConstantId( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - assert(IsAdditionalConstantRequired(message_.synonym_type()) && - "Synonym type doesn't require an additional constant"); - - auto synonym_type_id = - fuzzerutil::GetTypeId(ir_context, message_.result_id()); - assert(synonym_type_id && "Synonym has invalid type id"); - - switch (message_.synonym_type()) { - case protobufs::TransformationAddSynonym::ADD_ZERO: - case protobufs::TransformationAddSynonym::SUB_ZERO: - case protobufs::TransformationAddSynonym::LOGICAL_OR: - return fuzzerutil::MaybeGetZeroConstant( - ir_context, transformation_context, synonym_type_id, false); - case protobufs::TransformationAddSynonym::MUL_ONE: - case protobufs::TransformationAddSynonym::LOGICAL_AND: { - auto synonym_type = ir_context->get_type_mgr()->GetType(synonym_type_id); - assert(synonym_type && "Synonym has invalid type"); - - if (const auto* vector = synonym_type->AsVector()) { - auto element_type_id = - ir_context->get_type_mgr()->GetId(vector->element_type()); - assert(element_type_id && "Vector's element type is invalid"); - - auto one_word = - vector->element_type()->AsFloat() ? fuzzerutil::FloatToWord(1) : 1u; - if (auto scalar_one_id = fuzzerutil::MaybeGetScalarConstant( - ir_context, transformation_context, {one_word}, element_type_id, - false)) { - return fuzzerutil::MaybeGetCompositeConstant( - ir_context, transformation_context, - std::vector(vector->element_count(), scalar_one_id), - synonym_type_id, false); - } - - return 0; - } else { - return fuzzerutil::MaybeGetScalarConstant( - ir_context, transformation_context, - {synonym_type->AsFloat() ? fuzzerutil::FloatToWord(1) : 1u}, - synonym_type_id, false); - } - } - default: - // The assertion at the beginning of the function will fail in the debug - // mode. - return 0; - } -} - -bool TransformationAddSynonym::IsAdditionalConstantRequired( - protobufs::TransformationAddSynonym::SynonymType synonym_type) { - switch (synonym_type) { - case protobufs::TransformationAddSynonym::ADD_ZERO: - case protobufs::TransformationAddSynonym::SUB_ZERO: - case protobufs::TransformationAddSynonym::LOGICAL_OR: - case protobufs::TransformationAddSynonym::MUL_ONE: - case protobufs::TransformationAddSynonym::LOGICAL_AND: - return true; - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_synonym.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_synonym.h deleted file mode 100644 index 7705415a7..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_synonym.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_SYNONYM_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_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 TransformationAddSynonym : public Transformation { - public: - explicit TransformationAddSynonym( - protobufs::TransformationAddSynonym message); - - TransformationAddSynonym( - uint32_t result_id, - protobufs::TransformationAddSynonym::SynonymType synonym_type, - uint32_t synonym_fresh_id, - const protobufs::InstructionDescriptor& insert_before); - - // - |result_id| must be a valid result id of some instruction in the module. - // - |result_id| may not be an irrelevant id. - // - |synonym_type| is a type of the synonymous instruction that will be - // created. - // - |synonym_fresh_id| is a fresh id. - // - |insert_before| must be a valid instruction descriptor and we must be - // able to insert a new synonymous instruction before |insert_before|. - // - |result_id| must be available before |insert_before|. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Creates a new synonymous instruction according to the |synonym_type| with - // result id |synonym_fresh_id|. - // Inserts that instruction before |insert_before| and creates a fact - // that the |synonym_fresh_id| and the |result_id| are synonymous. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if we can create a synonym of |inst| according to the - // |synonym_type|. - static bool IsInstructionValid( - opt::IRContext* ir_context, - const TransformationContext& transformation_context, - opt::Instruction* inst, - protobufs::TransformationAddSynonym::SynonymType synonym_type); - - // Returns true if |synonym_type| requires an additional constant instruction - // to be present in the module. - static bool IsAdditionalConstantRequired( - protobufs::TransformationAddSynonym::SynonymType synonym_type); - - private: - // Returns a new instruction which is synonymous to |message_.result_id|. - std::unique_ptr MakeSynonymousInstruction( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const; - - // Returns a result id of a constant instruction that is required to be - // present in some synonym types (e.g. returns a result id of a zero constant - // for ADD_ZERO synonym type). Returns 0 if no such instruction is present in - // the module. This method should only be called when - // IsAdditionalConstantRequired returns true. - uint32_t MaybeGetConstantId( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const; - - protobufs::TransformationAddSynonym message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_SYNONYM_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_array.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_array.cpp deleted file mode 100644 index 8f5af07fb..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_array.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_array.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeArray::TransformationAddTypeArray( - const spvtools::fuzz::protobufs::TransformationAddTypeArray& message) - : message_(message) {} - -TransformationAddTypeArray::TransformationAddTypeArray(uint32_t fresh_id, - uint32_t element_type_id, - uint32_t size_id) { - message_.set_fresh_id(fresh_id); - message_.set_element_type_id(element_type_id); - message_.set_size_id(size_id); -} - -bool TransformationAddTypeArray::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // A fresh id is required. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - auto element_type = - ir_context->get_type_mgr()->GetType(message_.element_type_id()); - if (!element_type || element_type->AsFunction()) { - // The element type id either does not refer to a type, or refers to a - // function type; both are illegal. - return false; - } - auto constant = - ir_context->get_constant_mgr()->GetConstantsFromIds({message_.size_id()}); - if (constant.empty()) { - // The size id does not refer to a constant. - return false; - } - assert(constant.size() == 1 && - "Only one constant id was provided, so only one constant should have " - "been returned"); - - auto int_constant = constant[0]->AsIntConstant(); - if (!int_constant) { - // The size constant is not an integer. - return false; - } - // We require that the size constant be a 32-bit value that is positive when - // interpreted as being signed. - return int_constant->words().size() == 1 && int_constant->GetS32() >= 1; -} - -void TransformationAddTypeArray::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - opt::Instruction::OperandList in_operands; - in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.element_type_id()}}); - in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.size_id()}}); - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeArray, 0, message_.fresh_id(), in_operands)); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeArray::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_array() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_array.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_array.h deleted file mode 100644 index 5e9b8aaf9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_array.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_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 TransformationAddTypeArray : public Transformation { - public: - explicit TransformationAddTypeArray( - const protobufs::TransformationAddTypeArray& message); - - TransformationAddTypeArray(uint32_t fresh_id, uint32_t element_type_id, - uint32_t size_id); - - // - |message_.fresh_id| must be fresh - // - |message_.element_type_id| must be the id of a non-function type - // - |message_.size_id| must be the id of a 32-bit integer constant that is - // positive when interpreted as signed. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypeArray instruction to the module, with element type given by - // |message_.element_type_id| and size given by |message_.size_id|. The - // result id of the instruction is |message_.fresh_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeArray message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp deleted file mode 100644 index 77409a8c9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_boolean.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeBoolean::TransformationAddTypeBoolean( - const spvtools::fuzz::protobufs::TransformationAddTypeBoolean& message) - : message_(message) {} - -TransformationAddTypeBoolean::TransformationAddTypeBoolean(uint32_t fresh_id) { - message_.set_fresh_id(fresh_id); -} - -bool TransformationAddTypeBoolean::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // Applicable if there is no bool type already declared in the module. - opt::analysis::Bool bool_type; - return ir_context->get_type_mgr()->GetId(&bool_type) == 0; -} - -void TransformationAddTypeBoolean::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - opt::Instruction::OperandList empty_operands; - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands)); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeBoolean::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_boolean() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h deleted file mode 100644 index 5ce5b9a47..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/transformation.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -class TransformationAddTypeBoolean : public Transformation { - public: - explicit TransformationAddTypeBoolean( - const protobufs::TransformationAddTypeBoolean& message); - - explicit TransformationAddTypeBoolean(uint32_t fresh_id); - - // - |message_.fresh_id| must not be used by the module. - // - The module must not yet declare OpTypeBoolean - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds OpTypeBoolean with |message_.fresh_id| as result id. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeBoolean message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp deleted file mode 100644 index 9f43c3edc..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_float.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeFloat::TransformationAddTypeFloat(uint32_t fresh_id, - uint32_t width) { - message_.set_fresh_id(fresh_id); - message_.set_width(width); -} - -TransformationAddTypeFloat::TransformationAddTypeFloat( - const spvtools::fuzz::protobufs::TransformationAddTypeFloat& message) - : message_(message) {} - -bool TransformationAddTypeFloat::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // Checks float type width capabilities. - switch (message_.width()) { - case 16: - // The Float16 capability must be present. - if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityFloat16)) { - return false; - } - break; - case 32: - // No capabilities needed. - break; - case 64: - // The Float64 capability must be present. - if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityFloat64)) { - return false; - } - break; - default: - assert(false && "Unexpected float type width"); - return false; - } - - // Applicable if there is no float type with this width already declared in - // the module. - return fuzzerutil::MaybeGetFloatType(ir_context, message_.width()) == 0; -} - -void TransformationAddTypeFloat::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - fuzzerutil::AddFloatType(ir_context, message_.fresh_id(), message_.width()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeFloat::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_float() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h deleted file mode 100644 index a8fa0e104..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_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 TransformationAddTypeFloat : public Transformation { - public: - explicit TransformationAddTypeFloat( - const protobufs::TransformationAddTypeFloat& message); - - TransformationAddTypeFloat(uint32_t fresh_id, uint32_t width); - - // - |message_.fresh_id| must not be used by the module - // - The module must not contain an OpTypeFloat instruction with width - // |message_.width| - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypeFloat instruction to the module with the given width - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeFloat message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_function.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_function.cpp deleted file mode 100644 index c878025c6..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_function.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_function.h" - -#include - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeFunction::TransformationAddTypeFunction( - const spvtools::fuzz::protobufs::TransformationAddTypeFunction& message) - : message_(message) {} - -TransformationAddTypeFunction::TransformationAddTypeFunction( - uint32_t fresh_id, uint32_t return_type_id, - const std::vector& argument_type_ids) { - message_.set_fresh_id(fresh_id); - message_.set_return_type_id(return_type_id); - for (auto id : argument_type_ids) { - message_.add_argument_type_id(id); - } -} - -bool TransformationAddTypeFunction::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The result id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // The return and argument types must be type ids but not not be function - // type ids. - if (!fuzzerutil::IsNonFunctionTypeId(ir_context, message_.return_type_id())) { - return false; - } - for (auto argument_type_id : message_.argument_type_id()) { - if (!fuzzerutil::IsNonFunctionTypeId(ir_context, argument_type_id)) { - return false; - } - } - // Check whether there is already an OpTypeFunction definition that uses - // exactly the same return and argument type ids. (Note that the type manager - // does not allow us to check this, as it does not distinguish between - // function types with different but isomorphic pointer argument types.) - std::vector type_ids = {message_.return_type_id()}; - type_ids.insert(type_ids.end(), message_.argument_type_id().begin(), - message_.argument_type_id().end()); - return fuzzerutil::FindFunctionType(ir_context, type_ids) == 0; -} - -void TransformationAddTypeFunction::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - std::vector type_ids = {message_.return_type_id()}; - type_ids.insert(type_ids.end(), message_.argument_type_id().begin(), - message_.argument_type_id().end()); - - fuzzerutil::AddFunctionType(ir_context, message_.fresh_id(), type_ids); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeFunction::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_function() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_function.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_function.h deleted file mode 100644 index f26b2501c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_function.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FUNCTION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FUNCTION_H_ - -#include - -#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 TransformationAddTypeFunction : public Transformation { - public: - explicit TransformationAddTypeFunction( - const protobufs::TransformationAddTypeFunction& message); - - TransformationAddTypeFunction(uint32_t fresh_id, uint32_t return_type_id, - const std::vector& argument_type_ids); - - // - |message_.fresh_id| must not be used by the module - // - |message_.return_type_id| and each element of |message_.argument_type_id| - // must be the ids of non-function types - // - The module must not contain an OpTypeFunction instruction defining a - // function type with the signature provided by the given return and - // argument types - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypeFunction instruction to the module, with signature given by - // |message_.return_type_id| and |message_.argument_type_id|. The result id - // for the instruction is |message_.fresh_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeFunction message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FUNCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp deleted file mode 100644 index e39a23dfd..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_int.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeInt::TransformationAddTypeInt( - const spvtools::fuzz::protobufs::TransformationAddTypeInt& message) - : message_(message) {} - -TransformationAddTypeInt::TransformationAddTypeInt(uint32_t fresh_id, - uint32_t width, - bool is_signed) { - message_.set_fresh_id(fresh_id); - message_.set_width(width); - message_.set_is_signed(is_signed); -} - -bool TransformationAddTypeInt::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // Checks integer type width capabilities. - switch (message_.width()) { - case 8: - // The Int8 capability must be present. - if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt8)) { - return false; - } - break; - case 16: - // The Int16 capability must be present. - if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt16)) { - return false; - } - break; - case 32: - // No capabilities needed. - break; - case 64: - // The Int64 capability must be present. - if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt64)) { - return false; - } - break; - default: - assert(false && "Unexpected integer type width"); - return false; - } - - // Applicable if there is no int type with this width and signedness already - // declared in the module. - return fuzzerutil::MaybeGetIntegerType(ir_context, message_.width(), - message_.is_signed()) == 0; -} - -void TransformationAddTypeInt::Apply(opt::IRContext* ir_context, - TransformationContext* /*unused*/) const { - fuzzerutil::AddIntegerType(ir_context, message_.fresh_id(), message_.width(), - message_.is_signed()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeInt::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_int() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h deleted file mode 100644 index 5c3c9591d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_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 TransformationAddTypeInt : public Transformation { - public: - explicit TransformationAddTypeInt( - const protobufs::TransformationAddTypeInt& message); - - TransformationAddTypeInt(uint32_t fresh_id, uint32_t width, bool is_signed); - - // - |message_.fresh_id| must not be used by the module - // - The module must not contain an OpTypeInt instruction with width - // |message_.width| and signedness |message.is_signed| - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypeInt instruction to the module with the given width and - // signedness. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeInt message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_matrix.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_matrix.cpp deleted file mode 100644 index 2c24eaa08..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_matrix.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_matrix.h" - -#include "fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeMatrix::TransformationAddTypeMatrix( - const spvtools::fuzz::protobufs::TransformationAddTypeMatrix& message) - : message_(message) {} - -TransformationAddTypeMatrix::TransformationAddTypeMatrix( - uint32_t fresh_id, uint32_t column_type_id, uint32_t column_count) { - message_.set_fresh_id(fresh_id); - message_.set_column_type_id(column_type_id); - message_.set_column_count(column_count); -} - -bool TransformationAddTypeMatrix::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The result id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // The column type must be a floating-point vector. - auto column_type = - ir_context->get_type_mgr()->GetType(message_.column_type_id()); - if (!column_type) { - return false; - } - return column_type->AsVector() && - column_type->AsVector()->element_type()->AsFloat(); -} - -void TransformationAddTypeMatrix::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - opt::Instruction::OperandList in_operands; - in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.column_type_id()}}); - in_operands.push_back( - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.column_count()}}); - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeMatrix, 0, message_.fresh_id(), in_operands)); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeMatrix::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_matrix() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_matrix.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_matrix.h deleted file mode 100644 index 6d0724e6f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_matrix.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_MATRIX_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_MATRIX_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 TransformationAddTypeMatrix : public Transformation { - public: - explicit TransformationAddTypeMatrix( - const protobufs::TransformationAddTypeMatrix& message); - - TransformationAddTypeMatrix(uint32_t fresh_id, uint32_t column_type_id, - uint32_t column_count); - - // - |message_.fresh_id| must be a fresh id - // - |message_.column_type_id| must be the id of a floating-point vector type - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypeMatrix instruction to the module, with column type - // |message_.column_type_id| and |message_.column_count| columns, with result - // id |message_.fresh_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeMatrix message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_MATRIX_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp deleted file mode 100644 index 6cc8171ee..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_pointer.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypePointer::TransformationAddTypePointer( - const spvtools::fuzz::protobufs::TransformationAddTypePointer& message) - : message_(message) {} - -TransformationAddTypePointer::TransformationAddTypePointer( - uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) { - message_.set_fresh_id(fresh_id); - message_.set_storage_class(storage_class); - message_.set_base_type_id(base_type_id); -} - -bool TransformationAddTypePointer::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // The base type must be known. - return ir_context->get_type_mgr()->GetType(message_.base_type_id()) != - nullptr; -} - -void TransformationAddTypePointer::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Add the pointer type. - opt::Instruction::OperandList in_operands = { - {SPV_OPERAND_TYPE_STORAGE_CLASS, {message_.storage_class()}}, - {SPV_OPERAND_TYPE_ID, {message_.base_type_id()}}}; - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypePointer, 0, message_.fresh_id(), in_operands)); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypePointer::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_pointer() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.h deleted file mode 100644 index 3b50a293f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_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 TransformationAddTypePointer : public Transformation { - public: - explicit TransformationAddTypePointer( - const protobufs::TransformationAddTypePointer& message); - - TransformationAddTypePointer(uint32_t fresh_id, SpvStorageClass storage_class, - uint32_t base_type_id); - - // - |message_.fresh_id| must not be used by the module - // - |message_.base_type_id| must be the result id of an OpType[...] - // instruction - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypePointer instruction with the given storage class and base - // type to the module. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypePointer message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_struct.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_struct.cpp deleted file mode 100644 index a7345a17a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_struct.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_struct.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeStruct::TransformationAddTypeStruct( - const spvtools::fuzz::protobufs::TransformationAddTypeStruct& message) - : message_(message) {} - -TransformationAddTypeStruct::TransformationAddTypeStruct( - uint32_t fresh_id, const std::vector& member_type_ids) { - message_.set_fresh_id(fresh_id); - for (auto member_type_id : member_type_ids) { - message_.add_member_type_id(member_type_id); - } -} - -bool TransformationAddTypeStruct::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // A fresh id is required. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - for (auto member_type : message_.member_type_id()) { - auto type = ir_context->get_type_mgr()->GetType(member_type); - if (!type || type->AsFunction()) { - // The member type id either does not refer to a type, or refers to a - // function type; both are illegal. - return false; - } - } - return true; -} - -void TransformationAddTypeStruct::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - fuzzerutil::AddStructType( - ir_context, message_.fresh_id(), - std::vector(message_.member_type_id().begin(), - message_.member_type_id().end())); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeStruct::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_struct() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_struct.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_struct.h deleted file mode 100644 index 86a532d26..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_struct.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_STRUCT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_STRUCT_H_ - -#include - -#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 TransformationAddTypeStruct : public Transformation { - public: - explicit TransformationAddTypeStruct( - const protobufs::TransformationAddTypeStruct& message); - - TransformationAddTypeStruct(uint32_t fresh_id, - const std::vector& component_type_ids); - - // - |message_.fresh_id| must be a fresh id - // - |message_.member_type_id| must be a sequence of non-function type ids - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypeStruct instruction whose field types are given by - // |message_.member_type_id|, with result id |message_.fresh_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeStruct message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_STRUCT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_vector.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_vector.cpp deleted file mode 100644 index 10a622412..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_vector.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_add_type_vector.h" - -#include "fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationAddTypeVector::TransformationAddTypeVector( - const spvtools::fuzz::protobufs::TransformationAddTypeVector& message) - : message_(message) {} - -TransformationAddTypeVector::TransformationAddTypeVector( - uint32_t fresh_id, uint32_t component_type_id, uint32_t component_count) { - message_.set_fresh_id(fresh_id); - message_.set_component_type_id(component_type_id); - message_.set_component_count(component_count); -} - -bool TransformationAddTypeVector::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - auto component_type = - ir_context->get_type_mgr()->GetType(message_.component_type_id()); - if (!component_type) { - return false; - } - return component_type->AsBool() || component_type->AsFloat() || - component_type->AsInteger(); -} - -void TransformationAddTypeVector::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - fuzzerutil::AddVectorType(ir_context, message_.fresh_id(), - message_.component_type_id(), - message_.component_count()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddTypeVector::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_type_vector() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_vector.h b/3rdparty/spirv-tools/source/fuzz/transformation_add_type_vector.h deleted file mode 100644 index 240f7cce5..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_add_type_vector.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_VECTOR_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_VECTOR_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 TransformationAddTypeVector : public Transformation { - public: - explicit TransformationAddTypeVector( - const protobufs::TransformationAddTypeVector& message); - - TransformationAddTypeVector(uint32_t fresh_id, uint32_t component_type_id, - uint32_t component_count); - - // - |message_.fresh_id| must be a fresh id - // - |message_.component_type_id| must be the id of a scalar type - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpTypeVector instruction to the module, with component type - // |message_.component_type_id| and |message_.component_count| components, - // with result id |message_.fresh_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAddTypeVector message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_VECTOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_adjust_branch_weights.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_adjust_branch_weights.cpp deleted file mode 100644 index ed6813468..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_adjust_branch_weights.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_adjust_branch_weights.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -namespace { - -const uint32_t kBranchWeightForTrueLabelIndex = 3; -const uint32_t kBranchWeightForFalseLabelIndex = 4; - -} // namespace - -TransformationAdjustBranchWeights::TransformationAdjustBranchWeights( - const spvtools::fuzz::protobufs::TransformationAdjustBranchWeights& message) - : message_(message) {} - -TransformationAdjustBranchWeights::TransformationAdjustBranchWeights( - const protobufs::InstructionDescriptor& instruction_descriptor, - const std::pair& branch_weights) { - *message_.mutable_instruction_descriptor() = instruction_descriptor; - message_.mutable_branch_weights()->set_first(branch_weights.first); - message_.mutable_branch_weights()->set_second(branch_weights.second); -} - -bool TransformationAdjustBranchWeights::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - auto instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - if (instruction == nullptr) { - return false; - } - - SpvOp opcode = static_cast( - message_.instruction_descriptor().target_instruction_opcode()); - - assert(instruction->opcode() == opcode && - "The located instruction must have the same opcode as in the " - "descriptor."); - - // Must be an OpBranchConditional instruction. - if (opcode != SpvOpBranchConditional) { - return false; - } - - assert((message_.branch_weights().first() != 0 || - message_.branch_weights().second() != 0) && - "At least one weight must be non-zero."); - - assert(message_.branch_weights().first() <= - UINT32_MAX - message_.branch_weights().second() && - "The sum of the two weights must not be greater than UINT32_MAX."); - - return true; -} - -void TransformationAdjustBranchWeights::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - if (instruction->HasBranchWeights()) { - instruction->SetOperand(kBranchWeightForTrueLabelIndex, - {message_.branch_weights().first()}); - instruction->SetOperand(kBranchWeightForFalseLabelIndex, - {message_.branch_weights().second()}); - } else { - instruction->AddOperand({SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, - {message_.branch_weights().first()}}); - instruction->AddOperand({SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, - {message_.branch_weights().second()}}); - } -} - -protobufs::Transformation TransformationAdjustBranchWeights::ToMessage() const { - protobufs::Transformation result; - *result.mutable_adjust_branch_weights() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_adjust_branch_weights.h b/3rdparty/spirv-tools/source/fuzz/transformation_adjust_branch_weights.h deleted file mode 100644 index 638b0a90e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_adjust_branch_weights.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_ADJUST_BRANCH_WEIGHTS_H_ -#define SOURCE_FUZZ_TRANSFORMATION_ADJUST_BRANCH_WEIGHTS_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 TransformationAdjustBranchWeights : public Transformation { - public: - explicit TransformationAdjustBranchWeights( - const protobufs::TransformationAdjustBranchWeights& message); - - TransformationAdjustBranchWeights( - const protobufs::InstructionDescriptor& instruction_descriptor, - const std::pair& branch_weights); - - // - |message_.instruction_descriptor| must identify an existing - // branch conditional instruction - // - At least one of |branch_weights| must be non-zero and - // the two weights must not overflow a 32-bit unsigned integer when added - // together - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adjust the branch weights of a branch conditional instruction. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationAdjustBranchWeights message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_ADJUST_BRANCH_WEIGHTS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.cpp deleted file mode 100644 index 15af53ed7..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.cpp +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_composite_construct.h" - -#include "source/fuzz/data_descriptor.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/opt/instruction.h" - -namespace spvtools { -namespace fuzz { - -TransformationCompositeConstruct::TransformationCompositeConstruct( - const protobufs::TransformationCompositeConstruct& message) - : message_(message) {} - -TransformationCompositeConstruct::TransformationCompositeConstruct( - uint32_t composite_type_id, std::vector component, - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id) { - message_.set_composite_type_id(composite_type_id); - for (auto a_component : component) { - message_.add_component(a_component); - } - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; - message_.set_fresh_id(fresh_id); -} - -bool TransformationCompositeConstruct::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - // We require the id for the composite constructor to be unused. - return false; - } - - auto insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - if (!insert_before) { - // The instruction before which the composite should be inserted was not - // found. - return false; - } - - auto composite_type = - ir_context->get_type_mgr()->GetType(message_.composite_type_id()); - - if (!fuzzerutil::IsCompositeType(composite_type)) { - // The type must actually be a composite. - return false; - } - - // If the type is an array, matrix, struct or vector, the components need to - // be suitable for constructing something of that type. - if (composite_type->AsArray() && - !ComponentsForArrayConstructionAreOK(ir_context, - *composite_type->AsArray())) { - return false; - } - if (composite_type->AsMatrix() && - !ComponentsForMatrixConstructionAreOK(ir_context, - *composite_type->AsMatrix())) { - return false; - } - if (composite_type->AsStruct() && - !ComponentsForStructConstructionAreOK(ir_context, - *composite_type->AsStruct())) { - return false; - } - if (composite_type->AsVector() && - !ComponentsForVectorConstructionAreOK(ir_context, - *composite_type->AsVector())) { - return false; - } - - // Now check whether every component being used to initialize the composite is - // available at the desired program point. - for (auto component : message_.component()) { - auto* inst = ir_context->get_def_use_mgr()->GetDef(component); - if (!inst) { - return false; - } - - // We should be able to create a synonym of |component| if it's not - // irrelevant. - if (!transformation_context.GetFactManager()->IdIsIrrelevant(component) && - !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, - inst)) { - return false; - } - - if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, - component)) { - return false; - } - } - - return true; -} - -void TransformationCompositeConstruct::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Use the base and offset information from the transformation to determine - // where in the module a new instruction should be inserted. - auto insert_before_inst = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - auto destination_block = ir_context->get_instr_block(insert_before_inst); - auto insert_before = fuzzerutil::GetIteratorForInstruction( - destination_block, insert_before_inst); - - // Prepare the input operands for an OpCompositeConstruct instruction. - opt::Instruction::OperandList in_operands; - for (auto& component_id : message_.component()) { - in_operands.push_back({SPV_OPERAND_TYPE_ID, {component_id}}); - } - - // Insert an OpCompositeConstruct instruction. - insert_before.InsertBefore(MakeUnique( - ir_context, SpvOpCompositeConstruct, message_.composite_type_id(), - message_.fresh_id(), in_operands)); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - - // Inform the fact manager that we now have new synonyms: every component of - // the composite is synonymous with the id used to construct that component, - // except in the case of a vector where a single vector id can span multiple - // components. - auto composite_type = - ir_context->get_type_mgr()->GetType(message_.composite_type_id()); - uint32_t index = 0; - for (auto component : message_.component()) { - auto component_type = ir_context->get_type_mgr()->GetType( - ir_context->get_def_use_mgr()->GetDef(component)->type_id()); - if (composite_type->AsVector() && component_type->AsVector()) { - // The case where the composite being constructed is a vector and the - // component provided for construction is also a vector is special. It - // requires adding a synonym fact relating each element of the sub-vector - // to the corresponding element of the composite being constructed. - assert(component_type->AsVector()->element_type() == - composite_type->AsVector()->element_type()); - assert(component_type->AsVector()->element_count() < - composite_type->AsVector()->element_count()); - for (uint32_t subvector_index = 0; - subvector_index < component_type->AsVector()->element_count(); - subvector_index++) { - if (!transformation_context->GetFactManager()->IdIsIrrelevant( - component)) { - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(component, {subvector_index}), - MakeDataDescriptor(message_.fresh_id(), {index}), ir_context); - } - index++; - } - } else { - // The other cases are simple: the component is made directly synonymous - // with the element of the composite being constructed. - if (!transformation_context->GetFactManager()->IdIsIrrelevant( - component)) { - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(component, {}), - MakeDataDescriptor(message_.fresh_id(), {index}), ir_context); - } - index++; - } - } -} - -bool TransformationCompositeConstruct::ComponentsForArrayConstructionAreOK( - opt::IRContext* ir_context, const opt::analysis::Array& array_type) const { - if (array_type.length_info().words[0] != - opt::analysis::Array::LengthInfo::kConstant) { - // We only handle constant-sized arrays. - return false; - } - if (array_type.length_info().words.size() != 2) { - // We only handle the case where the array size can be captured in a single - // word. - return false; - } - // Get the array size. - auto array_size = array_type.length_info().words[1]; - if (static_cast(message_.component().size()) != array_size) { - // The number of components must match the array size. - return false; - } - // Check that each component is the result id of an instruction whose type is - // the array's element type. - for (auto component_id : message_.component()) { - auto inst = ir_context->get_def_use_mgr()->GetDef(component_id); - if (inst == nullptr || !inst->type_id()) { - // The component does not correspond to an instruction with a result - // type. - return false; - } - auto component_type = ir_context->get_type_mgr()->GetType(inst->type_id()); - assert(component_type); - if (component_type != array_type.element_type()) { - // The component's type does not match the array's element type. - return false; - } - } - return true; -} - -bool TransformationCompositeConstruct::ComponentsForMatrixConstructionAreOK( - opt::IRContext* ir_context, - const opt::analysis::Matrix& matrix_type) const { - if (static_cast(message_.component().size()) != - matrix_type.element_count()) { - // The number of components must match the number of columns of the matrix. - return false; - } - // Check that each component is the result id of an instruction whose type is - // the matrix's column type. - for (auto component_id : message_.component()) { - auto inst = ir_context->get_def_use_mgr()->GetDef(component_id); - if (inst == nullptr || !inst->type_id()) { - // The component does not correspond to an instruction with a result - // type. - return false; - } - auto component_type = ir_context->get_type_mgr()->GetType(inst->type_id()); - assert(component_type); - if (component_type != matrix_type.element_type()) { - // The component's type does not match the matrix's column type. - return false; - } - } - return true; -} - -bool TransformationCompositeConstruct::ComponentsForStructConstructionAreOK( - opt::IRContext* ir_context, - const opt::analysis::Struct& struct_type) const { - if (static_cast(message_.component().size()) != - struct_type.element_types().size()) { - // The number of components must match the number of fields of the struct. - return false; - } - // Check that each component is the result id of an instruction those type - // matches the associated field type. - for (uint32_t field_index = 0; - field_index < struct_type.element_types().size(); field_index++) { - auto inst = ir_context->get_def_use_mgr()->GetDef( - message_.component()[field_index]); - if (inst == nullptr || !inst->type_id()) { - // The component does not correspond to an instruction with a result - // type. - return false; - } - auto component_type = ir_context->get_type_mgr()->GetType(inst->type_id()); - assert(component_type); - if (component_type != struct_type.element_types()[field_index]) { - // The component's type does not match the corresponding field type. - return false; - } - } - return true; -} - -bool TransformationCompositeConstruct::ComponentsForVectorConstructionAreOK( - opt::IRContext* ir_context, - const opt::analysis::Vector& vector_type) const { - uint32_t base_element_count = 0; - auto element_type = vector_type.element_type(); - for (auto& component_id : message_.component()) { - auto inst = ir_context->get_def_use_mgr()->GetDef(component_id); - if (inst == nullptr || !inst->type_id()) { - // The component does not correspond to an instruction with a result - // type. - return false; - } - auto component_type = ir_context->get_type_mgr()->GetType(inst->type_id()); - assert(component_type); - if (component_type == element_type) { - base_element_count++; - } else if (component_type->AsVector() && - component_type->AsVector()->element_type() == element_type) { - base_element_count += component_type->AsVector()->element_count(); - } else { - // The component was not appropriate; e.g. no type corresponding to the - // given id was found, or the type that was found was not compatible - // with the vector being constructed. - return false; - } - } - // The number of components provided (when vector components are flattened - // out) needs to match the length of the vector being constructed. - return base_element_count == vector_type.element_count(); -} - -protobufs::Transformation TransformationCompositeConstruct::ToMessage() const { - protobufs::Transformation result; - *result.mutable_composite_construct() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.h b/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.h deleted file mode 100644 index 2e55e70f9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_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 TransformationCompositeConstruct : public Transformation { - public: - explicit TransformationCompositeConstruct( - const protobufs::TransformationCompositeConstruct& message); - - TransformationCompositeConstruct( - uint32_t composite_type_id, std::vector component, - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id); - - // - |message_.fresh_id| must not be used by the module. - // - |message_.composite_type_id| must be the id of a composite type - // - The elements of |message_.component| must be result ids that are - // suitable for constructing an element of the given composite type, in - // order - // - The elements of |message_.component| must not be the target of any - // decorations. - // - |message_.base_instruction_id| must be the result id of an instruction - // 'base' in some block 'blk'. - // - 'blk' must contain an instruction 'inst' located |message_.offset| - // instructions after 'base' (if |message_.offset| = 0 then 'inst' = - // 'base'). - // - It must be legal to insert an OpCompositeConstruct instruction directly - // before 'inst'. - // - Each element of |message_.component| must be available directly before - // 'inst'. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Inserts a new OpCompositeConstruct instruction, with id - // |message_.fresh_id|, directly before the instruction identified by - // |message_.base_instruction_id| and |message_.offset|. The instruction - // creates a composite of type |message_.composite_type_id| using the ids of - // |message_.component|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Helper to decide whether the components of the transformation are suitable - // for constructing an array of the given type. - bool ComponentsForArrayConstructionAreOK( - opt::IRContext* ir_context, const opt::analysis::Array& array_type) const; - - // Similar, but for matrices. - bool ComponentsForMatrixConstructionAreOK( - opt::IRContext* ir_context, - const opt::analysis::Matrix& matrix_type) const; - - // Similar, but for structs. - bool ComponentsForStructConstructionAreOK( - opt::IRContext* ir_context, - const opt::analysis::Struct& struct_type) const; - - // Similar, but for vectors. - bool ComponentsForVectorConstructionAreOK( - opt::IRContext* ir_context, - const opt::analysis::Vector& vector_type) const; - - protobufs::TransformationCompositeConstruct message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.cpp deleted file mode 100644 index 9f4d55462..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_composite_extract.h" - -#include - -#include "source/fuzz/data_descriptor.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationCompositeExtract::TransformationCompositeExtract( - const spvtools::fuzz::protobufs::TransformationCompositeExtract& message) - : message_(message) {} - -TransformationCompositeExtract::TransformationCompositeExtract( - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id, uint32_t composite_id, std::vector&& index) { - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; - message_.set_fresh_id(fresh_id); - message_.set_composite_id(composite_id); - for (auto an_index : index) { - message_.add_index(an_index); - } -} - -bool TransformationCompositeExtract::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - auto instruction_to_insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - if (!instruction_to_insert_before) { - return false; - } - auto composite_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.composite_id()); - if (!composite_instruction) { - return false; - } - if (!transformation_context.GetFactManager()->IdIsIrrelevant( - message_.composite_id()) && - !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, - composite_instruction)) { - // |composite_id| will participate in DataSynonym facts. Thus, it can't be - // an irrelevant id. - return false; - } - if (auto block = ir_context->get_instr_block(composite_instruction)) { - if (composite_instruction == instruction_to_insert_before || - !ir_context->GetDominatorAnalysis(block->GetParent()) - ->Dominates(composite_instruction, instruction_to_insert_before)) { - return false; - } - } - assert(composite_instruction->type_id() && - "An instruction in a block cannot have a result id but no type id."); - - auto composite_type = - ir_context->get_type_mgr()->GetType(composite_instruction->type_id()); - if (!composite_type) { - return false; - } - - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpCompositeExtract, instruction_to_insert_before)) { - return false; - } - - return fuzzerutil::WalkCompositeTypeIndices(ir_context, - composite_instruction->type_id(), - message_.index()) != 0; -} - -void TransformationCompositeExtract::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - opt::Instruction::OperandList extract_operands; - extract_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}}); - for (auto an_index : message_.index()) { - extract_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {an_index}}); - } - auto composite_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.composite_id()); - auto extracted_type = fuzzerutil::WalkCompositeTypeIndices( - ir_context, composite_instruction->type_id(), message_.index()); - - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, extracted_type, - message_.fresh_id(), extract_operands)); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - - // Add the fact that the id storing the extracted element is synonymous with - // the index into the structure. - if (!transformation_context->GetFactManager()->IdIsIrrelevant( - message_.composite_id())) { - std::vector indices; - for (auto an_index : message_.index()) { - indices.push_back(an_index); - } - protobufs::DataDescriptor data_descriptor_for_extracted_element = - MakeDataDescriptor(message_.composite_id(), std::move(indices)); - protobufs::DataDescriptor data_descriptor_for_result_id = - MakeDataDescriptor(message_.fresh_id(), {}); - transformation_context->GetFactManager()->AddFactDataSynonym( - data_descriptor_for_extracted_element, data_descriptor_for_result_id, - ir_context); - } -} - -protobufs::Transformation TransformationCompositeExtract::ToMessage() const { - protobufs::Transformation result; - *result.mutable_composite_extract() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.h b/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.h deleted file mode 100644 index 34df82348..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_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 TransformationCompositeExtract : public Transformation { - public: - explicit TransformationCompositeExtract( - const protobufs::TransformationCompositeExtract& message); - - TransformationCompositeExtract( - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id, uint32_t composite_id, std::vector&& index); - - // - |message_.fresh_id| must be available - // - |message_.instruction_to_insert_before| must identify an instruction - // before which it is valid to place an OpCompositeExtract - // - |message_.composite_id| must be the id of an instruction that defines - // a composite object, and this id must be available at the instruction - // identified by |message_.instruction_to_insert_before| - // - |message_.index| must be a suitable set of indices for - // |message_.composite_id|, i.e. it must be possible to follow this chain - // of indices to reach a sub-object of |message_.composite_id| - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an OpCompositeConstruct instruction before the instruction identified - // by |message_.instruction_to_insert_before|, that extracts from - // |message_.composite_id| via indices |message_.index| into - // |message_.fresh_id|. If |composite_id| is not an irrelevant id, - // generates a data synonym fact relating - // |message_.fresh_id| to the extracted element. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationCompositeExtract message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_insert.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_composite_insert.cpp deleted file mode 100644 index 75eebd434..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_composite_insert.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2020 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 "transformation_composite_insert.h" - -#include "source/fuzz/fuzzer_pass_add_composite_inserts.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationCompositeInsert::TransformationCompositeInsert( - const spvtools::fuzz::protobufs::TransformationCompositeInsert& message) - : message_(message) {} - -TransformationCompositeInsert::TransformationCompositeInsert( - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id, uint32_t composite_id, uint32_t object_id, - const std::vector& index) { - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; - message_.set_fresh_id(fresh_id); - message_.set_composite_id(composite_id); - message_.set_object_id(object_id); - for (auto an_index : index) { - message_.add_index(an_index); - } -} - -bool TransformationCompositeInsert::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |message_.fresh_id| must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // |message_.composite_id| must refer to an existing composite value. - auto composite = - ir_context->get_def_use_mgr()->GetDef(message_.composite_id()); - - if (!IsCompositeInstructionSupported(ir_context, composite)) { - return false; - } - - // The indices in |message_.index| must be suitable for indexing into - // |composite->type_id()|. - auto component_to_be_replaced_type_id = fuzzerutil::WalkCompositeTypeIndices( - ir_context, composite->type_id(), message_.index()); - if (component_to_be_replaced_type_id == 0) { - return false; - } - - // The instruction having the id of |message_.object_id| must be defined. - auto object_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.object_id()); - if (object_instruction == nullptr || object_instruction->type_id() == 0) { - return false; - } - - // We ignore pointers for now. - auto object_instruction_type = - ir_context->get_type_mgr()->GetType(object_instruction->type_id()); - if (object_instruction_type->AsPointer() != nullptr) { - return false; - } - - // The type id of the object having |message_.object_id| and the type id of - // the component of the composite at index |message_.index| must be the same. - if (component_to_be_replaced_type_id != object_instruction->type_id()) { - return false; - } - - // |message_.instruction_to_insert_before| must be a defined instruction. - auto instruction_to_insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - if (instruction_to_insert_before == nullptr) { - return false; - } - - // |message_.composite_id| and |message_.object_id| must be available before - // the |message_.instruction_to_insert_before|. - if (!fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, instruction_to_insert_before, message_.composite_id())) { - return false; - } - if (!fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, instruction_to_insert_before, message_.object_id())) { - return false; - } - - // It must be possible to insert an OpCompositeInsert before this - // instruction. - return fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpCompositeInsert, instruction_to_insert_before); -} - -void TransformationCompositeInsert::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // |message_.struct_fresh_id| must be fresh. - assert(fuzzerutil::IsFreshId(ir_context, message_.fresh_id()) && - "|message_.fresh_id| must be fresh"); - - std::vector index = - fuzzerutil::RepeatedFieldToVector(message_.index()); - opt::Instruction::OperandList in_operands; - in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.object_id()}}); - in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}}); - for (auto i : index) { - in_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}); - } - auto composite_type_id = - fuzzerutil::GetTypeId(ir_context, message_.composite_id()); - - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeInsert, composite_type_id, - message_.fresh_id(), std::move(in_operands))); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // We have modified the module so most analyzes are now invalid. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - - // Add facts about synonyms. Every element which hasn't been changed in - // the copy is synonymous to the corresponding element in the original - // composite which has id |message_.composite_id|. For every index that is a - // prefix of |index|, the components different from the one that - // contains the inserted object are synonymous with corresponding - // elements in the original composite. - - // If |composite_id| is irrelevant then don't add any synonyms. - if (transformation_context->GetFactManager()->IdIsIrrelevant( - message_.composite_id())) { - return; - } - uint32_t current_node_type_id = composite_type_id; - std::vector current_index; - - for (uint32_t current_level = 0; current_level < index.size(); - current_level++) { - auto current_node_type_inst = - ir_context->get_def_use_mgr()->GetDef(current_node_type_id); - uint32_t index_to_skip = index[current_level]; - uint32_t num_of_components = fuzzerutil::GetBoundForCompositeIndex( - *current_node_type_inst, ir_context); - - // Update the current_node_type_id. - current_node_type_id = fuzzerutil::WalkOneCompositeTypeIndex( - ir_context, current_node_type_id, index_to_skip); - - for (uint32_t i = 0; i < num_of_components; i++) { - if (i == index_to_skip) { - continue; - } - current_index.push_back(i); - // TODO: (https://github.com/KhronosGroup/SPIRV-Tools/issues/3659) - // Google C++ guide restricts the use of r-value references. - // https://google.github.io/styleguide/cppguide.html#Rvalue_references - // Consider changing the signature of MakeDataDescriptor() - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(message_.fresh_id(), - std::vector(current_index)), - MakeDataDescriptor(message_.composite_id(), - std::vector(current_index)), - ir_context); - current_index.pop_back(); - } - // Store the prefix of the |index|. - current_index.push_back(index[current_level]); - } - // The element which has been changed is synonymous to the found object - // itself. Add this fact only if |object_id| is not irrelevant. - if (!transformation_context->GetFactManager()->IdIsIrrelevant( - message_.object_id())) { - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(message_.object_id(), {}), - MakeDataDescriptor(message_.fresh_id(), std::vector(index)), - ir_context); - } -} - -protobufs::Transformation TransformationCompositeInsert::ToMessage() const { - protobufs::Transformation result; - *result.mutable_composite_insert() = message_; - return result; -} - -bool TransformationCompositeInsert::IsCompositeInstructionSupported( - opt::IRContext* ir_context, opt::Instruction* instruction) { - if (instruction == nullptr) { - return false; - } - if (instruction->result_id() == 0 || instruction->type_id() == 0) { - return false; - } - auto composite_type = - ir_context->get_type_mgr()->GetType(instruction->type_id()); - if (!fuzzerutil::IsCompositeType(composite_type)) { - return false; - } - - // Empty composites are not supported. - auto instruction_type_inst = - ir_context->get_def_use_mgr()->GetDef(instruction->type_id()); - if (fuzzerutil::GetBoundForCompositeIndex(*instruction_type_inst, - ir_context) == 0) { - return false; - } - return true; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_insert.h b/3rdparty/spirv-tools/source/fuzz/transformation_composite_insert.h deleted file mode 100644 index c4ea9e4c9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_composite_insert.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_TRANSFORMATION_COMPOSITE_INSERT_H -#define SPIRV_TOOLS_TRANSFORMATION_COMPOSITE_INSERT_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 TransformationCompositeInsert : public Transformation { - public: - explicit TransformationCompositeInsert( - const protobufs::TransformationCompositeInsert& message); - - TransformationCompositeInsert( - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id, uint32_t composite_id, uint32_t object_id, - const std::vector& index); - - // - |message_.fresh_id| must be fresh. - // - |message_.composite_id| must refer to an existing composite value. - // - |message_.index| must refer to a correct index in the composite. - // - The type id of the object and the type id of the component of the - // composite at index |message_.index| must be the same. - // - |message_.instruction_to_insert_before| must refer to a defined - // instruction. - // - It must be possible to insert OpCompositeInsert before - // |instruction_to_insert_before|. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an instruction OpCompositeInsert before - // |instruction_to_insert_before|, which creates a new composite from - // |composite_id| by inserting |object_id| at the specified |index|. - // Synonyms are created between those components which are identical in the - // original and the modified composite and between the inserted object and its - // copy in the modified composite. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Checks if |instruction| is a instruction of a composite type supported by - // this transformation. - static bool IsCompositeInstructionSupported(opt::IRContext* ir_context, - opt::Instruction* instruction); - - private: - protobufs::TransformationCompositeInsert message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_TRANSFORMATION_COMPOSITE_INSERT_H diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_compute_data_synonym_fact_closure.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_compute_data_synonym_fact_closure.cpp deleted file mode 100644 index ff3ba3c6d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_compute_data_synonym_fact_closure.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_compute_data_synonym_fact_closure.h" - -namespace spvtools { -namespace fuzz { - -TransformationComputeDataSynonymFactClosure:: - TransformationComputeDataSynonymFactClosure( - const spvtools::fuzz::protobufs:: - TransformationComputeDataSynonymFactClosure& message) - : message_(message) {} - -TransformationComputeDataSynonymFactClosure:: - TransformationComputeDataSynonymFactClosure( - uint32_t maximum_equivalence_class_size) { - message_.set_maximum_equivalence_class_size(maximum_equivalence_class_size); -} - -bool TransformationComputeDataSynonymFactClosure::IsApplicable( - opt::IRContext* /*unused*/, const TransformationContext& /*unused*/) const { - return true; -} - -void TransformationComputeDataSynonymFactClosure::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - transformation_context->GetFactManager()->ComputeClosureOfFacts( - ir_context, message_.maximum_equivalence_class_size()); -} - -protobufs::Transformation -TransformationComputeDataSynonymFactClosure::ToMessage() const { - protobufs::Transformation result; - *result.mutable_compute_data_synonym_fact_closure() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_compute_data_synonym_fact_closure.h b/3rdparty/spirv-tools/source/fuzz/transformation_compute_data_synonym_fact_closure.h deleted file mode 100644 index eab43ffe4..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_compute_data_synonym_fact_closure.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_COMPUTE_DATA_SYNONYM_FACT_CLOSURE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_COMPUTE_DATA_SYNONYM_FACT_CLOSURE_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 TransformationComputeDataSynonymFactClosure : public Transformation { - public: - explicit TransformationComputeDataSynonymFactClosure( - const protobufs::TransformationComputeDataSynonymFactClosure& message); - - explicit TransformationComputeDataSynonymFactClosure( - uint32_t maximum_equivalence_class_size); - - // This transformation is trivially applicable. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Forces the fact manager to compute a closure of data synonym facts, so that - // facts implied by existing facts are deduced. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationComputeDataSynonymFactClosure message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_COMPUTE_DATA_SYNONYM_FACT_CLOSURE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_context.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_context.cpp deleted file mode 100644 index bd0e40641..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_context.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_context.h" - -#include - -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { -namespace { - -// An overflow id source that should never be used: its methods assert false. -// This is the right id source for use during fuzzing, when overflow ids should -// never be required. -class NullOverflowIdSource : public OverflowIdSource { - bool HasOverflowIds() const override { - assert(false && "Bad attempt to query whether overflow ids are available."); - return false; - } - - uint32_t GetNextOverflowId() override { - assert(false && "Bad attempt to request an overflow id."); - return 0; - } -}; - -} // namespace - -TransformationContext::TransformationContext( - FactManager* fact_manager, spv_validator_options validator_options) - : fact_manager_(fact_manager), - validator_options_(validator_options), - overflow_id_source_(MakeUnique()) {} - -TransformationContext::TransformationContext( - FactManager* fact_manager, spv_validator_options validator_options, - std::unique_ptr overflow_id_source) - : fact_manager_(fact_manager), - validator_options_(validator_options), - overflow_id_source_(std::move(overflow_id_source)) {} - -TransformationContext::~TransformationContext() = default; - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_context.h b/3rdparty/spirv-tools/source/fuzz/transformation_context.h deleted file mode 100644 index c76a7bef8..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_context.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_CONTEXT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_CONTEXT_H_ - -#include - -#include "source/fuzz/fact_manager/fact_manager.h" -#include "source/fuzz/overflow_id_source.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace fuzz { - -// Encapsulates all information that is required to inform how to apply a -// transformation to a module. -class TransformationContext { - public: - // Constructs a transformation context with a given fact manager and validator - // options. Overflow ids are not available from a transformation context - // constructed in this way. - TransformationContext(FactManager* fact_manager, - spv_validator_options validator_options); - - // Constructs a transformation context with a given fact manager, validator - // options and overflow id source. - TransformationContext(FactManager* fact_manager, - spv_validator_options validator_options, - std::unique_ptr overflow_id_source); - - ~TransformationContext(); - - FactManager* GetFactManager() { return fact_manager_; } - - const FactManager* GetFactManager() const { return fact_manager_; } - - OverflowIdSource* GetOverflowIdSource() { return overflow_id_source_.get(); } - - const OverflowIdSource* GetOverflowIdSource() const { - return overflow_id_source_.get(); - } - - spv_validator_options GetValidatorOptions() const { - return validator_options_; - } - - private: - // Manages facts that inform whether transformations can be applied, and that - // are produced by applying transformations. - FactManager* fact_manager_; - - // Options to control validation when deciding whether transformations can be - // applied. - spv_validator_options validator_options_; - - std::unique_ptr overflow_id_source_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_CONTEXT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_equation_instruction.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_equation_instruction.cpp deleted file mode 100644 index e27cd2970..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_equation_instruction.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_equation_instruction.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationEquationInstruction::TransformationEquationInstruction( - const spvtools::fuzz::protobufs::TransformationEquationInstruction& message) - : message_(message) {} - -TransformationEquationInstruction::TransformationEquationInstruction( - uint32_t fresh_id, SpvOp opcode, const std::vector& in_operand_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before) { - message_.set_fresh_id(fresh_id); - message_.set_opcode(opcode); - for (auto id : in_operand_id) { - message_.add_in_operand_id(id); - } - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; -} - -bool TransformationEquationInstruction::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // The result id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // The instruction to insert before must exist. - auto insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - if (!insert_before) { - return false; - } - // The input ids must all exist, not be OpUndef, and be available before this - // instruction. - for (auto id : message_.in_operand_id()) { - auto inst = ir_context->get_def_use_mgr()->GetDef(id); - if (!inst) { - return false; - } - if (inst->opcode() == SpvOpUndef) { - return false; - } - if (transformation_context.GetFactManager()->IdIsIrrelevant(id)) { - return false; - } - if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, - id)) { - return false; - } - } - - return MaybeGetResultTypeId(ir_context) != 0; -} - -void TransformationEquationInstruction::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - opt::Instruction::OperandList in_operands; - std::vector rhs_id; - for (auto id : message_.in_operand_id()) { - in_operands.push_back({SPV_OPERAND_TYPE_ID, {id}}); - rhs_id.push_back(id); - } - - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, static_cast(message_.opcode()), - MaybeGetResultTypeId(ir_context), message_.fresh_id(), - std::move(in_operands))); - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - - transformation_context->GetFactManager()->AddFactIdEquation( - message_.fresh_id(), static_cast(message_.opcode()), rhs_id, - ir_context); -} - -protobufs::Transformation TransformationEquationInstruction::ToMessage() const { - protobufs::Transformation result; - *result.mutable_equation_instruction() = message_; - return result; -} - -uint32_t TransformationEquationInstruction::MaybeGetResultTypeId( - opt::IRContext* ir_context) const { - auto opcode = static_cast(message_.opcode()); - switch (opcode) { - case SpvOpConvertUToF: - case SpvOpConvertSToF: { - if (message_.in_operand_id_size() != 1) { - return 0; - } - - const auto* type = ir_context->get_type_mgr()->GetType( - fuzzerutil::GetTypeId(ir_context, message_.in_operand_id(0))); - if (!type) { - return 0; - } - - if (const auto* vector = type->AsVector()) { - if (!vector->element_type()->AsInteger()) { - return 0; - } - - if (auto element_type_id = fuzzerutil::MaybeGetFloatType( - ir_context, vector->element_type()->AsInteger()->width())) { - return fuzzerutil::MaybeGetVectorType(ir_context, element_type_id, - vector->element_count()); - } - - return 0; - } else { - if (!type->AsInteger()) { - return 0; - } - - return fuzzerutil::MaybeGetFloatType(ir_context, - type->AsInteger()->width()); - } - } - case SpvOpBitcast: { - if (message_.in_operand_id_size() != 1) { - return 0; - } - - const auto* operand_inst = - ir_context->get_def_use_mgr()->GetDef(message_.in_operand_id(0)); - if (!operand_inst) { - return 0; - } - - const auto* operand_type = - ir_context->get_type_mgr()->GetType(operand_inst->type_id()); - if (!operand_type) { - return 0; - } - - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3539): - // The only constraint on the types of OpBitcast's parameters is that - // they must have the same number of bits. Consider improving the code - // below to support this in full. - if (const auto* vector = operand_type->AsVector()) { - uint32_t component_type_id; - if (const auto* int_type = vector->element_type()->AsInteger()) { - component_type_id = - fuzzerutil::MaybeGetFloatType(ir_context, int_type->width()); - } else if (const auto* float_type = vector->element_type()->AsFloat()) { - component_type_id = fuzzerutil::MaybeGetIntegerType( - ir_context, float_type->width(), true); - if (component_type_id == 0 || - fuzzerutil::MaybeGetVectorType(ir_context, component_type_id, - vector->element_count()) == 0) { - component_type_id = fuzzerutil::MaybeGetIntegerType( - ir_context, float_type->width(), false); - } - } else { - assert(false && "Only vectors of numerical components are supported"); - return 0; - } - - if (component_type_id == 0) { - return 0; - } - - return fuzzerutil::MaybeGetVectorType(ir_context, component_type_id, - vector->element_count()); - } else if (const auto* int_type = operand_type->AsInteger()) { - return fuzzerutil::MaybeGetFloatType(ir_context, int_type->width()); - } else if (const auto* float_type = operand_type->AsFloat()) { - if (auto existing_id = fuzzerutil::MaybeGetIntegerType( - ir_context, float_type->width(), true)) { - return existing_id; - } - - return fuzzerutil::MaybeGetIntegerType(ir_context, float_type->width(), - false); - } else { - assert(false && - "Operand is not a scalar or a vector of numerical type"); - return 0; - } - } - case SpvOpIAdd: - case SpvOpISub: { - if (message_.in_operand_id_size() != 2) { - return 0; - } - uint32_t first_operand_width = 0; - uint32_t first_operand_type_id = 0; - for (uint32_t index = 0; index < 2; index++) { - auto operand_inst = ir_context->get_def_use_mgr()->GetDef( - message_.in_operand_id(index)); - if (!operand_inst || !operand_inst->type_id()) { - return 0; - } - auto operand_type = - ir_context->get_type_mgr()->GetType(operand_inst->type_id()); - if (!(operand_type->AsInteger() || - (operand_type->AsVector() && - operand_type->AsVector()->element_type()->AsInteger()))) { - return 0; - } - uint32_t operand_width = - operand_type->AsInteger() - ? 1 - : operand_type->AsVector()->element_count(); - if (index == 0) { - first_operand_width = operand_width; - first_operand_type_id = operand_inst->type_id(); - } else { - assert(first_operand_width != 0 && - "The first operand should have been processed."); - if (operand_width != first_operand_width) { - return 0; - } - } - } - assert(first_operand_type_id != 0 && - "A type must have been found for the first operand."); - return first_operand_type_id; - } - case SpvOpLogicalNot: { - if (message_.in_operand_id().size() != 1) { - return 0; - } - auto operand_inst = - ir_context->get_def_use_mgr()->GetDef(message_.in_operand_id(0)); - if (!operand_inst || !operand_inst->type_id()) { - return 0; - } - auto operand_type = - ir_context->get_type_mgr()->GetType(operand_inst->type_id()); - if (!(operand_type->AsBool() || - (operand_type->AsVector() && - operand_type->AsVector()->element_type()->AsBool()))) { - return 0; - } - return operand_inst->type_id(); - } - case SpvOpSNegate: { - if (message_.in_operand_id().size() != 1) { - return 0; - } - auto operand_inst = - ir_context->get_def_use_mgr()->GetDef(message_.in_operand_id(0)); - if (!operand_inst || !operand_inst->type_id()) { - return 0; - } - auto operand_type = - ir_context->get_type_mgr()->GetType(operand_inst->type_id()); - if (!(operand_type->AsInteger() || - (operand_type->AsVector() && - operand_type->AsVector()->element_type()->AsInteger()))) { - return 0; - } - return operand_inst->type_id(); - } - default: - assert(false && "Inappropriate opcode for equation instruction."); - return 0; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_equation_instruction.h b/3rdparty/spirv-tools/source/fuzz/transformation_equation_instruction.h deleted file mode 100644 index 9ed01a87a..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_equation_instruction.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_EQUATION_INSTRUCTION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_EQUATION_INSTRUCTION_H_ - -#include - -#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 TransformationEquationInstruction : public Transformation { - public: - explicit TransformationEquationInstruction( - const protobufs::TransformationEquationInstruction& message); - - TransformationEquationInstruction( - uint32_t fresh_id, SpvOp opcode, - const std::vector& in_operand_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before); - - // - |message_.fresh_id| must be fresh. - // - |message_.instruction_to_insert_before| must identify an instruction - // before which an equation instruction can legitimately be inserted. - // - Each id in |message_.in_operand_id| must exist, not be an OpUndef, and - // be available before |message_.instruction_to_insert_before|. - // - |message_.opcode| must be an opcode for which we know how to handle - // equations, the types of the ids in |message_.in_operand_id| must be - // suitable for use with this opcode, and the module must contain an - // appropriate result type id. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an instruction to the module, right before - // |message_.instruction_to_insert_before|, of the form: - // - // |message_.fresh_id| = |message_.opcode| %type |message_.in_operand_ids| - // - // where %type is a type id that already exists in the module and that is - // compatible with the opcode and input operands. - // - // The fact manager is also updated to inform it of this equation fact. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Returns type id for the equation instruction. Returns 0 if result type does - // not exist. - uint32_t MaybeGetResultTypeId(opt::IRContext* ir_context) const; - - protobufs::TransformationEquationInstruction message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_EQUATION_INSTRUCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_function_call.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_function_call.cpp deleted file mode 100644 index 432634d38..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_function_call.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_function_call.h" - -#include "source/fuzz/call_graph.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationFunctionCall::TransformationFunctionCall( - const spvtools::fuzz::protobufs::TransformationFunctionCall& message) - : message_(message) {} - -TransformationFunctionCall::TransformationFunctionCall( - uint32_t fresh_id, uint32_t callee_id, - const std::vector& argument_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before) { - message_.set_fresh_id(fresh_id); - message_.set_callee_id(callee_id); - for (auto argument : argument_id) { - message_.add_argument_id(argument); - } - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; -} - -bool TransformationFunctionCall::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // The result id must be fresh - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // The function must exist - auto callee_inst = - ir_context->get_def_use_mgr()->GetDef(message_.callee_id()); - if (!callee_inst || callee_inst->opcode() != SpvOpFunction) { - return false; - } - - // The function must not be an entry point - if (fuzzerutil::FunctionIsEntryPoint(ir_context, message_.callee_id())) { - return false; - } - - auto callee_type_inst = ir_context->get_def_use_mgr()->GetDef( - callee_inst->GetSingleWordInOperand(1)); - assert(callee_type_inst->opcode() == SpvOpTypeFunction && - "Bad function type."); - - // The number of expected function arguments must match the number of given - // arguments. The number of expected arguments is one less than the function - // type's number of input operands, as one operand is for the return type. - if (callee_type_inst->NumInOperands() - 1 != - static_cast(message_.argument_id().size())) { - return false; - } - - // The instruction descriptor must refer to a position where it is valid to - // insert the call - auto insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - if (!insert_before) { - return false; - } - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpFunctionCall, - insert_before)) { - return false; - } - - auto block = ir_context->get_instr_block(insert_before); - auto enclosing_function = block->GetParent(); - - // If the block is not dead, the function must be livesafe - bool block_is_dead = - transformation_context.GetFactManager()->BlockIsDead(block->id()); - if (!block_is_dead && - !transformation_context.GetFactManager()->FunctionIsLivesafe( - message_.callee_id())) { - return false; - } - - // The ids must all match and have the right types and satisfy rules on - // pointers. If the block is not dead, pointers must be arbitrary. - for (uint32_t arg_index = 0; - arg_index < static_cast(message_.argument_id().size()); - arg_index++) { - opt::Instruction* arg_inst = - ir_context->get_def_use_mgr()->GetDef(message_.argument_id(arg_index)); - if (!arg_inst) { - // The given argument does not correspond to an instruction. - return false; - } - if (!arg_inst->type_id()) { - // The given argument does not have a type; it is thus not suitable. - } - if (arg_inst->type_id() != - callee_type_inst->GetSingleWordInOperand(arg_index + 1)) { - // Argument type mismatch. - return false; - } - opt::Instruction* arg_type_inst = - ir_context->get_def_use_mgr()->GetDef(arg_inst->type_id()); - if (arg_type_inst->opcode() == SpvOpTypePointer) { - switch (arg_inst->opcode()) { - case SpvOpFunctionParameter: - case SpvOpVariable: - // These are OK - break; - default: - // Other pointer ids cannot be passed as parameters - return false; - } - if (!block_is_dead && - !transformation_context.GetFactManager()->PointeeValueIsIrrelevant( - arg_inst->result_id())) { - // This is not a dead block, so pointer parameters passed to the called - // function might really have their contents modified. We thus require - // such pointers to be to arbitrary-valued variables, which this is not. - return false; - } - } - - // The argument id needs to be available (according to dominance rules) at - // the point where the call will occur. - if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, - arg_inst->result_id())) { - return false; - } - } - - // Introducing the call must not lead to recursion. - if (message_.callee_id() == enclosing_function->result_id()) { - // This would be direct recursion. - return false; - } - // Ensure the call would not lead to indirect recursion. - return !CallGraph(ir_context) - .GetIndirectCallees(message_.callee_id()) - .count(block->GetParent()->result_id()); -} - -void TransformationFunctionCall::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Update the module's bound to reflect the fresh id for the result of the - // function call. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // Get the return type of the function being called. - uint32_t return_type = - ir_context->get_def_use_mgr()->GetDef(message_.callee_id())->type_id(); - // Populate the operands to the call instruction, with the function id and the - // arguments. - opt::Instruction::OperandList operands; - operands.push_back({SPV_OPERAND_TYPE_ID, {message_.callee_id()}}); - for (auto arg : message_.argument_id()) { - operands.push_back({SPV_OPERAND_TYPE_ID, {arg}}); - } - // Insert the function call before the instruction specified in the message. - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpFunctionCall, return_type, message_.fresh_id(), - operands)); - // Invalidate all analyses since we have changed the module. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationFunctionCall::ToMessage() const { - protobufs::Transformation result; - *result.mutable_function_call() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_function_call.h b/3rdparty/spirv-tools/source/fuzz/transformation_function_call.h deleted file mode 100644 index 4ad7db13d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_function_call.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_FUNCTION_CALL_H_ -#define SOURCE_FUZZ_TRANSFORMATION_FUNCTION_CALL_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 TransformationFunctionCall : public Transformation { - public: - explicit TransformationFunctionCall( - const protobufs::TransformationFunctionCall& message); - - TransformationFunctionCall( - uint32_t fresh_id, uint32_t callee_id, - const std::vector& argument_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before); - - // - |message_.fresh_id| must be fresh - // - |message_.instruction_to_insert_before| must identify an instruction - // before which an OpFunctionCall can be legitimately inserted - // - |message_.function_id| must be the id of a function, and calling the - // function before the identified instruction must not introduce recursion - // - |message_.arg_id| must provide suitable arguments for the function call - // (they must have the right types and be available according to dominance - // rules) - // - If the insertion point is not in a dead block then |message_function_id| - // must refer to a livesafe function, and every pointer argument in - // |message_.arg_id| must refer to an arbitrary-valued variable - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an instruction of the form: - // |fresh_id| = OpFunctionCall %type |callee_id| |arg_id...| - // before |instruction_to_insert_before|, where %type is the return type of - // |callee_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationFunctionCall message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_FUNCTION_CALL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_inline_function.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_inline_function.cpp deleted file mode 100644 index f244f0d87..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_inline_function.cpp +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_inline_function.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationInlineFunction::TransformationInlineFunction( - const spvtools::fuzz::protobufs::TransformationInlineFunction& message) - : message_(message) {} - -TransformationInlineFunction::TransformationInlineFunction( - uint32_t function_call_id, - const std::map& result_id_map) { - message_.set_function_call_id(function_call_id); - *message_.mutable_result_id_map() = - fuzzerutil::MapToRepeatedUInt32Pair(result_id_map); -} - -bool TransformationInlineFunction::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The values in the |message_.result_id_map| must be all fresh and all - // distinct. - const auto result_id_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.result_id_map()); - std::set ids_used_by_this_transformation; - for (auto& pair : result_id_map) { - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - pair.second, ir_context, &ids_used_by_this_transformation)) { - return false; - } - } - - // |function_call_instruction| must be suitable for inlining. - auto* function_call_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.function_call_id()); - if (!IsSuitableForInlining(ir_context, function_call_instruction)) { - return false; - } - - // |function_call_instruction| must be the penultimate instruction in its - // block and its block termination instruction must be an OpBranch. This - // avoids the case where the penultimate instruction is an OpLoopMerge, which - // would make the back-edge block not branch to the loop header. - auto* function_call_instruction_block = - ir_context->get_instr_block(function_call_instruction); - if (function_call_instruction != - &*--function_call_instruction_block->tail() || - function_call_instruction_block->terminator()->opcode() != SpvOpBranch) { - return false; - } - - auto* called_function = fuzzerutil::FindFunction( - ir_context, function_call_instruction->GetSingleWordInOperand(0)); - for (auto& block : *called_function) { - // Since the entry block label will not be inlined, only the remaining - // labels must have a corresponding value in the map. - if (&block != &*called_function->entry() && - !result_id_map.count(block.GetLabel()->result_id())) { - return false; - } - - // |result_id_map| must have an entry for every result id in the called - // function. - for (auto& instruction : block) { - // If |instruction| has result id, then it must have a mapped id in - // |result_id_map|. - if (instruction.HasResultId() && - !result_id_map.count(instruction.result_id())) { - return false; - } - } - } - - // |result_id_map| must not contain an entry for any parameter of the function - // that is being inlined. - bool found_entry_for_parameter = false; - called_function->ForEachParam( - [&result_id_map, &found_entry_for_parameter](opt::Instruction* param) { - if (result_id_map.count(param->result_id())) { - found_entry_for_parameter = true; - } - }); - return !found_entry_for_parameter; -} - -void TransformationInlineFunction::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto* function_call_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.function_call_id()); - auto* caller_function = - ir_context->get_instr_block(function_call_instruction)->GetParent(); - auto* called_function = fuzzerutil::FindFunction( - ir_context, function_call_instruction->GetSingleWordInOperand(0)); - const auto result_id_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.result_id_map()); - auto* successor_block = ir_context->cfg()->block( - ir_context->get_instr_block(function_call_instruction) - ->terminator() - ->GetSingleWordInOperand(0)); - - // Inline the |called_function| entry block. - for (auto& entry_block_instruction : *called_function->entry()) { - opt::Instruction* inlined_instruction = nullptr; - - if (entry_block_instruction.opcode() == SpvOpVariable) { - // All OpVariable instructions in a function must be in the first block - // in the function. - inlined_instruction = caller_function->begin()->begin()->InsertBefore( - MakeUnique(entry_block_instruction)); - } else { - inlined_instruction = function_call_instruction->InsertBefore( - MakeUnique(entry_block_instruction)); - } - - AdaptInlinedInstruction(ir_context, inlined_instruction); - } - - // Inline the |called_function| non-entry blocks. - for (auto& block : *called_function) { - if (&block == &*called_function->entry()) { - continue; - } - - auto* cloned_block = block.Clone(ir_context); - cloned_block = caller_function->InsertBasicBlockBefore( - std::unique_ptr(cloned_block), successor_block); - cloned_block->SetParent(caller_function); - cloned_block->GetLabel()->SetResultId( - result_id_map.at(cloned_block->GetLabel()->result_id())); - fuzzerutil::UpdateModuleIdBound(ir_context, - cloned_block->GetLabel()->result_id()); - - for (auto& inlined_instruction : *cloned_block) { - AdaptInlinedInstruction(ir_context, &inlined_instruction); - } - } - - // Removes the function call instruction and its block termination instruction - // from |caller_function|. - ir_context->KillInst( - ir_context->get_instr_block(function_call_instruction)->terminator()); - ir_context->KillInst(function_call_instruction); - - // Since the SPIR-V module has changed, no analyses must be validated. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationInlineFunction::ToMessage() const { - protobufs::Transformation result; - *result.mutable_inline_function() = message_; - return result; -} - -bool TransformationInlineFunction::IsSuitableForInlining( - opt::IRContext* ir_context, opt::Instruction* function_call_instruction) { - // |function_call_instruction| must be defined and must be an OpFunctionCall - // instruction. - if (!function_call_instruction || - function_call_instruction->opcode() != SpvOpFunctionCall) { - return false; - } - - // If |function_call_instruction| return type is void, then - // |function_call_instruction| must not have uses. - if (ir_context->get_type_mgr() - ->GetType(function_call_instruction->type_id()) - ->AsVoid() && - ir_context->get_def_use_mgr()->NumUses(function_call_instruction) != 0) { - return false; - } - - // |called_function| must not have an early return. - auto called_function = fuzzerutil::FindFunction( - ir_context, function_call_instruction->GetSingleWordInOperand(0)); - if (called_function->HasEarlyReturn()) { - return false; - } - - // |called_function| must not use OpKill or OpUnreachable. - if (fuzzerutil::FunctionContainsOpKillOrUnreachable(*called_function)) { - return false; - } - - return true; -} - -void TransformationInlineFunction::AdaptInlinedInstruction( - opt::IRContext* ir_context, - opt::Instruction* instruction_to_be_inlined) const { - auto* function_call_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.function_call_id()); - auto* called_function = fuzzerutil::FindFunction( - ir_context, function_call_instruction->GetSingleWordInOperand(0)); - const auto result_id_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.result_id_map()); - - // Replaces the operand ids with their mapped result ids. - instruction_to_be_inlined->ForEachInId([called_function, - function_call_instruction, - &result_id_map](uint32_t* id) { - // If |id| is mapped, then set it to its mapped value. - if (result_id_map.count(*id)) { - *id = result_id_map.at(*id); - return; - } - - uint32_t parameter_index = 0; - called_function->ForEachParam( - [id, function_call_instruction, - ¶meter_index](opt::Instruction* parameter_instruction) { - // If the id is a function parameter, then set it to the - // parameter value passed in the function call instruction. - if (*id == parameter_instruction->result_id()) { - // We do + 1 because the first in-operand for OpFunctionCall is - // the function id that is being called. - *id = function_call_instruction->GetSingleWordInOperand( - parameter_index + 1); - } - parameter_index++; - }); - }); - - // If |instruction_to_be_inlined| has result id, then set it to its mapped - // value. - if (instruction_to_be_inlined->HasResultId()) { - assert(result_id_map.count(instruction_to_be_inlined->result_id()) && - "Result id must be mapped to a fresh id."); - instruction_to_be_inlined->SetResultId( - result_id_map.at(instruction_to_be_inlined->result_id())); - fuzzerutil::UpdateModuleIdBound(ir_context, - instruction_to_be_inlined->result_id()); - } - - // The return instruction will be changed into an OpBranch to the basic - // block that follows the block containing the function call. - if (spvOpcodeIsReturn(instruction_to_be_inlined->opcode())) { - uint32_t successor_block_id = - ir_context->get_instr_block(function_call_instruction) - ->terminator() - ->GetSingleWordInOperand(0); - switch (instruction_to_be_inlined->opcode()) { - case SpvOpReturn: - instruction_to_be_inlined->AddOperand( - {SPV_OPERAND_TYPE_ID, {successor_block_id}}); - break; - case SpvOpReturnValue: { - instruction_to_be_inlined->InsertBefore(MakeUnique( - ir_context, SpvOpCopyObject, function_call_instruction->type_id(), - function_call_instruction->result_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, - {instruction_to_be_inlined->GetSingleWordOperand(0)}}}))); - instruction_to_be_inlined->SetInOperand(0, {successor_block_id}); - break; - } - default: - break; - } - instruction_to_be_inlined->SetOpcode(SpvOpBranch); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_inline_function.h b/3rdparty/spirv-tools/source/fuzz/transformation_inline_function.h deleted file mode 100644 index 29a9ea6fb..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_inline_function.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_INLINE_FUNCTION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_INLINE_FUNCTION_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 TransformationInlineFunction : public Transformation { - public: - explicit TransformationInlineFunction( - const protobufs::TransformationInlineFunction& message); - - TransformationInlineFunction( - uint32_t function_call_id, - const std::map& result_id_map); - - // - |message_.result_id_map| must map the instructions of the called function - // to fresh ids. - // - |message_.function_call_id| must be an OpFunctionCall instruction. - // It must not have an early return and must not use OpUnreachable or - // OpKill. This is to guard against making the module invalid when the - // caller is inside a continue construct. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3735): - // Allow functions that use OpKill or OpUnreachable to be inlined if the - // function call is not part of a continue construct. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces the OpFunctionCall instruction, identified by - // |message_.function_call_id|, with a copy of the function's body. - // |message_.result_id_map| is used to provide fresh ids for duplicate - // instructions. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if |function_call_instruction| is defined, is an - // OpFunctionCall instruction, has no uses if its return type is void, has no - // early returns and has no uses of OpKill or OpUnreachable. - static bool IsSuitableForInlining( - opt::IRContext* ir_context, opt::Instruction* function_call_instruction); - - private: - protobufs::TransformationInlineFunction message_; - - // Inline |instruction_to_be_inlined| by setting its ids to the corresponding - // ids in |result_id_map|. - void AdaptInlinedInstruction(opt::IRContext* ir_context, - opt::Instruction* instruction) const; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_INLINE_FUNCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.cpp deleted file mode 100644 index a4e6d8b0c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_invert_comparison_operator.h" - -#include - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationInvertComparisonOperator::TransformationInvertComparisonOperator( - protobufs::TransformationInvertComparisonOperator message) - : message_(std::move(message)) {} - -TransformationInvertComparisonOperator::TransformationInvertComparisonOperator( - uint32_t operator_id, uint32_t fresh_id) { - message_.set_operator_id(operator_id); - message_.set_fresh_id(fresh_id); -} - -bool TransformationInvertComparisonOperator::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |message_.operator_id| must be valid and inversion must be supported for - // it. - auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.operator_id()); - if (!inst || !IsInversionSupported(inst->opcode())) { - return false; - } - - // Check that we can insert negation instruction. - auto* block = ir_context->get_instr_block(inst); - assert(block && "Instruction must have a basic block"); - - auto iter = fuzzerutil::GetIteratorForInstruction(block, inst); - ++iter; - assert(iter != block->end() && "Instruction can't be the last in the block"); - assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLogicalNot, iter) && - "Can't insert negation after comparison operator"); - - // |message_.fresh_id| must be fresh. - return fuzzerutil::IsFreshId(ir_context, message_.fresh_id()); -} - -void TransformationInvertComparisonOperator::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.operator_id()); - assert(inst && "Result id of an operator is invalid"); - - // Insert negation after |inst|. - auto iter = fuzzerutil::GetIteratorForInstruction( - ir_context->get_instr_block(inst), inst); - ++iter; - - iter.InsertBefore(MakeUnique( - ir_context, SpvOpLogicalNot, inst->type_id(), inst->result_id(), - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}})); - - // Change the result id of the original operator to |fresh_id|. - inst->SetResultId(message_.fresh_id()); - - // Invert the operator. - inst->SetOpcode(InvertOpcode(inst->opcode())); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -bool TransformationInvertComparisonOperator::IsInversionSupported( - SpvOp opcode) { - switch (opcode) { - case SpvOpSGreaterThan: - case SpvOpSGreaterThanEqual: - case SpvOpSLessThan: - case SpvOpSLessThanEqual: - case SpvOpUGreaterThan: - case SpvOpUGreaterThanEqual: - case SpvOpULessThan: - case SpvOpULessThanEqual: - case SpvOpIEqual: - case SpvOpINotEqual: - case SpvOpFOrdEqual: - case SpvOpFUnordEqual: - case SpvOpFOrdNotEqual: - case SpvOpFUnordNotEqual: - case SpvOpFOrdLessThan: - case SpvOpFUnordLessThan: - case SpvOpFOrdLessThanEqual: - case SpvOpFUnordLessThanEqual: - case SpvOpFOrdGreaterThan: - case SpvOpFUnordGreaterThan: - case SpvOpFOrdGreaterThanEqual: - case SpvOpFUnordGreaterThanEqual: - return true; - default: - return false; - } -} - -SpvOp TransformationInvertComparisonOperator::InvertOpcode(SpvOp opcode) { - assert(IsInversionSupported(opcode) && "Inversion must be supported"); - - switch (opcode) { - case SpvOpSGreaterThan: - return SpvOpSLessThanEqual; - case SpvOpSGreaterThanEqual: - return SpvOpSLessThan; - case SpvOpSLessThan: - return SpvOpSGreaterThanEqual; - case SpvOpSLessThanEqual: - return SpvOpSGreaterThan; - case SpvOpUGreaterThan: - return SpvOpULessThanEqual; - case SpvOpUGreaterThanEqual: - return SpvOpULessThan; - case SpvOpULessThan: - return SpvOpUGreaterThanEqual; - case SpvOpULessThanEqual: - return SpvOpUGreaterThan; - case SpvOpIEqual: - return SpvOpINotEqual; - case SpvOpINotEqual: - return SpvOpIEqual; - case SpvOpFOrdEqual: - return SpvOpFUnordNotEqual; - case SpvOpFUnordEqual: - return SpvOpFOrdNotEqual; - case SpvOpFOrdNotEqual: - return SpvOpFUnordEqual; - case SpvOpFUnordNotEqual: - return SpvOpFOrdEqual; - case SpvOpFOrdLessThan: - return SpvOpFUnordGreaterThanEqual; - case SpvOpFUnordLessThan: - return SpvOpFOrdGreaterThanEqual; - case SpvOpFOrdLessThanEqual: - return SpvOpFUnordGreaterThan; - case SpvOpFUnordLessThanEqual: - return SpvOpFOrdGreaterThan; - case SpvOpFOrdGreaterThan: - return SpvOpFUnordLessThanEqual; - case SpvOpFUnordGreaterThan: - return SpvOpFOrdLessThanEqual; - case SpvOpFOrdGreaterThanEqual: - return SpvOpFUnordLessThan; - case SpvOpFUnordGreaterThanEqual: - return SpvOpFOrdLessThan; - default: - // The program will fail in the debug mode because of the assertion - // at the beginning of the function. - return SpvOpNop; - } -} - -protobufs::Transformation TransformationInvertComparisonOperator::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_invert_comparison_operator() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.h b/3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.h deleted file mode 100644 index 9047a1489..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_INVERT_COMPARISON_OPERATOR_H_ -#define SOURCE_FUZZ_TRANSFORMATION_INVERT_COMPARISON_OPERATOR_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 TransformationInvertComparisonOperator : public Transformation { - public: - explicit TransformationInvertComparisonOperator( - protobufs::TransformationInvertComparisonOperator message); - - TransformationInvertComparisonOperator(uint32_t operator_id, - uint32_t fresh_id); - - // - |operator_id| should be a result id of some instruction for which - // IsInversionSupported returns true. - // - |fresh_id| must be a fresh id. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Inverts the opcode of the instruction with result id |operator_id| (e.g >= - // becomes <) and inserts OpLogicalNot instruction after |operator_id|. Also, - // changes the result id of OpLogicalNot to |operator_id| and the result id of - // the inverted operator to |fresh_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if |opcode| is supported by this transformation. - static bool IsInversionSupported(SpvOp opcode); - - private: - // Returns an inverted |opcode| (e.g. < becomes >=, == becomes != etc.) - static SpvOp InvertOpcode(SpvOp opcode); - - protobufs::TransformationInvertComparisonOperator message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_INVERT_COMPARISON_OPERATOR_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_load.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_load.cpp deleted file mode 100644 index a260c3358..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_load.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_load.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationLoad::TransformationLoad( - const spvtools::fuzz::protobufs::TransformationLoad& message) - : message_(message) {} - -TransformationLoad::TransformationLoad( - uint32_t fresh_id, uint32_t pointer_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before) { - message_.set_fresh_id(fresh_id); - message_.set_pointer_id(pointer_id); - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; -} - -bool TransformationLoad::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The result id must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - - // The pointer must exist and have a type. - auto pointer = ir_context->get_def_use_mgr()->GetDef(message_.pointer_id()); - if (!pointer || !pointer->type_id()) { - return false; - } - // The type must indeed be a pointer type. - auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id()); - assert(pointer_type && "Type id must be defined."); - if (pointer_type->opcode() != SpvOpTypePointer) { - return false; - } - // We do not want to allow loading from null or undefined pointers, as it is - // not clear how punishing the consequences of doing so are from a semantics - // point of view. - switch (pointer->opcode()) { - case SpvOpConstantNull: - case SpvOpUndef: - return false; - default: - break; - } - - // Determine which instruction we should be inserting before. - auto insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - // It must exist, ... - if (!insert_before) { - return false; - } - // ... and it must be legitimate to insert a store before it. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, insert_before)) { - return false; - } - - // The pointer needs to be available at the insertion point. - return fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, - message_.pointer_id()); -} - -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()); - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpLoad, result_type, message_.fresh_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}}))); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationLoad::ToMessage() const { - protobufs::Transformation result; - *result.mutable_load() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_load.h b/3rdparty/spirv-tools/source/fuzz/transformation_load.h deleted file mode 100644 index 4c7c00b6d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_load.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_LOAD_H_ -#define SOURCE_FUZZ_TRANSFORMATION_LOAD_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 TransformationLoad : public Transformation { - public: - explicit TransformationLoad(const protobufs::TransformationLoad& message); - - TransformationLoad( - uint32_t fresh_id, uint32_t pointer_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before); - - // - |message_.fresh_id| must be fresh - // - |message_.pointer_id| must be the id of a pointer - // - 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 - // |message_.pointer_id| is available (according to dominance rules) - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an instruction of the form: - // |message_.fresh_id| = OpLoad %type |message_.pointer_id| - // before the instruction identified by - // |message_.instruction_to_insert_before|, where %type is the pointer's - // pointee type. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationLoad message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_LOAD_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_make_vector_operation_dynamic.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_make_vector_operation_dynamic.cpp deleted file mode 100644 index c960676c5..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_make_vector_operation_dynamic.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_make_vector_operation_dynamic.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationMakeVectorOperationDynamic:: - TransformationMakeVectorOperationDynamic( - const spvtools::fuzz::protobufs:: - TransformationMakeVectorOperationDynamic& message) - : message_(message) {} - -TransformationMakeVectorOperationDynamic:: - TransformationMakeVectorOperationDynamic(uint32_t instruction_result_id, - uint32_t constant_index_id) { - message_.set_instruction_result_id(instruction_result_id); - message_.set_constant_index_id(constant_index_id); -} - -bool TransformationMakeVectorOperationDynamic::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |instruction| must be a vector operation. - auto instruction = - ir_context->get_def_use_mgr()->GetDef(message_.instruction_result_id()); - if (!IsVectorOperation(ir_context, instruction)) { - return false; - } - - // |constant_index_instruction| must be defined as an integer instruction. - auto constant_index_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.constant_index_id()); - if (!constant_index_instruction || !constant_index_instruction->type_id() || - !ir_context->get_type_mgr() - ->GetType(constant_index_instruction->type_id()) - ->AsInteger()) { - return false; - } - - return true; -} - -void TransformationMakeVectorOperationDynamic::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto instruction = - ir_context->get_def_use_mgr()->GetDef(message_.instruction_result_id()); - - // The OpVectorInsertDynamic instruction has the vector and component operands - // in reverse order in relation to the OpCompositeInsert corresponding - // operands. - if (instruction->opcode() == SpvOpCompositeInsert) { - std::swap(instruction->GetInOperand(0), instruction->GetInOperand(1)); - } - - // Sets the literal operand to the equivalent constant. - instruction->SetInOperand( - instruction->opcode() == SpvOpCompositeExtract ? 1 : 2, - {message_.constant_index_id()}); - - // Sets the |instruction| opcode to the corresponding vector dynamic opcode. - instruction->SetOpcode(instruction->opcode() == SpvOpCompositeExtract - ? SpvOpVectorExtractDynamic - : SpvOpVectorInsertDynamic); -} - -protobufs::Transformation TransformationMakeVectorOperationDynamic::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_make_vector_operation_dynamic() = message_; - return result; -} - -bool TransformationMakeVectorOperationDynamic::IsVectorOperation( - opt::IRContext* ir_context, opt::Instruction* instruction) { - // |instruction| must be defined and must be an OpCompositeExtract/Insert - // instruction. - if (!instruction || (instruction->opcode() != SpvOpCompositeExtract && - instruction->opcode() != SpvOpCompositeInsert)) { - return false; - } - - // The composite must be a vector. - auto composite_instruction = - ir_context->get_def_use_mgr()->GetDef(instruction->GetSingleWordInOperand( - instruction->opcode() == SpvOpCompositeExtract ? 0 : 1)); - if (!ir_context->get_type_mgr() - ->GetType(composite_instruction->type_id()) - ->AsVector()) { - return false; - } - - return true; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_make_vector_operation_dynamic.h b/3rdparty/spirv-tools/source/fuzz/transformation_make_vector_operation_dynamic.h deleted file mode 100644 index e7d17494f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_make_vector_operation_dynamic.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_MAKE_VECTOR_OPERATION_DYNAMIC_H_ -#define SOURCE_FUZZ_TRANSFORMATION_MAKE_VECTOR_OPERATION_DYNAMIC_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 TransformationMakeVectorOperationDynamic : public Transformation { - public: - explicit TransformationMakeVectorOperationDynamic( - const protobufs::TransformationMakeVectorOperationDynamic& message); - - TransformationMakeVectorOperationDynamic(uint32_t instruction_result_id, - uint32_t constant_index_id); - - // - |message_.instruction_result_id| must be the result id of an - // OpCompositeExtract/Insert instruction such that the composite operand is a - // vector. - // - |message_.constant_index_id| must be the result id of an integer - // instruction such that its value equals the indexing literal of the - // OpCompositeExtract/Insert instruction. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces the OpCompositeExtract and OpCompositeInsert instructions with the - // OpVectorExtractDynamic and OpVectorInsertDynamic instructions. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Checks |instruction| is defined, is an OpCompositeExtract/Insert - // instruction and the composite operand is a vector. - static bool IsVectorOperation(opt::IRContext* ir_context, - opt::Instruction* instruction); - - private: - protobufs::TransformationMakeVectorOperationDynamic message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_MAKE_VECTOR_OPERATION_DYNAMIC_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_merge_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_merge_blocks.cpp deleted file mode 100644 index 68ac09222..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_merge_blocks.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_merge_blocks.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/opt/block_merge_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationMergeBlocks::TransformationMergeBlocks( - const spvtools::fuzz::protobufs::TransformationMergeBlocks& message) - : message_(message) {} - -TransformationMergeBlocks::TransformationMergeBlocks(uint32_t block_id) { - message_.set_block_id(block_id); -} - -bool TransformationMergeBlocks::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - auto second_block = - fuzzerutil::MaybeFindBlock(ir_context, message_.block_id()); - // The given block must exist. - if (!second_block) { - return false; - } - // The block must have just one predecessor. - auto predecessors = ir_context->cfg()->preds(second_block->id()); - if (predecessors.size() != 1) { - return false; - } - auto first_block = ir_context->cfg()->block(predecessors.at(0)); - - return opt::blockmergeutil::CanMergeWithSuccessor(ir_context, first_block); -} - -void TransformationMergeBlocks::Apply(opt::IRContext* ir_context, - TransformationContext* /*unused*/) const { - auto second_block = - fuzzerutil::MaybeFindBlock(ir_context, message_.block_id()); - auto first_block = ir_context->cfg()->block( - ir_context->cfg()->preds(second_block->id()).at(0)); - - auto function = first_block->GetParent(); - // We need an iterator pointing to the predecessor, hence the loop. - for (auto bi = function->begin(); bi != function->end(); ++bi) { - if (bi->id() == first_block->id()) { - assert(opt::blockmergeutil::CanMergeWithSuccessor(ir_context, &*bi) && - "Because 'Apply' should only be invoked if 'IsApplicable' holds, " - "it must be possible to merge |bi| with its successor."); - opt::blockmergeutil::MergeWithSuccessor(ir_context, function, bi); - // Invalidate all analyses, since we have changed the module - // significantly. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - return; - } - } - assert(false && - "Control should not reach here - we should always find the desired " - "block"); -} - -protobufs::Transformation TransformationMergeBlocks::ToMessage() const { - protobufs::Transformation result; - *result.mutable_merge_blocks() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_merge_blocks.h b/3rdparty/spirv-tools/source/fuzz/transformation_merge_blocks.h deleted file mode 100644 index 1dc16d2f8..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_merge_blocks.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_MERGE_BLOCKS_H_ -#define SOURCE_FUZZ_TRANSFORMATION_MERGE_BLOCKS_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 TransformationMergeBlocks : public Transformation { - public: - explicit TransformationMergeBlocks( - const protobufs::TransformationMergeBlocks& message); - - TransformationMergeBlocks(uint32_t block_id); - - // - |message_.block_id| must be the id of a block, b - // - b must have a single predecessor, a - // - b must be the sole successor of a - // - Replacing a with the merge of a and b (and removing b) must lead to a - // valid module - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // The contents of b are merged into a, and a's terminator is replaced with - // the terminator of b. Block b is removed from the module. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationMergeBlocks message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_MERGE_BLOCKS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp deleted file mode 100644 index 6c71ab70b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_move_block_down.h" - -#include "source/opt/basic_block.h" - -namespace spvtools { -namespace fuzz { - -TransformationMoveBlockDown::TransformationMoveBlockDown( - const spvtools::fuzz::protobufs::TransformationMoveBlockDown& message) - : message_(message) {} - -TransformationMoveBlockDown::TransformationMoveBlockDown(uint32_t id) { - message_.set_block_id(id); -} - -bool TransformationMoveBlockDown::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Go through every block in every function, looking for a block whose id - // matches that of the block we want to consider moving down. - for (auto& function : *ir_context->module()) { - for (auto block_it = function.begin(); block_it != function.end(); - ++block_it) { - if (block_it->id() == message_.block_id()) { - // We have found a match. - if (block_it == function.begin()) { - // The block is the first one appearing in the function. We are not - // allowed to move this block down. - return false; - } - // Record the block we would like to consider moving down. - opt::BasicBlock* block_matching_id = &*block_it; - if (!ir_context->GetDominatorAnalysis(&function)->IsReachable( - block_matching_id)) { - // The block is not reachable. We are not allowed to move it down. - return false; - } - // Now see whether there is some block following that block in program - // order. - ++block_it; - if (block_it == function.end()) { - // There is no such block; i.e., the block we are considering moving - // is the last one in the function. The transformation thus does not - // apply. - return false; - } - opt::BasicBlock* next_block_in_program_order = &*block_it; - // We can move the block of interest down if and only if it does not - // dominate the block that comes next. - return !ir_context->GetDominatorAnalysis(&function)->Dominates( - block_matching_id, next_block_in_program_order); - } - } - } - - // We did not find a matching block, so the transformation is not applicable: - // there is no relevant block to move. - return false; -} - -void TransformationMoveBlockDown::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Go through every block in every function, looking for a block whose id - // matches that of the block we want to move down. - for (auto& function : *ir_context->module()) { - for (auto block_it = function.begin(); block_it != function.end(); - ++block_it) { - if (block_it->id() == message_.block_id()) { - ++block_it; - assert(block_it != function.end() && - "To be able to move a block down, it needs to have a " - "program-order successor."); - function.MoveBasicBlockToAfter(message_.block_id(), &*block_it); - // For performance, it is vital to keep the dominator analysis valid - // (which due to https://github.com/KhronosGroup/SPIRV-Tools/issues/2889 - // requires keeping the CFG analysis valid). - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisDefUse | - opt::IRContext::Analysis::kAnalysisCFG | - opt::IRContext::Analysis::kAnalysisDominatorAnalysis); - - return; - } - } - } - assert(false && "No block was found to move down."); -} - -protobufs::Transformation TransformationMoveBlockDown::ToMessage() const { - protobufs::Transformation result; - *result.mutable_move_block_down() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h b/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h deleted file mode 100644 index 7551c3822..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_H_ -#define SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_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 TransformationMoveBlockDown : public Transformation { - public: - explicit TransformationMoveBlockDown( - const protobufs::TransformationMoveBlockDown& message); - - explicit TransformationMoveBlockDown(uint32_t id); - - // - |message_.block_id| must be the id of a block b in the given module. - // - b must not be the first nor last block appearing, in program order, - // in a function. - // - b must not dominate the block that follows it in program order. - // - b must be reachable. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // The block with id |message_.block_id| is moved down; i.e. the program order - // between it and the block that follows it is swapped. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationMoveBlockDown message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_move_instruction_down.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_move_instruction_down.cpp deleted file mode 100644 index 7e383540b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_move_instruction_down.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_move_instruction_down.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationMoveInstructionDown::TransformationMoveInstructionDown( - const protobufs::TransformationMoveInstructionDown& message) - : message_(message) {} - -TransformationMoveInstructionDown::TransformationMoveInstructionDown( - const protobufs::InstructionDescriptor& instruction) { - *message_.mutable_instruction() = instruction; -} - -bool TransformationMoveInstructionDown::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |instruction| must be valid. - auto* inst = FindInstruction(message_.instruction(), ir_context); - if (!inst) { - return false; - } - - // Instruction's opcode must be supported by this transformation. - if (!IsOpcodeSupported(inst->opcode())) { - return false; - } - - auto* inst_block = ir_context->get_instr_block(inst); - assert(inst_block && - "Global instructions and function parameters are not supported"); - - auto inst_it = fuzzerutil::GetIteratorForInstruction(inst_block, inst); - assert(inst_it != inst_block->end() && - "Can't get an iterator for the instruction"); - - // |instruction| can't be the last instruction in the block. - auto successor_it = ++inst_it; - if (successor_it == inst_block->end()) { - return false; - } - - // Check that we can insert |instruction| after |inst_it|. - auto successors_successor_it = ++inst_it; - if (successors_successor_it == inst_block->end() || - !fuzzerutil::CanInsertOpcodeBeforeInstruction(inst->opcode(), - successors_successor_it)) { - return false; - } - - // Check that |instruction|'s successor doesn't depend on the |instruction|. - if (inst->result_id()) { - for (uint32_t i = 0; i < successor_it->NumInOperands(); ++i) { - const auto& operand = successor_it->GetInOperand(i); - if (operand.type == SPV_OPERAND_TYPE_ID && - operand.words[0] == inst->result_id()) { - return false; - } - } - } - - return true; -} - -void TransformationMoveInstructionDown::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto* inst = FindInstruction(message_.instruction(), ir_context); - assert(inst && - "The instruction should've been validated in the IsApplicable"); - - auto inst_it = fuzzerutil::GetIteratorForInstruction( - ir_context->get_instr_block(inst), inst); - - // Move the instruction down in the block. - inst->InsertAfter(&*++inst_it); - - ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationMoveInstructionDown::ToMessage() const { - protobufs::Transformation result; - *result.mutable_move_instruction_down() = message_; - return result; -} - -bool TransformationMoveInstructionDown::IsOpcodeSupported(SpvOp opcode) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3605): - // We only support "simple" instructions that work don't with memory. - // We should extend this so that we support the ones that modify the memory - // too. - switch (opcode) { - case SpvOpNop: - case SpvOpUndef: - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - case SpvOpArrayLength: - case SpvOpVectorExtractDynamic: - case SpvOpVectorInsertDynamic: - case SpvOpVectorShuffle: - case SpvOpCompositeConstruct: - case SpvOpCompositeExtract: - case SpvOpCompositeInsert: - case SpvOpCopyObject: - case SpvOpTranspose: - case SpvOpConvertFToU: - case SpvOpConvertFToS: - case SpvOpConvertSToF: - case SpvOpConvertUToF: - case SpvOpUConvert: - case SpvOpSConvert: - case SpvOpFConvert: - case SpvOpQuantizeToF16: - case SpvOpSatConvertSToU: - case SpvOpSatConvertUToS: - case SpvOpBitcast: - case SpvOpSNegate: - case SpvOpFNegate: - case SpvOpIAdd: - case SpvOpFAdd: - case SpvOpISub: - case SpvOpFSub: - case SpvOpIMul: - case SpvOpFMul: - case SpvOpUDiv: - case SpvOpSDiv: - case SpvOpFDiv: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSMod: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpVectorTimesScalar: - case SpvOpMatrixTimesScalar: - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - case SpvOpOuterProduct: - case SpvOpDot: - case SpvOpIAddCarry: - case SpvOpISubBorrow: - case SpvOpUMulExtended: - case SpvOpSMulExtended: - case SpvOpAny: - case SpvOpAll: - case SpvOpIsNan: - case SpvOpIsInf: - case SpvOpIsFinite: - case SpvOpIsNormal: - case SpvOpSignBitSet: - case SpvOpLessOrGreater: - case SpvOpOrdered: - case SpvOpUnordered: - case SpvOpLogicalEqual: - case SpvOpLogicalNotEqual: - case SpvOpLogicalOr: - case SpvOpLogicalAnd: - case SpvOpLogicalNot: - case SpvOpSelect: - case SpvOpIEqual: - case SpvOpINotEqual: - case SpvOpUGreaterThan: - case SpvOpSGreaterThan: - case SpvOpUGreaterThanEqual: - case SpvOpSGreaterThanEqual: - case SpvOpULessThan: - case SpvOpSLessThan: - case SpvOpULessThanEqual: - case SpvOpSLessThanEqual: - case SpvOpFOrdEqual: - case SpvOpFUnordEqual: - case SpvOpFOrdNotEqual: - case SpvOpFUnordNotEqual: - case SpvOpFOrdLessThan: - case SpvOpFUnordLessThan: - case SpvOpFOrdGreaterThan: - case SpvOpFUnordGreaterThan: - case SpvOpFOrdLessThanEqual: - case SpvOpFUnordLessThanEqual: - case SpvOpFOrdGreaterThanEqual: - case SpvOpFUnordGreaterThanEqual: - case SpvOpShiftRightLogical: - case SpvOpShiftRightArithmetic: - case SpvOpShiftLeftLogical: - case SpvOpBitwiseOr: - case SpvOpBitwiseXor: - case SpvOpBitwiseAnd: - case SpvOpNot: - case SpvOpBitFieldInsert: - case SpvOpBitFieldSExtract: - case SpvOpBitFieldUExtract: - case SpvOpBitReverse: - case SpvOpBitCount: - case SpvOpCopyLogical: - case SpvOpPtrEqual: - case SpvOpPtrNotEqual: - return true; - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_move_instruction_down.h b/3rdparty/spirv-tools/source/fuzz/transformation_move_instruction_down.h deleted file mode 100644 index 3f3c30211..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_move_instruction_down.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_H_ -#define SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_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 TransformationMoveInstructionDown : public Transformation { - public: - explicit TransformationMoveInstructionDown( - const protobufs::TransformationMoveInstructionDown& message); - - explicit TransformationMoveInstructionDown( - const protobufs::InstructionDescriptor& instruction); - - // - |instruction| should be a descriptor of a valid instruction in the module - // - |instruction|'s opcode should be supported by this transformation - // - neither |instruction| nor its successor may be the last instruction in - // the block - // - |instruction|'s successor may not be dependent on the |instruction| - // - it should be possible to insert |instruction|'s opcode after its - // successor - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Swaps |instruction| with its successor. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Returns true if the |opcode| is supported by this transformation (i.e. - // we can move an instruction with this opcode). - static bool IsOpcodeSupported(SpvOp opcode); - - protobufs::TransformationMoveInstructionDown message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp deleted file mode 100644 index 8534507a0..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.cpp +++ /dev/null @@ -1,966 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_outline_function.h" - -#include - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationOutlineFunction::TransformationOutlineFunction( - const spvtools::fuzz::protobufs::TransformationOutlineFunction& message) - : message_(message) {} - -TransformationOutlineFunction::TransformationOutlineFunction( - uint32_t entry_block, uint32_t exit_block, - uint32_t new_function_struct_return_type_id, uint32_t new_function_type_id, - uint32_t new_function_id, uint32_t new_function_region_entry_block, - uint32_t new_caller_result_id, uint32_t new_callee_result_id, - std::map&& input_id_to_fresh_id, - std::map&& output_id_to_fresh_id) { - message_.set_entry_block(entry_block); - message_.set_exit_block(exit_block); - message_.set_new_function_struct_return_type_id( - new_function_struct_return_type_id); - message_.set_new_function_type_id(new_function_type_id); - message_.set_new_function_id(new_function_id); - message_.set_new_function_region_entry_block(new_function_region_entry_block); - message_.set_new_caller_result_id(new_caller_result_id); - message_.set_new_callee_result_id(new_callee_result_id); - *message_.mutable_input_id_to_fresh_id() = - fuzzerutil::MapToRepeatedUInt32Pair(input_id_to_fresh_id); - *message_.mutable_output_id_to_fresh_id() = - fuzzerutil::MapToRepeatedUInt32Pair(output_id_to_fresh_id); -} - -bool TransformationOutlineFunction::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - std::set ids_used_by_this_transformation; - - // The various new ids used by the transformation must be fresh and distinct. - - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.new_function_struct_return_type_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.new_function_type_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.new_function_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.new_function_region_entry_block(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.new_caller_result_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - message_.new_callee_result_id(), ir_context, - &ids_used_by_this_transformation)) { - return false; - } - - for (auto& pair : message_.input_id_to_fresh_id()) { - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - pair.second(), ir_context, &ids_used_by_this_transformation)) { - return false; - } - } - - for (auto& pair : message_.output_id_to_fresh_id()) { - if (!CheckIdIsFreshAndNotUsedByThisTransformation( - pair.second(), ir_context, &ids_used_by_this_transformation)) { - return false; - } - } - - // The entry and exit block ids must indeed refer to blocks. - for (auto block_id : {message_.entry_block(), message_.exit_block()}) { - auto block_label = ir_context->get_def_use_mgr()->GetDef(block_id); - if (!block_label || block_label->opcode() != SpvOpLabel) { - return false; - } - } - - auto entry_block = ir_context->cfg()->block(message_.entry_block()); - auto exit_block = ir_context->cfg()->block(message_.exit_block()); - - // The entry block cannot start with OpVariable - this would mean that - // outlining would remove a variable from the function containing the region - // being outlined. - if (entry_block->begin()->opcode() == SpvOpVariable) { - return false; - } - - // For simplicity, we do not allow the entry block to be a loop header. - if (entry_block->GetLoopMergeInst()) { - return false; - } - - // For simplicity, we do not allow the exit block to be a merge block or - // continue target. - if (fuzzerutil::IsMergeOrContinue(ir_context, exit_block->id())) { - return false; - } - - // The entry block cannot start with OpPhi. This is to keep the - // transformation logic simple. (Another transformation to split the OpPhis - // from a block could be applied to avoid this scenario.) - if (entry_block->begin()->opcode() == SpvOpPhi) { - return false; - } - - // The block must be in the same function. - if (entry_block->GetParent() != exit_block->GetParent()) { - return false; - } - - // The entry block must dominate the exit block. - auto dominator_analysis = - ir_context->GetDominatorAnalysis(entry_block->GetParent()); - if (!dominator_analysis->Dominates(entry_block, exit_block)) { - return false; - } - - // The exit block must post-dominate the entry block. - auto postdominator_analysis = - ir_context->GetPostDominatorAnalysis(entry_block->GetParent()); - if (!postdominator_analysis->Dominates(exit_block, entry_block)) { - return false; - } - - // Find all the blocks dominated by |message_.entry_block| and post-dominated - // by |message_.exit_block|. - auto region_set = GetRegionBlocks( - ir_context, - entry_block = ir_context->cfg()->block(message_.entry_block()), - exit_block = ir_context->cfg()->block(message_.exit_block())); - - // Check whether |region_set| really is a single-entry single-exit region, and - // also check whether structured control flow constructs and their merge - // and continue constructs are either wholly in or wholly out of the region - - // e.g. avoid the situation where the region contains the head of a loop but - // not the loop's continue construct. - // - // This is achieved by going through every block in the function that contains - // the region. - for (auto& block : *entry_block->GetParent()) { - if (&block == exit_block) { - // It is OK (and typically expected) for the exit block of the region to - // have successors outside the region. - // - // It is also OK for the exit block to head a selection construct: the - // block containing the call to the outlined function will end up heading - // this construct if outlining takes place. However, it is not OK for - // the exit block to head a loop construct. - if (block.GetLoopMergeInst()) { - return false; - } - continue; - } - - if (region_set.count(&block) != 0) { - // The block is in the region and is not the region's exit block. Let's - // see whether all of the block's successors are in the region. If they - // are not, the region is not single-entry single-exit. - bool all_successors_in_region = true; - block.WhileEachSuccessorLabel([&all_successors_in_region, ir_context, - ®ion_set](uint32_t successor) -> bool { - if (region_set.count(ir_context->cfg()->block(successor)) == 0) { - all_successors_in_region = false; - return false; - } - return true; - }); - if (!all_successors_in_region) { - return false; - } - } - - if (auto merge = block.GetMergeInst()) { - // The block is a loop or selection header -- the header and its - // associated merge block had better both be in the region or both be - // outside the region. - auto merge_block = - ir_context->cfg()->block(merge->GetSingleWordOperand(0)); - if (region_set.count(&block) != region_set.count(merge_block)) { - return false; - } - } - - if (auto loop_merge = block.GetLoopMergeInst()) { - // Similar to the above, but for the continue target of a loop. - auto continue_target = - ir_context->cfg()->block(loop_merge->GetSingleWordOperand(1)); - if (continue_target != exit_block && - region_set.count(&block) != region_set.count(continue_target)) { - return false; - } - } - } - - // For each region input id, i.e. every id defined outside the region but - // used inside the region, ... - auto input_id_to_fresh_id_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.input_id_to_fresh_id()); - for (auto id : GetRegionInputIds(ir_context, region_set, exit_block)) { - // There needs to be a corresponding fresh id to be used as a function - // parameter, or overflow ids need to be available. - if (input_id_to_fresh_id_map.count(id) == 0 && - !transformation_context.GetOverflowIdSource()->HasOverflowIds()) { - return false; - } - // Furthermore, if the input id has pointer type it must be an OpVariable - // or OpFunctionParameter. - auto input_id_inst = ir_context->get_def_use_mgr()->GetDef(id); - if (ir_context->get_def_use_mgr() - ->GetDef(input_id_inst->type_id()) - ->opcode() == SpvOpTypePointer) { - switch (input_id_inst->opcode()) { - case SpvOpFunctionParameter: - case SpvOpVariable: - // These are OK. - break; - default: - // Anything else is not OK. - return false; - } - } - } - - // For each region output id -- i.e. every id defined inside the region but - // used outside the region, ... - auto output_id_to_fresh_id_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.output_id_to_fresh_id()); - for (auto id : GetRegionOutputIds(ir_context, region_set, exit_block)) { - if ( - // ... there needs to be a corresponding fresh id that can hold the - // value for this id computed in the outlined function (or overflow ids - // must be available), and ... - (output_id_to_fresh_id_map.count(id) == 0 && - !transformation_context.GetOverflowIdSource()->HasOverflowIds()) - // ... the output id must not have pointer type (to avoid creating a - // struct with pointer members to pass data out of the outlined - // function) - || ir_context->get_def_use_mgr() - ->GetDef(fuzzerutil::GetTypeId(ir_context, id)) - ->opcode() == SpvOpTypePointer) { - return false; - } - } - - return true; -} - -void TransformationOutlineFunction::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // The entry block for the region before outlining. - auto original_region_entry_block = - ir_context->cfg()->block(message_.entry_block()); - - // The exit block for the region before outlining. - auto original_region_exit_block = - ir_context->cfg()->block(message_.exit_block()); - - // The single-entry single-exit region defined by |message_.entry_block| and - // |message_.exit_block|. - std::set region_blocks = GetRegionBlocks( - ir_context, original_region_entry_block, original_region_exit_block); - - // Input and output ids for the region being outlined. - std::vector region_input_ids = - GetRegionInputIds(ir_context, region_blocks, original_region_exit_block); - std::vector region_output_ids = - GetRegionOutputIds(ir_context, region_blocks, original_region_exit_block); - - // Maps from input and output ids to fresh ids. - auto input_id_to_fresh_id_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.input_id_to_fresh_id()); - auto output_id_to_fresh_id_map = - fuzzerutil::RepeatedUInt32PairToMap(message_.output_id_to_fresh_id()); - - // Use overflow ids to augment these maps at any locations where fresh ids are - // required but not provided. - for (uint32_t id : region_input_ids) { - if (input_id_to_fresh_id_map.count(id) == 0) { - input_id_to_fresh_id_map.insert( - {id, - transformation_context->GetOverflowIdSource()->GetNextOverflowId()}); - } - } - for (uint32_t id : region_output_ids) { - if (output_id_to_fresh_id_map.count(id) == 0) { - output_id_to_fresh_id_map.insert( - {id, - transformation_context->GetOverflowIdSource()->GetNextOverflowId()}); - } - } - - UpdateModuleIdBoundForFreshIds(ir_context, input_id_to_fresh_id_map, - output_id_to_fresh_id_map); - - // Construct a map that associates each output id with its type id. - std::map output_id_to_type_id; - for (uint32_t output_id : region_output_ids) { - output_id_to_type_id[output_id] = - ir_context->get_def_use_mgr()->GetDef(output_id)->type_id(); - } - - // The region will be collapsed to a single block that calls a function - // containing the outlined region. This block needs to end with whatever - // the exit block of the region ended with before outlining. We thus clone - // the terminator of the region's exit block, and the merge instruction for - // the block if there is one, so that we can append them to the end of the - // collapsed block later. - std::unique_ptr cloned_exit_block_terminator = - std::unique_ptr( - original_region_exit_block->terminator()->Clone(ir_context)); - std::unique_ptr cloned_exit_block_merge = - original_region_exit_block->GetMergeInst() - ? std::unique_ptr( - original_region_exit_block->GetMergeInst()->Clone(ir_context)) - : nullptr; - - // Make a function prototype for the outlined function, which involves - // figuring out its required type. - std::unique_ptr outlined_function = PrepareFunctionPrototype( - region_input_ids, region_output_ids, input_id_to_fresh_id_map, ir_context, - transformation_context); - - // If the original function was livesafe, the new function should also be - // livesafe. - if (transformation_context->GetFactManager()->FunctionIsLivesafe( - original_region_entry_block->GetParent()->result_id())) { - transformation_context->GetFactManager()->AddFactFunctionIsLivesafe( - message_.new_function_id()); - } - - // Adapt the region to be outlined so that its input ids are replaced with the - // ids of the outlined function's input parameters, and so that output ids - // are similarly remapped. - RemapInputAndOutputIdsInRegion( - ir_context, *original_region_exit_block, region_blocks, region_input_ids, - region_output_ids, input_id_to_fresh_id_map, output_id_to_fresh_id_map); - - // Fill out the body of the outlined function according to the region that is - // being outlined. - PopulateOutlinedFunction( - *original_region_entry_block, *original_region_exit_block, region_blocks, - region_output_ids, output_id_to_fresh_id_map, ir_context, - outlined_function.get(), transformation_context); - - // Collapse the region that has been outlined into a function down to a single - // block that calls said function. - ShrinkOriginalRegion( - ir_context, region_blocks, region_input_ids, region_output_ids, - output_id_to_type_id, outlined_function->type_id(), - std::move(cloned_exit_block_merge), - std::move(cloned_exit_block_terminator), original_region_entry_block); - - // Add the outlined function to the module. - ir_context->module()->AddFunction(std::move(outlined_function)); - - // Major surgery has been conducted on the module, so invalidate all analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationOutlineFunction::ToMessage() const { - protobufs::Transformation result; - *result.mutable_outline_function() = message_; - return result; -} - -std::vector TransformationOutlineFunction::GetRegionInputIds( - opt::IRContext* ir_context, const std::set& region_set, - opt::BasicBlock* region_exit_block) { - std::vector result; - - auto enclosing_function = region_exit_block->GetParent(); - - // Consider each parameter of the function containing the region. - enclosing_function->ForEachParam( - [ir_context, ®ion_set, &result](opt::Instruction* function_parameter) { - // Consider every use of the parameter. - ir_context->get_def_use_mgr()->WhileEachUse( - function_parameter, - [ir_context, function_parameter, ®ion_set, &result]( - opt::Instruction* use, uint32_t /*unused*/) { - // Get the block, if any, in which the parameter is used. - auto use_block = ir_context->get_instr_block(use); - // If the use is in a block that lies within the region, the - // parameter is an input id for the region. - if (use_block && region_set.count(use_block) != 0) { - result.push_back(function_parameter->result_id()); - return false; - } - return true; - }); - }); - - // Consider all definitions in the function that might turn out to be input - // ids. - for (auto& block : *enclosing_function) { - std::vector candidate_input_ids_for_block; - if (region_set.count(&block) == 0) { - // All instructions in blocks outside the region are candidate's for - // generating input ids. - for (auto& inst : block) { - candidate_input_ids_for_block.push_back(&inst); - } - } else { - // Blocks in the region cannot generate input ids. - continue; - } - - // Consider each candidate input id to check whether it is used in the - // region. - for (auto& inst : candidate_input_ids_for_block) { - ir_context->get_def_use_mgr()->WhileEachUse( - inst, - [ir_context, &inst, region_exit_block, ®ion_set, &result]( - opt::Instruction* use, uint32_t /*unused*/) -> bool { - - // Find the block in which this id use occurs, recording the id as - // an input id if the block is outside the region, with some - // exceptions detailed below. - auto use_block = ir_context->get_instr_block(use); - - if (!use_block) { - // There might be no containing block, e.g. if the use is in a - // decoration. - return true; - } - - if (region_set.count(use_block) == 0) { - // The use is not in the region: this does not make it an input - // id. - return true; - } - - if (use_block == region_exit_block && use->IsBlockTerminator()) { - // We do not regard uses in the exit block terminator as input - // ids, as this terminator does not get outlined. - return true; - } - - result.push_back(inst->result_id()); - return false; - }); - } - } - return result; -} - -std::vector TransformationOutlineFunction::GetRegionOutputIds( - opt::IRContext* ir_context, const std::set& region_set, - opt::BasicBlock* region_exit_block) { - std::vector result; - - // Consider each block in the function containing the region. - for (auto& block : *region_exit_block->GetParent()) { - if (region_set.count(&block) == 0) { - // Skip blocks that are not in the region. - continue; - } - // Consider each use of each instruction defined in the block. - for (auto& inst : block) { - ir_context->get_def_use_mgr()->WhileEachUse( - &inst, - [®ion_set, ir_context, &inst, region_exit_block, &result]( - opt::Instruction* use, uint32_t /*unused*/) -> bool { - - // Find the block in which this id use occurs, recording the id as - // an output id if the block is outside the region, with some - // exceptions detailed below. - auto use_block = ir_context->get_instr_block(use); - - if (!use_block) { - // There might be no containing block, e.g. if the use is in a - // decoration. - return true; - } - - if (region_set.count(use_block) != 0) { - // The use is in the region. - if (use_block != region_exit_block || !use->IsBlockTerminator()) { - // Furthermore, the use is not in the terminator of the region's - // exit block. - return true; - } - } - - result.push_back(inst.result_id()); - return false; - }); - } - } - return result; -} - -std::set TransformationOutlineFunction::GetRegionBlocks( - opt::IRContext* ir_context, opt::BasicBlock* entry_block, - opt::BasicBlock* exit_block) { - auto enclosing_function = entry_block->GetParent(); - auto dominator_analysis = - ir_context->GetDominatorAnalysis(enclosing_function); - auto postdominator_analysis = - ir_context->GetPostDominatorAnalysis(enclosing_function); - - std::set result; - for (auto& block : *enclosing_function) { - if (dominator_analysis->Dominates(entry_block, &block) && - postdominator_analysis->Dominates(exit_block, &block)) { - result.insert(&block); - } - } - return result; -} - -std::unique_ptr -TransformationOutlineFunction::PrepareFunctionPrototype( - const std::vector& region_input_ids, - const std::vector& region_output_ids, - const std::map& input_id_to_fresh_id_map, - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - uint32_t return_type_id = 0; - uint32_t function_type_id = 0; - - // First, try to find an existing function type that is suitable. This is - // only possible if the region generates no output ids; if it generates output - // ids we are going to make a new struct for those, and since that struct does - // not exist there cannot already be a function type with this struct as its - // return type. - if (region_output_ids.empty()) { - std::vector return_and_parameter_types; - opt::analysis::Void void_type; - return_type_id = ir_context->get_type_mgr()->GetId(&void_type); - return_and_parameter_types.push_back(return_type_id); - for (auto id : region_input_ids) { - return_and_parameter_types.push_back( - ir_context->get_def_use_mgr()->GetDef(id)->type_id()); - } - function_type_id = - fuzzerutil::FindFunctionType(ir_context, return_and_parameter_types); - } - - // If no existing function type was found, we need to create one. - if (function_type_id == 0) { - assert( - ((return_type_id == 0) == !region_output_ids.empty()) && - "We should only have set the return type if there are no output ids."); - // If the region generates output ids, we need to make a struct with one - // field per output id. - if (!region_output_ids.empty()) { - opt::Instruction::OperandList struct_member_types; - for (uint32_t output_id : region_output_ids) { - auto output_id_type = - ir_context->get_def_use_mgr()->GetDef(output_id)->type_id(); - struct_member_types.push_back({SPV_OPERAND_TYPE_ID, {output_id_type}}); - } - // Add a new struct type to the module. - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeStruct, 0, - message_.new_function_struct_return_type_id(), - std::move(struct_member_types))); - // The return type for the function is the newly-created struct. - return_type_id = message_.new_function_struct_return_type_id(); - } - assert( - return_type_id != 0 && - "We should either have a void return type, or have created a struct."); - - // The region's input ids dictate the parameter types to the function. - opt::Instruction::OperandList function_type_operands; - function_type_operands.push_back({SPV_OPERAND_TYPE_ID, {return_type_id}}); - for (auto id : region_input_ids) { - function_type_operands.push_back( - {SPV_OPERAND_TYPE_ID, - {ir_context->get_def_use_mgr()->GetDef(id)->type_id()}}); - } - // Add a new function type to the module, and record that this is the type - // id for the new function. - ir_context->module()->AddType(MakeUnique( - ir_context, SpvOpTypeFunction, 0, message_.new_function_type_id(), - function_type_operands)); - function_type_id = message_.new_function_type_id(); - } - - // Create a new function with |message_.new_function_id| as the function id, - // and the return type and function type prepared above. - std::unique_ptr outlined_function = - MakeUnique(MakeUnique( - ir_context, SpvOpFunction, return_type_id, message_.new_function_id(), - opt::Instruction::OperandList( - {{spv_operand_type_t ::SPV_OPERAND_TYPE_LITERAL_INTEGER, - {SpvFunctionControlMaskNone}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {function_type_id}}}))); - - // Add one parameter to the function for each input id, using the fresh ids - // provided in |input_id_to_fresh_id_map|, or overflow ids if needed. - for (auto id : region_input_ids) { - outlined_function->AddParameter(MakeUnique( - ir_context, SpvOpFunctionParameter, - ir_context->get_def_use_mgr()->GetDef(id)->type_id(), - input_id_to_fresh_id_map.at(id), opt::Instruction::OperandList())); - // If the input id is an irrelevant-valued variable, the same should be true - // of the corresponding parameter. - if (transformation_context->GetFactManager()->PointeeValueIsIrrelevant( - id)) { - transformation_context->GetFactManager() - ->AddFactValueOfPointeeIsIrrelevant(input_id_to_fresh_id_map.at(id)); - } - } - - return outlined_function; -} - -void TransformationOutlineFunction::UpdateModuleIdBoundForFreshIds( - opt::IRContext* ir_context, - const std::map& input_id_to_fresh_id_map, - const std::map& output_id_to_fresh_id_map) const { - // Enlarge the module's id bound as needed to accommodate the various fresh - // ids associated with the transformation. - fuzzerutil::UpdateModuleIdBound( - ir_context, message_.new_function_struct_return_type_id()); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.new_function_type_id()); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.new_function_id()); - fuzzerutil::UpdateModuleIdBound(ir_context, - message_.new_function_region_entry_block()); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.new_caller_result_id()); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.new_callee_result_id()); - - for (auto& entry : input_id_to_fresh_id_map) { - fuzzerutil::UpdateModuleIdBound(ir_context, entry.second); - } - - for (auto& entry : output_id_to_fresh_id_map) { - fuzzerutil::UpdateModuleIdBound(ir_context, entry.second); - } -} - -void TransformationOutlineFunction::RemapInputAndOutputIdsInRegion( - opt::IRContext* ir_context, - const opt::BasicBlock& original_region_exit_block, - const std::set& region_blocks, - const std::vector& region_input_ids, - const std::vector& region_output_ids, - const std::map& input_id_to_fresh_id_map, - const std::map& output_id_to_fresh_id_map) const { - // Change all uses of input ids inside the region to the corresponding fresh - // ids that will ultimately be parameters of the outlined function. - // This is done by considering each region input id in turn. - for (uint32_t id : region_input_ids) { - // We then consider each use of the input id. - ir_context->get_def_use_mgr()->ForEachUse( - id, [ir_context, id, &input_id_to_fresh_id_map, region_blocks]( - opt::Instruction* use, uint32_t operand_index) { - // Find the block in which this use of the input id occurs. - opt::BasicBlock* use_block = ir_context->get_instr_block(use); - // We want to rewrite the use id if its block occurs in the outlined - // region. - if (region_blocks.count(use_block) != 0) { - // Rewrite this use of the input id. - use->SetOperand(operand_index, {input_id_to_fresh_id_map.at(id)}); - } - }); - } - - // Change each definition of a region output id to define the corresponding - // fresh ids that will store intermediate value for the output ids. Also - // change all uses of the output id located in the outlined region. - // This is done by considering each region output id in turn. - for (uint32_t id : region_output_ids) { - // First consider each use of the output id and update the relevant uses. - ir_context->get_def_use_mgr()->ForEachUse( - id, [ir_context, &original_region_exit_block, id, - &output_id_to_fresh_id_map, - region_blocks](opt::Instruction* use, uint32_t operand_index) { - // Find the block in which this use of the output id occurs. - auto use_block = ir_context->get_instr_block(use); - // We want to rewrite the use id if its block occurs in the outlined - // region, with one exception: the terminator of the exit block of - // the region is going to remain in the original function, so if the - // use appears in such a terminator instruction we leave it alone. - if ( - // The block is in the region ... - region_blocks.count(use_block) != 0 && - // ... and the use is not in the terminator instruction of the - // region's exit block. - !(use_block == &original_region_exit_block && - use->IsBlockTerminator())) { - // Rewrite this use of the output id. - use->SetOperand(operand_index, {output_id_to_fresh_id_map.at(id)}); - } - }); - - // Now change the instruction that defines the output id so that it instead - // defines the corresponding fresh id. We do this after changing all the - // uses so that the definition of the original id is still registered when - // we analyse its uses. - ir_context->get_def_use_mgr()->GetDef(id)->SetResultId( - output_id_to_fresh_id_map.at(id)); - } -} - -void TransformationOutlineFunction::PopulateOutlinedFunction( - const opt::BasicBlock& original_region_entry_block, - const opt::BasicBlock& original_region_exit_block, - const std::set& region_blocks, - const std::vector& region_output_ids, - const std::map& output_id_to_fresh_id_map, - opt::IRContext* ir_context, opt::Function* outlined_function, - TransformationContext* transformation_context) const { - // When we create the exit block for the outlined region, we use this pointer - // to track of it so that we can manipulate it later. - opt::BasicBlock* outlined_region_exit_block = nullptr; - - // The region entry block in the new function is identical to the entry block - // of the region being outlined, except that it has - // |message_.new_function_region_entry_block| as its id. - std::unique_ptr outlined_region_entry_block = - MakeUnique(MakeUnique( - ir_context, SpvOpLabel, 0, message_.new_function_region_entry_block(), - opt::Instruction::OperandList())); - outlined_region_entry_block->SetParent(outlined_function); - - // If the original region's entry block was dead, the outlined region's entry - // block is also dead. - if (transformation_context->GetFactManager()->BlockIsDead( - original_region_entry_block.id())) { - transformation_context->GetFactManager()->AddFactBlockIsDead( - outlined_region_entry_block->id()); - } - - if (&original_region_entry_block == &original_region_exit_block) { - outlined_region_exit_block = outlined_region_entry_block.get(); - } - - for (auto& inst : original_region_entry_block) { - outlined_region_entry_block->AddInstruction( - std::unique_ptr(inst.Clone(ir_context))); - } - outlined_function->AddBasicBlock(std::move(outlined_region_entry_block)); - - // We now go through the single-entry single-exit region defined by the entry - // and exit blocks, adding clones of all blocks to the new function. - - // Consider every block in the enclosing function. - auto enclosing_function = original_region_entry_block.GetParent(); - for (auto block_it = enclosing_function->begin(); - block_it != enclosing_function->end();) { - // Skip the region's entry block - we already dealt with it above. - if (region_blocks.count(&*block_it) == 0 || - &*block_it == &original_region_entry_block) { - ++block_it; - continue; - } - // Clone the block so that it can be added to the new function. - auto cloned_block = - std::unique_ptr(block_it->Clone(ir_context)); - - // If this is the region's exit block, then the cloned block is the outlined - // region's exit block. - if (&*block_it == &original_region_exit_block) { - assert(outlined_region_exit_block == nullptr && - "We should not yet have encountered the exit block."); - outlined_region_exit_block = cloned_block.get(); - } - - cloned_block->SetParent(outlined_function); - - // Redirect any OpPhi operands whose predecessors are the original region - // entry block to become the new function entry block. - cloned_block->ForEachPhiInst([this](opt::Instruction* phi_inst) { - for (uint32_t predecessor_index = 1; - predecessor_index < phi_inst->NumInOperands(); - predecessor_index += 2) { - if (phi_inst->GetSingleWordInOperand(predecessor_index) == - message_.entry_block()) { - phi_inst->SetInOperand(predecessor_index, - {message_.new_function_region_entry_block()}); - } - } - }); - - outlined_function->AddBasicBlock(std::move(cloned_block)); - block_it = block_it.Erase(); - } - assert(outlined_region_exit_block != nullptr && - "We should have encountered the region's exit block when iterating " - "through the function"); - - // We now need to adapt the exit block for the region - in the new function - - // so that it ends with a return. - - // We first eliminate the merge instruction (if any) and the terminator for - // the cloned exit block. - for (auto inst_it = outlined_region_exit_block->begin(); - inst_it != outlined_region_exit_block->end();) { - if (inst_it->opcode() == SpvOpLoopMerge || - inst_it->opcode() == SpvOpSelectionMerge) { - inst_it = inst_it.Erase(); - } else if (inst_it->IsBlockTerminator()) { - inst_it = inst_it.Erase(); - } else { - ++inst_it; - } - } - - // We now add either OpReturn or OpReturnValue as the cloned exit block's - // terminator. - if (region_output_ids.empty()) { - // The case where there are no region output ids is simple: we just add - // OpReturn. - outlined_region_exit_block->AddInstruction(MakeUnique( - ir_context, SpvOpReturn, 0, 0, opt::Instruction::OperandList())); - } else { - // In the case where there are output ids, we add an OpCompositeConstruct - // instruction to pack all the output values into a struct, and then an - // OpReturnValue instruction to return this struct. - opt::Instruction::OperandList struct_member_operands; - for (uint32_t id : region_output_ids) { - struct_member_operands.push_back( - {SPV_OPERAND_TYPE_ID, {output_id_to_fresh_id_map.at(id)}}); - } - outlined_region_exit_block->AddInstruction(MakeUnique( - ir_context, SpvOpCompositeConstruct, - message_.new_function_struct_return_type_id(), - message_.new_callee_result_id(), struct_member_operands)); - outlined_region_exit_block->AddInstruction(MakeUnique( - ir_context, SpvOpReturnValue, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.new_callee_result_id()}}}))); - } - - outlined_function->SetFunctionEnd(MakeUnique( - ir_context, SpvOpFunctionEnd, 0, 0, opt::Instruction::OperandList())); -} - -void TransformationOutlineFunction::ShrinkOriginalRegion( - opt::IRContext* ir_context, std::set& region_blocks, - const std::vector& region_input_ids, - const std::vector& region_output_ids, - const std::map& output_id_to_type_id, - uint32_t return_type_id, - std::unique_ptr cloned_exit_block_merge, - std::unique_ptr cloned_exit_block_terminator, - opt::BasicBlock* original_region_entry_block) const { - // Erase all blocks from the original function that are in the outlined - // region, except for the region's entry block. - // - // In the process, identify all references to the exit block of the region, - // as merge blocks, continue targets, or OpPhi predecessors, and rewrite them - // to refer to the region entry block (the single block to which we are - // shrinking the region). - auto enclosing_function = original_region_entry_block->GetParent(); - for (auto block_it = enclosing_function->begin(); - block_it != enclosing_function->end();) { - if (&*block_it == original_region_entry_block) { - ++block_it; - } else if (region_blocks.count(&*block_it) == 0) { - // The block is not in the region. Check whether it has the last block - // of the region as an OpPhi predecessor, and if so change the - // predecessor to be the first block of the region (i.e. the block - // containing the call to what was outlined). - assert(block_it->MergeBlockIdIfAny() != message_.exit_block() && - "Outlined region must not end with a merge block"); - assert(block_it->ContinueBlockIdIfAny() != message_.exit_block() && - "Outlined region must not end with a continue target"); - block_it->ForEachPhiInst([this](opt::Instruction* phi_inst) { - for (uint32_t predecessor_index = 1; - predecessor_index < phi_inst->NumInOperands(); - predecessor_index += 2) { - if (phi_inst->GetSingleWordInOperand(predecessor_index) == - message_.exit_block()) { - phi_inst->SetInOperand(predecessor_index, {message_.entry_block()}); - } - } - }); - ++block_it; - } else { - // The block is in the region and is not the region's entry block: kill - // it. - block_it = block_it.Erase(); - } - } - - // Now erase all instructions from the region's entry block, as they have - // been outlined. - for (auto inst_it = original_region_entry_block->begin(); - inst_it != original_region_entry_block->end();) { - inst_it = inst_it.Erase(); - } - - // Now we add a call to the outlined function to the region's entry block. - opt::Instruction::OperandList function_call_operands; - function_call_operands.push_back( - {SPV_OPERAND_TYPE_ID, {message_.new_function_id()}}); - // The function parameters are the region input ids. - for (auto input_id : region_input_ids) { - function_call_operands.push_back({SPV_OPERAND_TYPE_ID, {input_id}}); - } - - original_region_entry_block->AddInstruction(MakeUnique( - ir_context, SpvOpFunctionCall, return_type_id, - message_.new_caller_result_id(), function_call_operands)); - - // If there are output ids, the function call will return a struct. For each - // output id, we add an extract operation to pull the appropriate struct - // member out into an output id. - for (uint32_t index = 0; index < region_output_ids.size(); ++index) { - uint32_t output_id = region_output_ids[index]; - original_region_entry_block->AddInstruction(MakeUnique( - ir_context, SpvOpCompositeExtract, output_id_to_type_id.at(output_id), - output_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.new_caller_result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}}}))); - } - - // Finally, we terminate the block with the merge instruction (if any) that - // used to belong to the region's exit block, and the terminator that used - // to belong to the region's exit block. - if (cloned_exit_block_merge != nullptr) { - original_region_entry_block->AddInstruction( - std::move(cloned_exit_block_merge)); - } - original_region_entry_block->AddInstruction( - std::move(cloned_exit_block_terminator)); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.h b/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.h deleted file mode 100644 index dac434641..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_outline_function.h +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_OUTLINE_FUNCTION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_OUTLINE_FUNCTION_H_ - -#include -#include -#include - -#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 TransformationOutlineFunction : public Transformation { - public: - explicit TransformationOutlineFunction( - const protobufs::TransformationOutlineFunction& message); - - TransformationOutlineFunction( - uint32_t entry_block, uint32_t exit_block, - uint32_t new_function_struct_return_type_id, - uint32_t new_function_type_id, uint32_t new_function_id, - uint32_t new_function_region_entry_block, uint32_t new_caller_result_id, - uint32_t new_callee_result_id, - std::map&& input_id_to_fresh_id, - std::map&& output_id_to_fresh_id); - - // - All the fresh ids occurring in the transformation must be distinct and - // fresh - // - |message_.entry_block| and |message_.exit_block| must form a single-entry - // single-exit control flow graph region - // - |message_.entry_block| must not start with OpVariable - // - |message_.entry_block| must not be a loop header - // - |message_.exit_block| must not be a merge block or the continue target - // of a loop - // - A structured control flow construct must lie either completely within the - // region or completely outside it - // - |message.entry_block| must not start with OpPhi; this is to keep the - // transformation simple - another transformation should be used to split - // a desired entry block that starts with OpPhi if needed - // - |message_.input_id_to_fresh_id| must contain an entry for every id - // defined outside the region but used in the region - // - |message_.output_id_to_fresh_id| must contain an entry for every id - // defined in the region but used outside the region - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - A new function with id |message_.new_function_id| is added to the module. - // - If the region generates output ids, the return type of this function is - // a new struct type with one field per output id, and with type id - // |message_.new_function_struct_return_type|, otherwise the function return - // types is void and |message_.new_function_struct_return_type| is not used. - // - If the region generates input ids, the new function has one parameter per - // input id. Fresh ids for these parameters are provided by - // |message_.input_id_to_fresh_id|. - // - Unless the type required for the new function is already known, - // |message_.new_function_type_id| is used as the type id for a new function - // type, and the new function uses this type. - // - The new function starts with a placeholder block with id - // |message_.new_function_first_block|, which jumps straight to a successor - // block, to avoid violating rules on what the first block in a function may - // look like. - // - The outlined region is replaced with a single block, with the same id - // as |message_.entry_block|, and which calls the new function, passing the - // region's input ids as parameters. The result is stored in - // |message_.new_caller_result_id|, which has type - // |message_.new_function_struct_return_type| (unless there are - // no output ids, in which case the return type is void). The components - // of this returned struct are then copied out into the region's output ids. - // The block ends with the merge instruction (if any) and terminator of - // |message_.exit_block|. - // - The body of the new function is identical to the outlined region, except - // that (a) the region's entry block has id - // |message_.new_function_region_entry_block|, (b) input id uses are - // replaced with parameter accesses, (c) and definitions of output ids are - // replaced with definitions of corresponding fresh ids provided by - // |message_.output_id_to_fresh_id|, and (d) the block of the function - // ends by returning a composite of type - // |message_.new_function_struct_return_type| comprised of all the fresh - // output ids (unless the return type is void, in which case no value is - // returned. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns the set of blocks dominated by |entry_block| and post-dominated - // by |exit_block|. - static std::set GetRegionBlocks( - opt::IRContext* ir_context, opt::BasicBlock* entry_block, - opt::BasicBlock* exit_block); - - // Yields ids that are used in |region_set| and that are either parameters - // to the function containing |region_set|, or are defined by blocks of this - // function that are outside |region_set|. - // - // Special cases: OpPhi instructions in |region_entry_block| and the - // terminator of |region_exit_block| do not get outlined, therefore - // - id uses in OpPhi instructions in |region_entry_block| are ignored - // - id uses in the terminator instruction of |region_exit_block| are ignored - static std::vector GetRegionInputIds( - opt::IRContext* ir_context, const std::set& region_set, - opt::BasicBlock* region_exit_block); - - // Yields all ids that are defined in |region_set| and used outside - // |region_set|. - // - // Special cases: for similar reasons as for |GetRegionInputIds|, - // - ids defined in the region and used in the terminator of - // |region_exit_block| count as output ids - static std::vector GetRegionOutputIds( - opt::IRContext* ir_context, const std::set& region_set, - opt::BasicBlock* region_exit_block); - - private: - // Ensures that the module's id bound is at least the maximum of any fresh id - // associated with the transformation. - void UpdateModuleIdBoundForFreshIds( - opt::IRContext* ir_context, - const std::map& input_id_to_fresh_id_map, - const std::map& output_id_to_fresh_id_map) const; - - // Uses |input_id_to_fresh_id_map| and |output_id_to_fresh_id_map| to convert, - // in the region to be outlined, all the input ids in |region_input_ids| and - // the output ids in |region_output_ids| to their fresh counterparts. - // Parameters |region_blocks| provides access to the blocks that must be - // modified, and |original_region_exit_block| allows for some special cases - // where ids should not be remapped. - void RemapInputAndOutputIdsInRegion( - opt::IRContext* ir_context, - const opt::BasicBlock& original_region_exit_block, - const std::set& region_blocks, - const std::vector& region_input_ids, - const std::vector& region_output_ids, - const std::map& input_id_to_fresh_id_map, - const std::map& output_id_to_fresh_id_map) const; - - // Produce a Function object that has the right function type and parameter - // declarations. The function argument types and parameter ids are dictated - // by |region_input_ids| and |input_id_to_fresh_id_map|. The function return - // type is dictated by |region_output_ids|. - // - // A new struct type to represent the function return type, and a new function - // type for the function, will be added to the module (unless suitable types - // are already present). - // - // Facts about the function containing the outlined region that are relevant - // to the new function are propagated via the vact manager in - // |transformation_context|. - std::unique_ptr PrepareFunctionPrototype( - const std::vector& region_input_ids, - const std::vector& region_output_ids, - const std::map& input_id_to_fresh_id_map, - opt::IRContext* ir_context, - TransformationContext* transformation_context) const; - - // Creates the body of the outlined function by cloning blocks from the - // original region, given by |region_blocks|, adapting the cloned version - // of |original_region_exit_block| so that it returns something appropriate, - // and patching up branches to |original_region_entry_block| to refer to its - // clone. Parameters |region_output_ids| and |output_id_to_fresh_id_map| are - // used to determine what the function should return. - // - // The |transformation_context| argument allow facts about blocks being - // outlined, e.g. whether they are dead blocks, to be asserted about blocks - // that get created during outlining. - void PopulateOutlinedFunction( - const opt::BasicBlock& original_region_entry_block, - const opt::BasicBlock& original_region_exit_block, - const std::set& region_blocks, - const std::vector& region_output_ids, - const std::map& output_id_to_fresh_id_map, - opt::IRContext* ir_context, opt::Function* outlined_function, - TransformationContext* transformation_context) const; - - // Shrinks the outlined region, given by |region_blocks|, down to the single - // block |original_region_entry_block|. This block is itself shrunk to just - // contain: - // - any OpPhi instructions that were originally present - // - a call to the outlined function, with parameters provided by - // |region_input_ids| - // - instructions to route components of the call's return value into - // |region_output_ids| - // - The merge instruction (if any) and terminator of the original region's - // exit block, given by |cloned_exit_block_merge| and - // |cloned_exit_block_terminator| - // Parameters |output_id_to_type_id| and |return_type_id| provide the - // provide types for the region's output ids, and the return type of the - // outlined function: as the module is in an inconsistent state when this - // function is called, this information cannot be gotten from the def-use - // manager. - void ShrinkOriginalRegion( - opt::IRContext* ir_context, std::set& region_blocks, - const std::vector& region_input_ids, - const std::vector& region_output_ids, - const std::map& output_id_to_type_id, - uint32_t return_type_id, - std::unique_ptr cloned_exit_block_merge, - std::unique_ptr cloned_exit_block_terminator, - opt::BasicBlock* original_region_entry_block) const; - - protobufs::TransformationOutlineFunction message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_OUTLINE_FUNCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_permute_function_parameters.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_permute_function_parameters.cpp deleted file mode 100644 index c4de743d5..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_permute_function_parameters.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_permute_function_parameters.h" - -#include - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationPermuteFunctionParameters:: - TransformationPermuteFunctionParameters( - const spvtools::fuzz::protobufs:: - TransformationPermuteFunctionParameters& message) - : message_(message) {} - -TransformationPermuteFunctionParameters:: - TransformationPermuteFunctionParameters( - uint32_t function_id, uint32_t function_type_fresh_id, - const std::vector& permutation) { - message_.set_function_id(function_id); - message_.set_function_type_fresh_id(function_type_fresh_id); - - for (auto index : permutation) { - message_.add_permutation(index); - } -} - -bool TransformationPermuteFunctionParameters::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Check that function exists - const auto* function = - fuzzerutil::FindFunction(ir_context, message_.function_id()); - if (!function || function->DefInst().opcode() != SpvOpFunction || - fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) { - return false; - } - - // Check that permutation has valid indices - const auto* function_type = fuzzerutil::GetFunctionType(ir_context, function); - assert(function_type && "Function type is null"); - - std::vector permutation(message_.permutation().begin(), - message_.permutation().end()); - - // Don't take return type into account - auto arg_size = function_type->NumInOperands() - 1; - - // |permutation| vector should be equal to the number of arguments - if (static_cast(permutation.size()) != arg_size) { - return false; - } - - // Check that permutation doesn't have duplicated values. - assert(!fuzzerutil::HasDuplicates(permutation) && - "Permutation has duplicates"); - - // Check that elements in permutation are in range [0, arg_size - 1]. - // - // We must check whether the permutation is empty first because in that case - // |arg_size - 1| will produce |std::numeric_limits::max()| since - // it's an unsigned integer. - if (!permutation.empty() && - !fuzzerutil::IsPermutationOfRange(permutation, 0, arg_size - 1)) { - return false; - } - - return fuzzerutil::IsFreshId(ir_context, message_.function_type_fresh_id()); -} - -void TransformationPermuteFunctionParameters::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Find the function that will be transformed - auto* function = fuzzerutil::FindFunction(ir_context, message_.function_id()); - assert(function && "Can't find the function"); - - // Adjust OpFunctionParameter instructions - - // Collect ids and types from OpFunctionParameter instructions - std::vector param_id, param_type; - function->ForEachParam( - [¶m_id, ¶m_type](const opt::Instruction* param) { - param_id.push_back(param->result_id()); - param_type.push_back(param->type_id()); - }); - - // Permute parameters' ids and types - std::vector permuted_param_id, permuted_param_type; - for (auto index : message_.permutation()) { - permuted_param_id.push_back(param_id[index]); - permuted_param_type.push_back(param_type[index]); - } - - // Set OpFunctionParameter instructions to point to new parameters - size_t i = 0; - function->ForEachParam( - [&i, &permuted_param_id, &permuted_param_type](opt::Instruction* param) { - param->SetResultType(permuted_param_type[i]); - param->SetResultId(permuted_param_id[i]); - ++i; - }); - - // Fix all OpFunctionCall instructions - for (auto* call : fuzzerutil::GetCallers(ir_context, function->result_id())) { - opt::Instruction::OperandList call_operands = { - call->GetInOperand(0) // Function id - }; - - for (auto index : message_.permutation()) { - // Take function id into account - call_operands.push_back(call->GetInOperand(index + 1)); - } - - call->SetInOperands(std::move(call_operands)); - } - - // Update function type. - { - // We use a separate scope here since |old_function_type_inst| might become - // a dangling pointer after the call to the fuzzerutil::UpdateFunctionType. - - auto* old_function_type_inst = - fuzzerutil::GetFunctionType(ir_context, function); - assert(old_function_type_inst && "Function must have a valid type"); - - std::vector parameter_type_ids; - for (auto index : message_.permutation()) { - // +1 since the first operand to OpTypeFunction is a return type. - parameter_type_ids.push_back( - old_function_type_inst->GetSingleWordInOperand(index + 1)); - } - - // Change function's type. - fuzzerutil::UpdateFunctionType( - ir_context, function->result_id(), message_.function_type_fresh_id(), - old_function_type_inst->GetSingleWordInOperand(0), parameter_type_ids); - } - - // Make sure our changes are analyzed - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationPermuteFunctionParameters::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_permute_function_parameters() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_permute_function_parameters.h b/3rdparty/spirv-tools/source/fuzz/transformation_permute_function_parameters.h deleted file mode 100644 index 830805179..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_permute_function_parameters.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_PERMUTE_FUNCTION_PARAMETERS_H_ -#define SOURCE_FUZZ_TRANSFORMATION_PERMUTE_FUNCTION_PARAMETERS_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 TransformationPermuteFunctionParameters : public Transformation { - public: - explicit TransformationPermuteFunctionParameters( - const protobufs::TransformationPermuteFunctionParameters& message); - - TransformationPermuteFunctionParameters( - uint32_t function_id, uint32_t function_type_fresh_id, - const std::vector& permutation); - - // - |function_id| is a valid non-entry-point OpFunction instruction - // - |function_type_fresh_id| is a fresh id. - // New type is valid if: - // - it has the same number of operands as the old one - // - function's result type is the same as the old one - // - function's arguments are permuted according to |permutation| vector - // - |permutation| is a set of [0..(n - 1)], where n is a number of arguments - // to the function - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - OpFunction instruction with |result_id == function_id| is changed. - // Its arguments are permuted according to the |permutation| vector - // - Adjusts function's type to accommodate for permuted parameters. - // - Calls to the function are adjusted accordingly - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationPermuteFunctionParameters message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_PERMUTE_FUNCTION_PARAMETERS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_permute_phi_operands.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_permute_phi_operands.cpp deleted file mode 100644 index 95e7a1f4d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_permute_phi_operands.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_permute_phi_operands.h" - -namespace spvtools { -namespace fuzz { - -TransformationPermutePhiOperands::TransformationPermutePhiOperands( - const spvtools::fuzz::protobufs::TransformationPermutePhiOperands& message) - : message_(message) {} - -TransformationPermutePhiOperands::TransformationPermutePhiOperands( - uint32_t result_id, const std::vector& permutation) { - message_.set_result_id(result_id); - - for (auto index : permutation) { - message_.add_permutation(index); - } -} - -bool TransformationPermutePhiOperands::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Check that |message_.result_id| is valid. - const auto* inst = - ir_context->get_def_use_mgr()->GetDef(message_.result_id()); - if (!inst || inst->opcode() != SpvOpPhi) { - return false; - } - - // Check that |message_.permutation| has expected size. - auto expected_permutation_size = inst->NumInOperands() / 2; - if (static_cast(message_.permutation().size()) != - expected_permutation_size) { - return false; - } - - // Check that |message_.permutation| has elements in range - // [0, expected_permutation_size - 1]. - std::vector permutation(message_.permutation().begin(), - message_.permutation().end()); - assert(!fuzzerutil::HasDuplicates(permutation) && - "Permutation has duplicates"); - - // We must check whether the permutation is empty first because in that case - // |expected_permutation_size - 1| will produce - // |std::numeric_limits::max()| since it's an unsigned integer. - return permutation.empty() || - fuzzerutil::IsPermutationOfRange(permutation, 0, - expected_permutation_size - 1); -} - -void TransformationPermutePhiOperands::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.result_id()); - assert(inst); - - opt::Instruction::OperandList permuted_operands; - permuted_operands.reserve(inst->NumInOperands()); - - for (auto index : message_.permutation()) { - permuted_operands.push_back(std::move(inst->GetInOperand(2 * index))); - permuted_operands.push_back(std::move(inst->GetInOperand(2 * index + 1))); - } - - inst->SetInOperands(std::move(permuted_operands)); - - // Make sure our changes are analyzed - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationPermutePhiOperands::ToMessage() const { - protobufs::Transformation result; - *result.mutable_permute_phi_operands() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_permute_phi_operands.h b/3rdparty/spirv-tools/source/fuzz/transformation_permute_phi_operands.h deleted file mode 100644 index df242e3ef..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_permute_phi_operands.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_PERMUTE_PHI_OPERANDS_H_ -#define SOURCE_FUZZ_TRANSFORMATION_PERMUTE_PHI_OPERANDS_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 TransformationPermutePhiOperands : public Transformation { - public: - explicit TransformationPermutePhiOperands( - const protobufs::TransformationPermutePhiOperands& message); - - TransformationPermutePhiOperands(uint32_t result_id, - const std::vector& permutation); - - // - |result_id| must be a valid id of some OpPhi instruction in the module. - // - |permutation| must contain elements in the range [0, n/2 - 1] where |n| - // is a number of operands to the instruction with |result_id|. All elements - // must be unique (i.e. |permutation.size() == n / 2|). - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Permutes operands of the OpPhi instruction with |result_id| according to - // the elements in |permutation|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationPermutePhiOperands message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_PERMUTE_PHI_OPERANDS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_propagate_instruction_up.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_propagate_instruction_up.cpp deleted file mode 100644 index adf3a5169..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_propagate_instruction_up.cpp +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_propagate_instruction_up.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { -namespace { - -uint32_t GetResultIdFromLabelId(const opt::Instruction& phi_inst, - uint32_t label_id) { - assert(phi_inst.opcode() == SpvOpPhi && "|phi_inst| is not an OpPhi"); - - for (uint32_t i = 1; i < phi_inst.NumInOperands(); i += 2) { - if (phi_inst.GetSingleWordInOperand(i) == label_id) { - return phi_inst.GetSingleWordInOperand(i - 1); - } - } - - return 0; -} - -bool ContainsPointers(const opt::analysis::Type& type) { - switch (type.kind()) { - case opt::analysis::Type::kPointer: - return true; - case opt::analysis::Type::kStruct: - return std::any_of(type.AsStruct()->element_types().begin(), - type.AsStruct()->element_types().end(), - [](const opt::analysis::Type* element_type) { - return ContainsPointers(*element_type); - }); - default: - return false; - } -} - -bool HasValidDependencies(opt::IRContext* ir_context, opt::Instruction* inst) { - const auto* inst_block = ir_context->get_instr_block(inst); - assert(inst_block && - "This function shouldn't be applied to global instructions or function" - "parameters"); - - for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { - const auto& operand = inst->GetInOperand(i); - if (operand.type != SPV_OPERAND_TYPE_ID) { - // Consider only operands. - continue; - } - - auto* dependency = ir_context->get_def_use_mgr()->GetDef(operand.words[0]); - assert(dependency && "Operand has invalid id"); - - if (ir_context->get_instr_block(dependency) == inst_block && - dependency->opcode() != SpvOpPhi) { - // |dependency| is "valid" if it's an OpPhi from the same basic block or - // an instruction from a different basic block. - return false; - } - } - - return true; -} - -} // namespace - -TransformationPropagateInstructionUp::TransformationPropagateInstructionUp( - const protobufs::TransformationPropagateInstructionUp& message) - : message_(message) {} - -TransformationPropagateInstructionUp::TransformationPropagateInstructionUp( - uint32_t block_id, - const std::map& predecessor_id_to_fresh_id) { - message_.set_block_id(block_id); - *message_.mutable_predecessor_id_to_fresh_id() = - fuzzerutil::MapToRepeatedUInt32Pair(predecessor_id_to_fresh_id); -} - -bool TransformationPropagateInstructionUp::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // Check that we can apply this transformation to the |block_id|. - if (!IsApplicableToBlock(ir_context, message_.block_id())) { - return false; - } - - const auto predecessor_id_to_fresh_id = fuzzerutil::RepeatedUInt32PairToMap( - message_.predecessor_id_to_fresh_id()); - for (auto id : ir_context->cfg()->preds(message_.block_id())) { - // Each predecessor must have a fresh id in the |predecessor_id_to_fresh_id| - // map. - if (!predecessor_id_to_fresh_id.count(id)) { - return false; - } - } - - std::vector maybe_fresh_ids; - maybe_fresh_ids.reserve(predecessor_id_to_fresh_id.size()); - for (const auto& entry : predecessor_id_to_fresh_id) { - maybe_fresh_ids.push_back(entry.second); - } - - // All ids must be unique and fresh. - return !fuzzerutil::HasDuplicates(maybe_fresh_ids) && - std::all_of(maybe_fresh_ids.begin(), maybe_fresh_ids.end(), - [ir_context](uint32_t id) { - return fuzzerutil::IsFreshId(ir_context, id); - }); -} - -void TransformationPropagateInstructionUp::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto* inst = GetInstructionToPropagate(ir_context, message_.block_id()); - assert(inst && - "The block must have at least one supported instruction to propagate"); - assert(inst->result_id() && inst->type_id() && - "|inst| must have a result id and a type id"); - - opt::Instruction::OperandList op_phi_operands; - const auto predecessor_id_to_fresh_id = fuzzerutil::RepeatedUInt32PairToMap( - message_.predecessor_id_to_fresh_id()); - std::unordered_set visited_predecessors; - for (auto predecessor_id : ir_context->cfg()->preds(message_.block_id())) { - // A block can have multiple identical predecessors. - if (visited_predecessors.count(predecessor_id)) { - continue; - } - - visited_predecessors.insert(predecessor_id); - - auto new_result_id = predecessor_id_to_fresh_id.at(predecessor_id); - - // Compute InOperands for the OpPhi instruction to be inserted later. - op_phi_operands.push_back({SPV_OPERAND_TYPE_ID, {new_result_id}}); - op_phi_operands.push_back({SPV_OPERAND_TYPE_ID, {predecessor_id}}); - - // Create a clone of the |inst| to be inserted into the |predecessor_id|. - std::unique_ptr clone(inst->Clone(ir_context)); - clone->SetResultId(new_result_id); - - fuzzerutil::UpdateModuleIdBound(ir_context, new_result_id); - - // Adjust |clone|'s operands to account for possible dependencies on OpPhi - // instructions from the same basic block. - for (uint32_t i = 0; i < clone->NumInOperands(); ++i) { - auto& operand = clone->GetInOperand(i); - if (operand.type != SPV_OPERAND_TYPE_ID) { - // Consider only ids. - continue; - } - - const auto* dependency_inst = - ir_context->get_def_use_mgr()->GetDef(operand.words[0]); - assert(dependency_inst && "|clone| depends on an invalid id"); - - if (ir_context->get_instr_block(dependency_inst->result_id()) != - ir_context->cfg()->block(message_.block_id())) { - // We don't need to adjust anything if |dependency_inst| is from a - // different block, a global instruction or a function parameter. - continue; - } - - assert(dependency_inst->opcode() == SpvOpPhi && - "Propagated instruction can depend only on OpPhis from the same " - "basic block or instructions from different basic blocks"); - - auto new_id = GetResultIdFromLabelId(*dependency_inst, predecessor_id); - assert(new_id && "OpPhi instruction is missing a predecessor"); - operand.words[0] = new_id; - } - - auto* insert_before_inst = fuzzerutil::GetLastInsertBeforeInstruction( - ir_context, predecessor_id, clone->opcode()); - assert(insert_before_inst && "Can't insert |clone| into |predecessor_id"); - - insert_before_inst->InsertBefore(std::move(clone)); - } - - // Insert an OpPhi instruction into the basic block of |inst|. - ir_context->get_instr_block(inst)->begin()->InsertBefore( - MakeUnique(ir_context, SpvOpPhi, inst->type_id(), - inst->result_id(), - std::move(op_phi_operands))); - - // Remove |inst| from the basic block. - ir_context->KillInst(inst); - - // We have changed the module so most analyzes are now invalid. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationPropagateInstructionUp::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_propagate_instruction_up() = message_; - return result; -} - -bool TransformationPropagateInstructionUp::IsOpcodeSupported(SpvOp opcode) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3605): - // We only support "simple" instructions that don't work with memory. - // We should extend this so that we support the ones that modify the memory - // too. - switch (opcode) { - case SpvOpUndef: - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - case SpvOpArrayLength: - case SpvOpVectorExtractDynamic: - case SpvOpVectorInsertDynamic: - case SpvOpVectorShuffle: - case SpvOpCompositeConstruct: - case SpvOpCompositeExtract: - case SpvOpCompositeInsert: - case SpvOpCopyObject: - case SpvOpTranspose: - case SpvOpConvertFToU: - case SpvOpConvertFToS: - case SpvOpConvertSToF: - case SpvOpConvertUToF: - case SpvOpUConvert: - case SpvOpSConvert: - case SpvOpFConvert: - case SpvOpQuantizeToF16: - case SpvOpSatConvertSToU: - case SpvOpSatConvertUToS: - case SpvOpBitcast: - case SpvOpSNegate: - case SpvOpFNegate: - case SpvOpIAdd: - case SpvOpFAdd: - case SpvOpISub: - case SpvOpFSub: - case SpvOpIMul: - case SpvOpFMul: - case SpvOpUDiv: - case SpvOpSDiv: - case SpvOpFDiv: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSMod: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpVectorTimesScalar: - case SpvOpMatrixTimesScalar: - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - case SpvOpOuterProduct: - case SpvOpDot: - case SpvOpIAddCarry: - case SpvOpISubBorrow: - case SpvOpUMulExtended: - case SpvOpSMulExtended: - case SpvOpAny: - case SpvOpAll: - case SpvOpIsNan: - case SpvOpIsInf: - case SpvOpIsFinite: - case SpvOpIsNormal: - case SpvOpSignBitSet: - case SpvOpLessOrGreater: - case SpvOpOrdered: - case SpvOpUnordered: - case SpvOpLogicalEqual: - case SpvOpLogicalNotEqual: - case SpvOpLogicalOr: - case SpvOpLogicalAnd: - case SpvOpLogicalNot: - case SpvOpSelect: - case SpvOpIEqual: - case SpvOpINotEqual: - case SpvOpUGreaterThan: - case SpvOpSGreaterThan: - case SpvOpUGreaterThanEqual: - case SpvOpSGreaterThanEqual: - case SpvOpULessThan: - case SpvOpSLessThan: - case SpvOpULessThanEqual: - case SpvOpSLessThanEqual: - case SpvOpFOrdEqual: - case SpvOpFUnordEqual: - case SpvOpFOrdNotEqual: - case SpvOpFUnordNotEqual: - case SpvOpFOrdLessThan: - case SpvOpFUnordLessThan: - case SpvOpFOrdGreaterThan: - case SpvOpFUnordGreaterThan: - case SpvOpFOrdLessThanEqual: - case SpvOpFUnordLessThanEqual: - case SpvOpFOrdGreaterThanEqual: - case SpvOpFUnordGreaterThanEqual: - case SpvOpShiftRightLogical: - case SpvOpShiftRightArithmetic: - case SpvOpShiftLeftLogical: - case SpvOpBitwiseOr: - case SpvOpBitwiseXor: - case SpvOpBitwiseAnd: - case SpvOpNot: - case SpvOpBitFieldInsert: - case SpvOpBitFieldSExtract: - case SpvOpBitFieldUExtract: - case SpvOpBitReverse: - case SpvOpBitCount: - case SpvOpCopyLogical: - case SpvOpPtrEqual: - case SpvOpPtrNotEqual: - return true; - default: - return false; - } -} - -opt::Instruction* -TransformationPropagateInstructionUp::GetInstructionToPropagate( - opt::IRContext* ir_context, uint32_t block_id) { - auto* block = ir_context->cfg()->block(block_id); - assert(block && "|block_id| is invalid"); - - for (auto& inst : *block) { - // We look for the first instruction in the block that satisfies the - // following rules: - // - it's not an OpPhi - // - it must be supported by this transformation - // - it may depend only on instructions from different basic blocks or on - // OpPhi instructions from the same basic block. - if (inst.opcode() == SpvOpPhi || !IsOpcodeSupported(inst.opcode()) || - !inst.type_id() || !inst.result_id()) { - continue; - } - - const auto* inst_type = ir_context->get_type_mgr()->GetType(inst.type_id()); - assert(inst_type && "|inst| has invalid type"); - - if (!ir_context->get_feature_mgr()->HasCapability( - SpvCapabilityVariablePointersStorageBuffer) && - ContainsPointers(*inst_type)) { - // OpPhi supports pointer operands only with VariablePointers or - // VariablePointersStorageBuffer capabilities. - // - // Note that VariablePointers capability implicitly declares - // VariablePointersStorageBuffer capability. - continue; - } - - if (!HasValidDependencies(ir_context, &inst)) { - continue; - } - - return &inst; - } - - return nullptr; -} - -bool TransformationPropagateInstructionUp::IsApplicableToBlock( - opt::IRContext* ir_context, uint32_t block_id) { - // Check that |block_id| is valid. - const auto* label_inst = ir_context->get_def_use_mgr()->GetDef(block_id); - if (!label_inst || label_inst->opcode() != SpvOpLabel) { - return false; - } - - // Check that |block| has predecessors. - const auto& predecessors = ir_context->cfg()->preds(block_id); - if (predecessors.empty()) { - return false; - } - - // The block must contain an instruction to propagate. - const auto* inst_to_propagate = - GetInstructionToPropagate(ir_context, block_id); - if (!inst_to_propagate) { - return false; - } - - // We should be able to insert |inst_to_propagate| into every predecessor of - // |block|. - return std::all_of(predecessors.begin(), predecessors.end(), - [ir_context, inst_to_propagate](uint32_t predecessor_id) { - return fuzzerutil::GetLastInsertBeforeInstruction( - ir_context, predecessor_id, - inst_to_propagate->opcode()) != nullptr; - }); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_propagate_instruction_up.h b/3rdparty/spirv-tools/source/fuzz/transformation_propagate_instruction_up.h deleted file mode 100644 index 8e2374962..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_propagate_instruction_up.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_PROPAGATE_INSTRUCTION_UP_H_ -#define SOURCE_FUZZ_TRANSFORMATION_PROPAGATE_INSTRUCTION_UP_H_ - -#include - -#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 TransformationPropagateInstructionUp : public Transformation { - public: - explicit TransformationPropagateInstructionUp( - const protobufs::TransformationPropagateInstructionUp& message); - - TransformationPropagateInstructionUp( - uint32_t block_id, - const std::map& predecessor_id_to_fresh_id); - - // - |block_id| must be a valid result id of some OpLabel instruction. - // - |block_id| must have at least one predecessor - // - |block_id| must contain an instruction that can be propagated using this - // transformation - // - the instruction can be propagated if: - // - it's not an OpPhi - // - it is supported by this transformation - // - it depends only on instructions from different basic blocks or on - // OpPhi instructions from the same basic block - // - it should be possible to insert the propagated instruction at the end of - // each |block_id|'s predecessor - // - |predecessor_id_to_fresh_id| must have an entry for at least every - // predecessor of |block_id| - // - each value in the |predecessor_id_to_fresh_id| map must be a fresh id - // - all fresh ids in the |predecessor_id_to_fresh_id| must be unique - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Inserts a copy of the propagated instruction into each |block_id|'s - // predecessor. Replaces the original instruction with an OpPhi referring - // inserted copies. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if this transformation can be applied to the block with id - // |block_id|. Concretely, returns true iff: - // - |block_id| is a valid id of some block in the module - // - |block_id| has predecessors - // - |block_id| contains an instruction that can be propagated - // - it is possible to insert the propagated instruction into every - // |block_id|'s predecessor - static bool IsApplicableToBlock(opt::IRContext* ir_context, - uint32_t block_id); - - private: - // Returns the instruction that will be propagated into the predecessors of - // the |block_id|. Returns nullptr if no such an instruction exists. - static opt::Instruction* GetInstructionToPropagate(opt::IRContext* ir_context, - uint32_t block_id); - - // Returns true if |opcode| is supported by this transformation. - static bool IsOpcodeSupported(SpvOp opcode); - - protobufs::TransformationPropagateInstructionUp message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_PROPAGATE_INSTRUCTION_UP_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp deleted file mode 100644 index 647bfa065..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_push_id_through_variable.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationPushIdThroughVariable::TransformationPushIdThroughVariable( - const spvtools::fuzz::protobufs::TransformationPushIdThroughVariable& - message) - : message_(message) {} - -TransformationPushIdThroughVariable::TransformationPushIdThroughVariable( - uint32_t value_id, uint32_t value_synonym_id, uint32_t variable_id, - uint32_t variable_storage_class, uint32_t initializer_id, - const protobufs::InstructionDescriptor& instruction_descriptor) { - message_.set_value_id(value_id); - message_.set_value_synonym_id(value_synonym_id); - message_.set_variable_id(variable_id); - message_.set_variable_storage_class(variable_storage_class); - message_.set_initializer_id(initializer_id); - *message_.mutable_instruction_descriptor() = instruction_descriptor; -} - -bool TransformationPushIdThroughVariable::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // |message_.value_synonym_id| and |message_.variable_id| must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.value_synonym_id()) || - !fuzzerutil::IsFreshId(ir_context, message_.variable_id())) { - return false; - } - - // The instruction to insert before must be defined. - auto instruction_to_insert_before = - FindInstruction(message_.instruction_descriptor(), ir_context); - if (!instruction_to_insert_before) { - return false; - } - - // It must be valid to insert the OpStore and OpLoad instruction before it. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpStore, instruction_to_insert_before) || - !fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpLoad, instruction_to_insert_before)) { - return false; - } - - // The instruction to insert before must belong to a reachable block. - auto basic_block = ir_context->get_instr_block(instruction_to_insert_before); - if (!fuzzerutil::BlockIsReachableInItsFunction(ir_context, basic_block)) { - return false; - } - - // The value instruction must be defined and have a type. - auto value_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.value_id()); - if (!value_instruction || !value_instruction->type_id()) { - return false; - } - - // We should be able to create a synonym of |value_id| if it's not irrelevant. - if (!transformation_context.GetFactManager()->IdIsIrrelevant( - message_.value_id()) && - !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, - value_instruction)) { - return false; - } - - // A pointer type instruction pointing to the value type must be defined. - auto pointer_type_id = fuzzerutil::MaybeGetPointerType( - ir_context, value_instruction->type_id(), - static_cast(message_.variable_storage_class())); - if (!pointer_type_id) { - return false; - } - - // |message_.variable_storage_class| must be private or function. - assert((message_.variable_storage_class() == SpvStorageClassPrivate || - message_.variable_storage_class() == SpvStorageClassFunction) && - "The variable storage class must be private or function."); - - // Check that initializer is valid. - const auto* constant_inst = - ir_context->get_def_use_mgr()->GetDef(message_.initializer_id()); - if (!constant_inst || !spvOpcodeIsConstant(constant_inst->opcode()) || - value_instruction->type_id() != constant_inst->type_id()) { - return false; - } - - // |message_.value_id| must be available at the insertion point. - return fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, instruction_to_insert_before, message_.value_id()); -} - -void TransformationPushIdThroughVariable::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - auto value_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.value_id()); - - // A pointer type instruction pointing to the value type must be defined. - auto pointer_type_id = fuzzerutil::MaybeGetPointerType( - ir_context, value_instruction->type_id(), - static_cast(message_.variable_storage_class())); - assert(pointer_type_id && "The required pointer type must be available."); - - // Adds whether a global or local variable. - if (message_.variable_storage_class() == SpvStorageClassPrivate) { - fuzzerutil::AddGlobalVariable(ir_context, message_.variable_id(), - pointer_type_id, SpvStorageClassPrivate, - message_.initializer_id()); - } else { - auto function_id = ir_context - ->get_instr_block(FindInstruction( - message_.instruction_descriptor(), ir_context)) - ->GetParent() - ->result_id(); - fuzzerutil::AddLocalVariable(ir_context, message_.variable_id(), - pointer_type_id, function_id, - message_.initializer_id()); - } - - // First, insert the OpLoad instruction before |instruction_descriptor| and - // then insert the OpStore instruction before the OpLoad instruction. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.value_synonym_id()); - FindInstruction(message_.instruction_descriptor(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpLoad, value_instruction->type_id(), - message_.value_synonym_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}}))) - ->InsertBefore(MakeUnique( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.value_id()}}}))); - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - - if (!transformation_context->GetFactManager()->IdIsIrrelevant( - message_.value_id())) { - // Adds the fact that |message_.value_synonym_id| - // and |message_.value_id| are synonymous. - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(message_.value_synonym_id(), {}), - MakeDataDescriptor(message_.value_id(), {}), ir_context); - } -} - -protobufs::Transformation TransformationPushIdThroughVariable::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_push_id_through_variable() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.h b/3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.h deleted file mode 100644 index f49db3170..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_PUSH_ID_THROUGH_VARIABLE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_PUSH_ID_THROUGH_VARIABLE_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 TransformationPushIdThroughVariable : public Transformation { - public: - explicit TransformationPushIdThroughVariable( - const protobufs::TransformationPushIdThroughVariable& message); - - TransformationPushIdThroughVariable( - uint32_t value_id, uint32_t value_synonym_fresh_id, - uint32_t variable_fresh_id, uint32_t variable_storage_class, - uint32_t initializer_id, - const protobufs::InstructionDescriptor& instruction_descriptor); - - // - |message_.value_id| must be an instruction result id that has the same - // type as the pointee type of |message_.pointer_id| - // - |message_.value_synonym_id| must be fresh - // - |message_.variable_id| must be fresh - // - |message_.variable_storage_class| must be either StorageClassPrivate or - // StorageClassFunction - // - |message_.initializer_id| must be a result id of some constant in the - // module. Its type must be equal to the pointee type of the variable that - // will be created. - // - |message_.instruction_descriptor| must identify an instruction - // which it is valid to insert the OpStore and OpLoad instructions before it - // and must be belongs to a reachable block. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Stores |value_id| to |variable_id|, loads |variable_id| to - // |value_synonym_id|. Adds the fact that |value_synonym_id| and |value_id| - // are synonymous if |value_id| is not irrelevant. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationPushIdThroughVariable message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_PUSH_ID_THROUGH_VARIABLE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.cpp deleted file mode 100644 index a93e1d429..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2020 Stefano Milizia -// Copyright (c) 2020 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 "transformation_record_synonymous_constants.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationRecordSynonymousConstants:: - TransformationRecordSynonymousConstants( - const protobufs::TransformationRecordSynonymousConstants& message) - : message_(message) {} - -TransformationRecordSynonymousConstants:: - TransformationRecordSynonymousConstants(uint32_t constant1_id, - uint32_t constant2_id) { - message_.set_constant1_id(constant1_id); - message_.set_constant2_id(constant2_id); -} - -bool TransformationRecordSynonymousConstants::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // The ids must be different - if (message_.constant1_id() == message_.constant2_id()) { - return false; - } - - if (transformation_context.GetFactManager()->IdIsIrrelevant( - message_.constant1_id()) || - transformation_context.GetFactManager()->IdIsIrrelevant( - message_.constant2_id())) { - return false; - } - - return AreEquivalentConstants(ir_context, message_.constant1_id(), - message_.constant2_id()); -} - -void TransformationRecordSynonymousConstants::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Add the fact to the fact manager - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(message_.constant1_id(), {}), - MakeDataDescriptor(message_.constant2_id(), {}), ir_context); -} - -protobufs::Transformation TransformationRecordSynonymousConstants::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_record_synonymous_constants() = message_; - return result; -} - -bool TransformationRecordSynonymousConstants::AreEquivalentConstants( - opt::IRContext* ir_context, uint32_t constant_id1, uint32_t constant_id2) { - const auto* def_1 = ir_context->get_def_use_mgr()->GetDef(constant_id1); - const auto* def_2 = ir_context->get_def_use_mgr()->GetDef(constant_id2); - - // Check that the definitions exist - if (!def_1 || !def_2) { - // We don't use an assertion since otherwise the shrinker fails. - return false; - } - - auto constant1 = ir_context->get_constant_mgr()->GetConstantFromInst(def_1); - auto constant2 = ir_context->get_constant_mgr()->GetConstantFromInst(def_2); - - assert(constant1 && constant2 && "The ids must refer to constants."); - - // The types must be compatible. - if (!fuzzerutil::TypesAreEqualUpToSign(ir_context, def_1->type_id(), - def_2->type_id())) { - return false; - } - - // If either constant is null, the other is equivalent iff it is zero-like - if (constant1->AsNullConstant()) { - return constant2->IsZero(); - } - - if (constant2->AsNullConstant()) { - return constant1->IsZero(); - } - - // If the constants are scalar, they are equal iff their words are the same - if (auto scalar1 = constant1->AsScalarConstant()) { - return scalar1->words() == constant2->AsScalarConstant()->words(); - } - - // The only remaining possibility is that the constants are composite - assert(constant1->AsCompositeConstant() && - "Equivalence of constants can only be checked with scalar, composite " - "or null constants."); - - // Since the types match, we already know that the number of components is - // the same. We check that the input operands of the definitions are all - // constants and that they are pairwise equivalent. - for (uint32_t i = 0; i < def_1->NumInOperands(); i++) { - if (!AreEquivalentConstants(ir_context, def_1->GetSingleWordInOperand(i), - def_2->GetSingleWordInOperand(i))) { - return false; - } - } - - // If we get here, all the components are equivalent - return true; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.h b/3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.h deleted file mode 100644 index 8cff0cdab..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2020 Stefano Milizia -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS_H -#define SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS_H - -#include "source/fuzz/transformation.h" - -namespace spvtools { -namespace fuzz { - -class TransformationRecordSynonymousConstants : public Transformation { - public: - explicit TransformationRecordSynonymousConstants( - const protobufs::TransformationRecordSynonymousConstants& message); - - TransformationRecordSynonymousConstants(uint32_t constant1_id, - uint32_t constant2_id); - - // - |message_.constant_id| and |message_.synonym_id| are distinct ids - // of constants - // - |message_.constant_id| and |message_.synonym_id| refer to constants - // that are equivalent. - // Constants are equivalent if at least one of the following holds: - // - they are equal (i.e. they have the same type ids and equal values) - // - both of them represent zero-like values of compatible types - // - they are composite constants with compatible types and their - // components are pairwise equivalent - // Two types are compatible if at least one of the following holds: - // - they have the same id - // - they are integer scalar types with the same width - // - they are integer vectors and their components have the same width - // (this is always the case if the components are equivalent) - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds the fact that |message_.constant_id| and |message_.synonym_id| - // are synonyms to the fact manager. The module is not changed. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationRecordSynonymousConstants message_; - - // Returns true if the two given constants are equivalent - // (the description of IsApplicable specifies the conditions they must satisfy - // to be considered equivalent) - static bool AreEquivalentConstants(opt::IRContext* ir_context, - uint32_t constant_id1, - uint32_t constant_id2); -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp deleted file mode 100644 index ea84cf255..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h" - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -namespace { -const uint32_t kOpCompositeExtractIndexLowOrderBits = 0; -const uint32_t kArithmeticInstructionIndexLeftInOperand = 0; -const uint32_t kArithmeticInstructionIndexRightInOperand = 1; -} // namespace - -TransformationReplaceAddSubMulWithCarryingExtended:: - TransformationReplaceAddSubMulWithCarryingExtended( - const spvtools::fuzz::protobufs:: - TransformationReplaceAddSubMulWithCarryingExtended& message) - : message_(message) {} - -TransformationReplaceAddSubMulWithCarryingExtended:: - TransformationReplaceAddSubMulWithCarryingExtended(uint32_t struct_fresh_id, - uint32_t result_id) { - message_.set_struct_fresh_id(struct_fresh_id); - message_.set_result_id(result_id); -} - -bool TransformationReplaceAddSubMulWithCarryingExtended::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |message_.struct_fresh_id| must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.struct_fresh_id())) { - return false; - } - - // |message_.result_id| must refer to a suitable OpIAdd, OpISub or OpIMul - // instruction. The instruction must be defined. - auto instruction = - ir_context->get_def_use_mgr()->GetDef(message_.result_id()); - if (instruction == nullptr) { - return false; - } - if (!TransformationReplaceAddSubMulWithCarryingExtended:: - IsInstructionSuitable(ir_context, *instruction)) { - return false; - } - - // The struct type for holding the intermediate result must exist in the - // module. The struct type is based on the operand type. - uint32_t operand_type_id = ir_context->get_def_use_mgr() - ->GetDef(instruction->GetSingleWordInOperand( - kArithmeticInstructionIndexLeftInOperand)) - ->type_id(); - - uint32_t struct_type_id = fuzzerutil::MaybeGetStructType( - ir_context, {operand_type_id, operand_type_id}); - if (struct_type_id == 0) { - return false; - } - return true; -} - -void TransformationReplaceAddSubMulWithCarryingExtended::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // |message_.struct_fresh_id| must be fresh. - assert(fuzzerutil::IsFreshId(ir_context, message_.struct_fresh_id()) && - "|message_.struct_fresh_id| must be fresh"); - - // Get the signedness of an operand if it is an int or the signedness of a - // component if it is a vector. - auto type_id = - ir_context->get_def_use_mgr()->GetDef(message_.result_id())->type_id(); - auto type = ir_context->get_type_mgr()->GetType(type_id); - bool operand_is_signed; - if (type->kind() == opt::analysis::Type::kVector) { - auto operand_type = type->AsVector()->element_type(); - operand_is_signed = operand_type->AsInteger()->IsSigned(); - } else { - operand_is_signed = type->AsInteger()->IsSigned(); - } - - auto original_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.result_id()); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.struct_fresh_id()); - - // Determine the opcode of the new instruction that computes the result into a - // struct. - SpvOp new_instruction_opcode; - - switch (original_instruction->opcode()) { - case SpvOpIAdd: - new_instruction_opcode = SpvOpIAddCarry; - break; - case SpvOpISub: - new_instruction_opcode = SpvOpISubBorrow; - break; - case SpvOpIMul: - if (!operand_is_signed) { - new_instruction_opcode = SpvOpUMulExtended; - } else { - new_instruction_opcode = SpvOpSMulExtended; - } - break; - default: - assert(false && "The instruction has an unsupported opcode."); - return; - } - // Get the type of struct type id holding the intermediate result based on the - // operand type. - uint32_t operand_type_id = - ir_context->get_def_use_mgr() - ->GetDef(original_instruction->GetSingleWordInOperand( - kArithmeticInstructionIndexLeftInOperand)) - ->type_id(); - - uint32_t struct_type_id = fuzzerutil::MaybeGetStructType( - ir_context, {operand_type_id, operand_type_id}); - // Avoid unused variables in release mode. - (void)struct_type_id; - assert(struct_type_id && "The struct type must exist in the module."); - - // Insert the new instruction that computes the result into a struct before - // the |original_instruction|. - original_instruction->InsertBefore(MakeUnique( - ir_context, new_instruction_opcode, struct_type_id, - message_.struct_fresh_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, - {original_instruction->GetSingleWordInOperand( - kArithmeticInstructionIndexLeftInOperand)}}, - {SPV_OPERAND_TYPE_ID, - {original_instruction->GetSingleWordInOperand( - kArithmeticInstructionIndexRightInOperand)}}}))); - - // Insert the OpCompositeExtract after the added instruction. This instruction - // takes the first component of the struct which represents low-order bits of - // the operation. This is the original result. - original_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, original_instruction->type_id(), - message_.result_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.struct_fresh_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, - {kOpCompositeExtractIndexLowOrderBits}}}))); - - // Remove the original instruction. - ir_context->KillInst(original_instruction); - - // We have modified the module so most analyzes are now invalid. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -bool TransformationReplaceAddSubMulWithCarryingExtended::IsInstructionSuitable( - opt::IRContext* ir_context, const opt::Instruction& instruction) { - auto instruction_opcode = instruction.opcode(); - - // Only instructions OpIAdd, OpISub, OpIMul are supported. - switch (instruction_opcode) { - case SpvOpIAdd: - case SpvOpISub: - case SpvOpIMul: - break; - default: - return false; - } - uint32_t operand_1_type_id = - ir_context->get_def_use_mgr() - ->GetDef(instruction.GetSingleWordInOperand( - kArithmeticInstructionIndexLeftInOperand)) - ->type_id(); - - uint32_t operand_2_type_id = - ir_context->get_def_use_mgr() - ->GetDef(instruction.GetSingleWordInOperand( - kArithmeticInstructionIndexRightInOperand)) - ->type_id(); - - uint32_t result_type_id = instruction.type_id(); - - // Both type ids of the operands and the result type ids must be equal. - if (operand_1_type_id != operand_2_type_id) { - return false; - } - if (operand_2_type_id != result_type_id) { - return false; - } - - // In case of OpIAdd and OpISub, the type must be unsigned. - auto type = ir_context->get_type_mgr()->GetType(instruction.type_id()); - - switch (instruction_opcode) { - case SpvOpIAdd: - case SpvOpISub: { - // In case of OpIAdd and OpISub if the operand is a vector, the component - // type must be unsigned. Otherwise (if the operand is an int), the - // operand must be unsigned. - bool operand_is_signed = - type->AsVector() - ? type->AsVector()->element_type()->AsInteger()->IsSigned() - : type->AsInteger()->IsSigned(); - if (operand_is_signed) { - return false; - } - } break; - default: - break; - } - return true; -} - -protobufs::Transformation -TransformationReplaceAddSubMulWithCarryingExtended::ToMessage() const { - protobufs::Transformation result; - *result.mutable_replace_add_sub_mul_with_carrying_extended() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h deleted file mode 100644 index db71779a3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_TRANSFORMATION_REPLACE_ADD_SUB_MUL_WITH_CARRYING_EXTENDED_H -#define SPIRV_TOOLS_TRANSFORMATION_REPLACE_ADD_SUB_MUL_WITH_CARRYING_EXTENDED_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 TransformationReplaceAddSubMulWithCarryingExtended - : public Transformation { - public: - explicit TransformationReplaceAddSubMulWithCarryingExtended( - const protobufs::TransformationReplaceAddSubMulWithCarryingExtended& - message); - - explicit TransformationReplaceAddSubMulWithCarryingExtended( - uint32_t struct_fresh_id, uint32_t result_id); - - // - |message_.struct_fresh_id| must be fresh. - // - |message_.result_id| must refer to an OpIAdd or OpISub or OpIMul - // instruction. In this instruction the result type id and the type ids of - // the operands must be the same. - // - The type of struct holding the intermediate result must exists in the - // module. - // - For OpIAdd, OpISub both operands must be unsigned. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // A transformation that replaces instructions OpIAdd, OpISub, OpIMul with - // pairs of instructions. The first one (OpIAddCarry, OpISubBorrow, - // OpUMulExtended, OpSMulExtended) computes the result into a struct. The - // second one extracts the appropriate component from the struct to yield the - // original result. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Checks if an OpIAdd, OpISub or OpIMul instruction can be used by the - // transformation. - bool static IsInstructionSuitable(opt::IRContext* ir_context, - const opt::Instruction& instruction); - - private: - protobufs::TransformationReplaceAddSubMulWithCarryingExtended message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_TRANSFORMATION_REPLACE_ADD_SUB_MUL_WITH_CARRYING_EXTENDED_H diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp deleted file mode 100644 index 6e22e7c6d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/id_use_descriptor.h" - -namespace spvtools { -namespace fuzz { - -namespace { - -// Given floating-point values |lhs| and |rhs|, and a floating-point binary -// operator |binop|, returns true if it is certain that 'lhs binop rhs' -// evaluates to |required_value|. -template -bool float_binop_evaluates_to(T lhs, T rhs, SpvOp binop, bool required_value) { - // Infinity and NaN values are conservatively treated as out of scope. - if (!std::isfinite(lhs) || !std::isfinite(rhs)) { - return false; - } - bool binop_result; - // The following captures the binary operators that spirv-fuzz can actually - // generate when turning a boolean constant into a binary expression. - switch (binop) { - case SpvOpFOrdGreaterThanEqual: - case SpvOpFUnordGreaterThanEqual: - binop_result = (lhs >= rhs); - break; - case SpvOpFOrdGreaterThan: - case SpvOpFUnordGreaterThan: - binop_result = (lhs > rhs); - break; - case SpvOpFOrdLessThanEqual: - case SpvOpFUnordLessThanEqual: - binop_result = (lhs <= rhs); - break; - case SpvOpFOrdLessThan: - case SpvOpFUnordLessThan: - binop_result = (lhs < rhs); - break; - default: - return false; - } - return binop_result == required_value; -} - -// Analogous to 'float_binop_evaluates_to', but for signed int values. -template -bool signed_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop, - bool required_value) { - bool binop_result; - switch (binop) { - case SpvOpSGreaterThanEqual: - binop_result = (lhs >= rhs); - break; - case SpvOpSGreaterThan: - binop_result = (lhs > rhs); - break; - case SpvOpSLessThanEqual: - binop_result = (lhs <= rhs); - break; - case SpvOpSLessThan: - binop_result = (lhs < rhs); - break; - default: - return false; - } - return binop_result == required_value; -} - -// Analogous to 'float_binop_evaluates_to', but for unsigned int values. -template -bool unsigned_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop, - bool required_value) { - bool binop_result; - switch (binop) { - case SpvOpUGreaterThanEqual: - binop_result = (lhs >= rhs); - break; - case SpvOpUGreaterThan: - binop_result = (lhs > rhs); - break; - case SpvOpULessThanEqual: - binop_result = (lhs <= rhs); - break; - case SpvOpULessThan: - binop_result = (lhs < rhs); - break; - default: - return false; - } - return binop_result == required_value; -} - -} // namespace - -TransformationReplaceBooleanConstantWithConstantBinary:: - TransformationReplaceBooleanConstantWithConstantBinary( - const spvtools::fuzz::protobufs:: - TransformationReplaceBooleanConstantWithConstantBinary& message) - : message_(message) {} - -TransformationReplaceBooleanConstantWithConstantBinary:: - TransformationReplaceBooleanConstantWithConstantBinary( - const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id, - uint32_t rhs_id, SpvOp comparison_opcode, - uint32_t fresh_id_for_binary_operation) { - *message_.mutable_id_use_descriptor() = id_use_descriptor; - message_.set_lhs_id(lhs_id); - message_.set_rhs_id(rhs_id); - message_.set_opcode(comparison_opcode); - message_.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation); -} - -bool TransformationReplaceBooleanConstantWithConstantBinary::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // The id for the binary result must be fresh - if (!fuzzerutil::IsFreshId(ir_context, - message_.fresh_id_for_binary_operation())) { - return false; - } - - // The used id must be for a boolean constant - auto boolean_constant = ir_context->get_def_use_mgr()->GetDef( - message_.id_use_descriptor().id_of_interest()); - if (!boolean_constant) { - return false; - } - if (!(boolean_constant->opcode() == SpvOpConstantFalse || - boolean_constant->opcode() == SpvOpConstantTrue)) { - return false; - } - - // The left-hand-side id must correspond to a constant instruction. - auto lhs_constant_inst = - ir_context->get_def_use_mgr()->GetDef(message_.lhs_id()); - if (!lhs_constant_inst) { - return false; - } - if (lhs_constant_inst->opcode() != SpvOpConstant) { - return false; - } - - // The right-hand-side id must correspond to a constant instruction. - auto rhs_constant_inst = - ir_context->get_def_use_mgr()->GetDef(message_.rhs_id()); - if (!rhs_constant_inst) { - return false; - } - if (rhs_constant_inst->opcode() != SpvOpConstant) { - return false; - } - - // The left- and right-hand side instructions must have the same type. - if (lhs_constant_inst->type_id() != rhs_constant_inst->type_id()) { - return false; - } - - // The expression 'LHS opcode RHS' must evaluate to the boolean constant. - auto lhs_constant = - ir_context->get_constant_mgr()->FindDeclaredConstant(message_.lhs_id()); - auto rhs_constant = - ir_context->get_constant_mgr()->FindDeclaredConstant(message_.rhs_id()); - bool expected_result = (boolean_constant->opcode() == SpvOpConstantTrue); - - const auto binary_opcode = static_cast(message_.opcode()); - - // We consider the floating point, signed and unsigned integer cases - // separately. In each case the logic is very similar. - if (lhs_constant->AsFloatConstant()) { - assert(rhs_constant->AsFloatConstant() && - "Both constants should be of the same type."); - if (lhs_constant->type()->AsFloat()->width() == 32) { - if (!float_binop_evaluates_to(lhs_constant->GetFloat(), - rhs_constant->GetFloat(), binary_opcode, - expected_result)) { - return false; - } - } else { - assert(lhs_constant->type()->AsFloat()->width() == 64); - if (!float_binop_evaluates_to(lhs_constant->GetDouble(), - rhs_constant->GetDouble(), binary_opcode, - expected_result)) { - return false; - } - } - } else { - assert(lhs_constant->AsIntConstant() && "Constants should be in or float."); - assert(rhs_constant->AsIntConstant() && - "Both constants should be of the same type."); - if (lhs_constant->type()->AsInteger()->IsSigned()) { - if (lhs_constant->type()->AsInteger()->width() == 32) { - if (!signed_int_binop_evaluates_to(lhs_constant->GetS32(), - rhs_constant->GetS32(), - binary_opcode, expected_result)) { - return false; - } - } else { - assert(lhs_constant->type()->AsInteger()->width() == 64); - if (!signed_int_binop_evaluates_to(lhs_constant->GetS64(), - rhs_constant->GetS64(), - binary_opcode, expected_result)) { - return false; - } - } - } else { - if (lhs_constant->type()->AsInteger()->width() == 32) { - if (!unsigned_int_binop_evaluates_to(lhs_constant->GetU32(), - rhs_constant->GetU32(), - binary_opcode, expected_result)) { - return false; - } - } else { - assert(lhs_constant->type()->AsInteger()->width() == 64); - if (!unsigned_int_binop_evaluates_to(lhs_constant->GetU64(), - rhs_constant->GetU64(), - binary_opcode, expected_result)) { - return false; - } - } - } - } - - // The id use descriptor must identify some instruction - auto instruction = - FindInstructionContainingUse(message_.id_use_descriptor(), ir_context); - if (instruction == nullptr) { - return false; - } - - // The instruction must not be an OpVariable, because (a) we cannot insert - // a binary operator before an OpVariable, but in any case (b) the - // constant we would be replacing is the initializer constant of the - // OpVariable, and this cannot be the result of a binary operation. - if (instruction->opcode() == SpvOpVariable) { - return false; - } - - return true; -} - -void TransformationReplaceBooleanConstantWithConstantBinary::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - ApplyWithResult(ir_context, transformation_context); -} - -opt::Instruction* -TransformationReplaceBooleanConstantWithConstantBinary::ApplyWithResult( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - opt::analysis::Bool bool_type; - opt::Instruction::OperandList operands = { - {SPV_OPERAND_TYPE_ID, {message_.lhs_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.rhs_id()}}}; - auto binary_instruction = MakeUnique( - ir_context, static_cast(message_.opcode()), - ir_context->get_type_mgr()->GetId(&bool_type), - message_.fresh_id_for_binary_operation(), operands); - opt::Instruction* result = binary_instruction.get(); - auto instruction_containing_constant_use = - FindInstructionContainingUse(message_.id_use_descriptor(), ir_context); - auto instruction_before_which_to_insert = instruction_containing_constant_use; - - // If |instruction_before_which_to_insert| is an OpPhi instruction, - // then |binary_instruction| will be inserted into the parent block associated - // with the OpPhi variable operand. - if (instruction_containing_constant_use->opcode() == SpvOpPhi) { - instruction_before_which_to_insert = - ir_context->cfg() - ->block(instruction_containing_constant_use->GetSingleWordInOperand( - message_.id_use_descriptor().in_operand_index() + 1)) - ->terminator(); - } - - // We want to insert the new instruction before the instruction that contains - // the use of the boolean, but we need to go backwards one more instruction if - // the using instruction is preceded by a merge instruction. - { - opt::Instruction* previous_node = - instruction_before_which_to_insert->PreviousNode(); - if (previous_node && (previous_node->opcode() == SpvOpLoopMerge || - previous_node->opcode() == SpvOpSelectionMerge)) { - instruction_before_which_to_insert = previous_node; - } - } - - instruction_before_which_to_insert->InsertBefore( - std::move(binary_instruction)); - instruction_containing_constant_use->SetInOperand( - message_.id_use_descriptor().in_operand_index(), - {message_.fresh_id_for_binary_operation()}); - fuzzerutil::UpdateModuleIdBound(ir_context, - message_.fresh_id_for_binary_operation()); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - return result; -} - -protobufs::Transformation -TransformationReplaceBooleanConstantWithConstantBinary::ToMessage() const { - protobufs::Transformation result; - *result.mutable_replace_boolean_constant_with_constant_binary() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h deleted file mode 100644 index 3abb4854b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ -#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_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 TransformationReplaceBooleanConstantWithConstantBinary - : public Transformation { - public: - explicit TransformationReplaceBooleanConstantWithConstantBinary( - const protobufs::TransformationReplaceBooleanConstantWithConstantBinary& - message); - - TransformationReplaceBooleanConstantWithConstantBinary( - const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id, - uint32_t rhs_id, SpvOp comparison_opcode, - uint32_t fresh_id_for_binary_operation); - - // - |message_.fresh_id_for_binary_operation| must not already be used by the - // module. - // - |message_.id_use_descriptor| must identify a use of a boolean constant c. - // - |message_.lhs_id| and |message.rhs_id| must be the ids of constant - // instructions with the same type - // - |message_.opcode| must be suitable for applying to |message.lhs_id| and - // |message_.rhs_id|, and the result must evaluate to the boolean constant - // c. - // - The boolean constant usage must not be an argument to OpPhi, because in - // this case it is not legal to insert a binary operator instruction right - // before the OpPhi. - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2902): consider - // replacing a boolean in an OpPhi by adding a binary operator instruction - // to the parent block for the OpPhi. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // A new instruction is added before the boolean constant usage that computes - // the result of applying |message_.opcode| to |message_.lhs_id| and - // |message_.rhs_id| is added, with result id - // |message_.fresh_id_for_binary_operation|. The boolean constant usage is - // replaced with this result id. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - // The same as Apply, except that the newly-added binary instruction is - // returned. - opt::Instruction* ApplyWithResult( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationReplaceBooleanConstantWithConstantBinary message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp deleted file mode 100644 index 8de7201b8..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_constant_with_uniform.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/uniform_buffer_element_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationReplaceConstantWithUniform:: - TransformationReplaceConstantWithUniform( - const spvtools::fuzz::protobufs:: - TransformationReplaceConstantWithUniform& message) - : message_(message) {} - -TransformationReplaceConstantWithUniform:: - TransformationReplaceConstantWithUniform( - protobufs::IdUseDescriptor id_use, - protobufs::UniformBufferElementDescriptor uniform_descriptor, - uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load) { - *message_.mutable_id_use_descriptor() = std::move(id_use); - *message_.mutable_uniform_descriptor() = std::move(uniform_descriptor); - message_.set_fresh_id_for_access_chain(fresh_id_for_access_chain); - message_.set_fresh_id_for_load(fresh_id_for_load); -} - -std::unique_ptr -TransformationReplaceConstantWithUniform::MakeAccessChainInstruction( - spvtools::opt::IRContext* ir_context, uint32_t constant_type_id) const { - // The input operands for the access chain. - opt::Instruction::OperandList operands_for_access_chain; - - opt::Instruction* uniform_variable = - FindUniformVariable(message_.uniform_descriptor(), ir_context, false); - - // The first input operand is the id of the uniform variable. - operands_for_access_chain.push_back( - {SPV_OPERAND_TYPE_ID, {uniform_variable->result_id()}}); - - // The other input operands are the ids of the constants used to index into - // the uniform. The uniform buffer descriptor specifies a series of literals; - // for each we find the id of the instruction that defines it, and add these - // instruction ids as operands. - opt::analysis::Integer int_type(32, true); - auto registered_int_type = - ir_context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger(); - auto int_type_id = ir_context->get_type_mgr()->GetId(&int_type); - for (auto index : message_.uniform_descriptor().index()) { - opt::analysis::IntConstant int_constant(registered_int_type, {index}); - auto constant_id = ir_context->get_constant_mgr()->FindDeclaredConstant( - &int_constant, int_type_id); - operands_for_access_chain.push_back({SPV_OPERAND_TYPE_ID, {constant_id}}); - } - - // The type id for the access chain is a uniform pointer with base type - // matching the given constant id type. - auto type_and_pointer_type = - ir_context->get_type_mgr()->GetTypeAndPointerType(constant_type_id, - SpvStorageClassUniform); - assert(type_and_pointer_type.first != nullptr); - assert(type_and_pointer_type.second != nullptr); - auto pointer_to_uniform_constant_type_id = - ir_context->get_type_mgr()->GetId(type_and_pointer_type.second.get()); - - return MakeUnique( - ir_context, SpvOpAccessChain, pointer_to_uniform_constant_type_id, - message_.fresh_id_for_access_chain(), operands_for_access_chain); -} - -std::unique_ptr -TransformationReplaceConstantWithUniform::MakeLoadInstruction( - spvtools::opt::IRContext* ir_context, uint32_t constant_type_id) const { - opt::Instruction::OperandList operands_for_load = { - {SPV_OPERAND_TYPE_ID, {message_.fresh_id_for_access_chain()}}}; - return MakeUnique(ir_context, SpvOpLoad, constant_type_id, - message_.fresh_id_for_load(), - operands_for_load); -} - -opt::Instruction* -TransformationReplaceConstantWithUniform::GetInsertBeforeInstruction( - opt::IRContext* ir_context) const { - auto* result = - FindInstructionContainingUse(message_.id_use_descriptor(), ir_context); - if (!result) { - return nullptr; - } - - // The use might be in an OpPhi instruction. - if (result->opcode() == SpvOpPhi) { - // OpPhi instructions must be the first instructions in a block. Thus, we - // can't insert above the OpPhi instruction. Given the predecessor block - // that corresponds to the id use, get the last instruction in that block - // above which we can insert OpAccessChain and OpLoad. - return fuzzerutil::GetLastInsertBeforeInstruction( - ir_context, - result->GetSingleWordInOperand( - message_.id_use_descriptor().in_operand_index() + 1), - SpvOpLoad); - } - - // The only operand that we could've replaced in the OpBranchConditional is - // the condition id. But that operand has a boolean type and uniform variables - // can't store booleans (see the spec on OpTypeBool). Thus, |result| can't be - // an OpBranchConditional. - assert(result->opcode() != SpvOpBranchConditional && - "OpBranchConditional has no operands to replace"); - - assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, result) && - "We should be able to insert OpLoad and OpAccessChain at this point"); - return result; -} - -bool TransformationReplaceConstantWithUniform::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // The following is really an invariant of the transformation rather than - // merely a requirement of the precondition. We check it here since we cannot - // check it in the message_ constructor. - assert(message_.fresh_id_for_access_chain() != message_.fresh_id_for_load() && - "Fresh ids for access chain and load result cannot be the same."); - - // The ids for the access chain and load instructions must both be fresh. - if (!fuzzerutil::IsFreshId(ir_context, - message_.fresh_id_for_access_chain())) { - return false; - } - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id_for_load())) { - return false; - } - - // The id specified in the id use descriptor must be that of a declared scalar - // constant. - auto declared_constant = ir_context->get_constant_mgr()->FindDeclaredConstant( - message_.id_use_descriptor().id_of_interest()); - if (!declared_constant) { - return false; - } - if (!declared_constant->AsScalarConstant()) { - return false; - } - - // The fact manager needs to believe that the uniform data element described - // by the uniform buffer element descriptor will hold a scalar value. - auto constant_id_associated_with_uniform = - transformation_context.GetFactManager()->GetConstantFromUniformDescriptor( - ir_context, message_.uniform_descriptor()); - if (!constant_id_associated_with_uniform) { - return false; - } - auto constant_associated_with_uniform = - ir_context->get_constant_mgr()->FindDeclaredConstant( - constant_id_associated_with_uniform); - assert(constant_associated_with_uniform && - "The constant should be present in the module."); - if (!constant_associated_with_uniform->AsScalarConstant()) { - return false; - } - - // The types and values of the scalar value held in the id specified by the id - // use descriptor and in the uniform data element specified by the uniform - // buffer element descriptor need to match on both type and value. - if (!declared_constant->type()->IsSame( - constant_associated_with_uniform->type())) { - return false; - } - if (declared_constant->AsScalarConstant()->words() != - constant_associated_with_uniform->AsScalarConstant()->words()) { - return false; - } - - // The id use descriptor must identify some instruction with respect to the - // module. - auto instruction_using_constant = - FindInstructionContainingUse(message_.id_use_descriptor(), ir_context); - if (!instruction_using_constant) { - return false; - } - - // The use must not be a variable initializer; these are required to be - // constants, so it would be illegal to replace one with a uniform access. - if (instruction_using_constant->opcode() == SpvOpVariable) { - return false; - } - - // The module needs to have a uniform pointer type suitable for indexing into - // the uniform variable, i.e. matching the type of the constant we wish to - // replace with a uniform. - opt::analysis::Pointer pointer_to_type_of_constant(declared_constant->type(), - SpvStorageClassUniform); - if (!ir_context->get_type_mgr()->GetId(&pointer_to_type_of_constant)) { - return false; - } - - // In order to index into the uniform, the module has got to contain the int32 - // type, plus an OpConstant for each of the indices of interest. - opt::analysis::Integer int_type(32, true); - if (!ir_context->get_type_mgr()->GetId(&int_type)) { - return false; - } - auto registered_int_type = - ir_context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger(); - auto int_type_id = ir_context->get_type_mgr()->GetId(&int_type); - for (auto index : message_.uniform_descriptor().index()) { - opt::analysis::IntConstant int_constant(registered_int_type, {index}); - if (!ir_context->get_constant_mgr()->FindDeclaredConstant(&int_constant, - int_type_id)) { - return false; - } - } - - // Once all checks are completed, we should be able to safely insert - // OpAccessChain and OpLoad into the module. - assert(GetInsertBeforeInstruction(ir_context) && - "There must exist an instruction that we can use to insert " - "OpAccessChain and OpLoad above"); - - return true; -} - -void TransformationReplaceConstantWithUniform::Apply( - spvtools::opt::IRContext* ir_context, - TransformationContext* /*unused*/) const { - // Get the instruction that contains the id use we wish to replace. - auto* instruction_containing_constant_use = - FindInstructionContainingUse(message_.id_use_descriptor(), ir_context); - assert(instruction_containing_constant_use && - "Precondition requires that the id use can be found."); - assert(instruction_containing_constant_use->GetSingleWordInOperand( - message_.id_use_descriptor().in_operand_index()) == - message_.id_use_descriptor().id_of_interest() && - "Does not appear to be a usage of the desired id."); - - // The id of the type for the constant whose use we wish to replace. - auto constant_type_id = - ir_context->get_def_use_mgr() - ->GetDef(message_.id_use_descriptor().id_of_interest()) - ->type_id(); - - // Get an instruction that will be used to insert OpAccessChain and OpLoad. - auto* insert_before_inst = GetInsertBeforeInstruction(ir_context); - assert(insert_before_inst && - "There must exist an insertion point for OpAccessChain and OpLoad"); - - // Add an access chain instruction to target the uniform element. - insert_before_inst->InsertBefore( - MakeAccessChainInstruction(ir_context, constant_type_id)); - - // Add a load from this access chain. - insert_before_inst->InsertBefore( - MakeLoadInstruction(ir_context, constant_type_id)); - - // Adjust the instruction containing the usage of the constant so that this - // usage refers instead to the result of the load. - instruction_containing_constant_use->SetInOperand( - message_.id_use_descriptor().in_operand_index(), - {message_.fresh_id_for_load()}); - - // Update the module id bound to reflect the new instructions. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id_for_load()); - fuzzerutil::UpdateModuleIdBound(ir_context, - message_.fresh_id_for_access_chain()); - - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationReplaceConstantWithUniform::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_replace_constant_with_uniform() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h deleted file mode 100644 index b27fb6949..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h +++ /dev/null @@ -1,97 +0,0 @@ -#include - -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_ -#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_ - -#include "source/fuzz/id_use_descriptor.h" -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/fuzz/transformation.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -class TransformationReplaceConstantWithUniform : public Transformation { - public: - explicit TransformationReplaceConstantWithUniform( - const protobufs::TransformationReplaceConstantWithUniform& message); - - TransformationReplaceConstantWithUniform( - protobufs::IdUseDescriptor id_use, - protobufs::UniformBufferElementDescriptor uniform_descriptor, - uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load); - - // - |message_.fresh_id_for_access_chain| and |message_.fresh_id_for_load| - // must be distinct fresh ids. - // - |message_.uniform_descriptor| specifies a result id and a list of integer - // literal indices. - // As an example, suppose |message_.uniform_descriptor| is (18, [0, 1, 0]) - // It is required that: - // - the result id (18 in our example) is the id of some uniform variable - // - the module contains an integer constant instruction corresponding to - // each of the literal indices; in our example there must thus be - // OpConstant instructions %A and %B say for each of 0 and 1 - // - it is legitimate to index into the uniform variable using the - // sequence of indices; in our example this means indexing into %18 - // using the sequence %A %B %A - // - the module contains a uniform pointer type corresponding to the type - // of the uniform data element obtained by following these indices - // - |message_.id_use_descriptor| identifies the use of some id %C. It is - // required that: - // - this use does indeed exist in the module - // - %C is an OpConstant - // - According to the fact manager, the uniform data element specified by - // |message_.uniform_descriptor| holds a value with the same type and - // value as %C - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - Introduces two new instructions: - // - An access chain targeting the uniform data element specified by - // |message_.uniform_descriptor|, with result id - // |message_.fresh_id_for_access_chain| - // - A load from this access chain, with id |message_.fresh_id_for_load| - // - Replaces the id use specified by |message_.id_use_descriptor| with - // |message_.fresh_id_for_load| - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Helper method to create an access chain for the uniform element associated - // with the transformation. - std::unique_ptr MakeAccessChainInstruction( - spvtools::opt::IRContext* ir_context, uint32_t constant_type_id) const; - - // Helper to create a load instruction. - std::unique_ptr MakeLoadInstruction( - spvtools::opt::IRContext* ir_context, uint32_t constant_type_id) const; - - // OpAccessChain and OpLoad will be inserted above the instruction returned - // by this function. Returns nullptr if no such instruction is present. - opt::Instruction* GetInsertBeforeInstruction( - opt::IRContext* ir_context) const; - - protobufs::TransformationReplaceConstantWithUniform message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp deleted file mode 100644 index bf6996ad3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_copy_memory_with_load_store.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationReplaceCopyMemoryWithLoadStore:: - TransformationReplaceCopyMemoryWithLoadStore( - const spvtools::fuzz::protobufs:: - TransformationReplaceCopyMemoryWithLoadStore& message) - : message_(message) {} - -TransformationReplaceCopyMemoryWithLoadStore:: - TransformationReplaceCopyMemoryWithLoadStore( - uint32_t fresh_id, const protobufs::InstructionDescriptor& - copy_memory_instruction_descriptor) { - message_.set_fresh_id(fresh_id); - *message_.mutable_copy_memory_instruction_descriptor() = - copy_memory_instruction_descriptor; -} - -bool TransformationReplaceCopyMemoryWithLoadStore::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |message_.fresh_id| must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // The instruction to be replaced must be defined and have opcode - // OpCopyMemory. - auto copy_memory_instruction = FindInstruction( - message_.copy_memory_instruction_descriptor(), ir_context); - if (!copy_memory_instruction || - copy_memory_instruction->opcode() != SpvOpCopyMemory) { - return false; - } - return true; -} - -void TransformationReplaceCopyMemoryWithLoadStore::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto copy_memory_instruction = FindInstruction( - message_.copy_memory_instruction_descriptor(), ir_context); - // |copy_memory_instruction| must be defined. - assert(copy_memory_instruction && - copy_memory_instruction->opcode() == SpvOpCopyMemory && - "The required OpCopyMemory instruction must be defined."); - - // Coherence check: Both operands must be pointers. - - // Get types of ids used as a source and target of |copy_memory_instruction|. - auto target = ir_context->get_def_use_mgr()->GetDef( - copy_memory_instruction->GetSingleWordInOperand(0)); - auto source = ir_context->get_def_use_mgr()->GetDef( - copy_memory_instruction->GetSingleWordInOperand(1)); - auto target_type_opcode = - ir_context->get_def_use_mgr()->GetDef(target->type_id())->opcode(); - auto source_type_opcode = - ir_context->get_def_use_mgr()->GetDef(source->type_id())->opcode(); - - // Keep release-mode compilers happy. (No unused variables.) - (void)target; - (void)source; - (void)target_type_opcode; - (void)source_type_opcode; - - assert(target_type_opcode == SpvOpTypePointer && - source_type_opcode == SpvOpTypePointer && - "Operands must be of type OpTypePointer"); - - // Coherence check: |source| and |target| must point to the same type. - uint32_t target_pointee_type = fuzzerutil::GetPointeeTypeIdFromPointerType( - ir_context, target->type_id()); - uint32_t source_pointee_type = fuzzerutil::GetPointeeTypeIdFromPointerType( - ir_context, source->type_id()); - - // Keep release-mode compilers happy. (No unused variables.) - (void)target_pointee_type; - (void)source_pointee_type; - - assert(target_pointee_type == source_pointee_type && - "Operands must have the same type to which they point to."); - - // First, insert the OpStore instruction before the OpCopyMemory instruction - // and then insert the OpLoad instruction before the OpStore instruction. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - FindInstruction(message_.copy_memory_instruction_descriptor(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {target->result_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}}))) - ->InsertBefore(MakeUnique( - ir_context, SpvOpLoad, target_pointee_type, message_.fresh_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {source->result_id()}}}))); - - // Remove the OpCopyMemory instruction. - ir_context->KillInst(copy_memory_instruction); - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation -TransformationReplaceCopyMemoryWithLoadStore::ToMessage() const { - protobufs::Transformation result; - *result.mutable_replace_copy_memory_with_load_store() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_memory_with_load_store.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_memory_with_load_store.h deleted file mode 100644 index 70120f8df..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_memory_with_load_store.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_TRANSFORMATION_REPLACE_COPY_MEMORY_WITH_LOAD_STORE_H -#define SPIRV_TOOLS_TRANSFORMATION_REPLACE_COPY_MEMORY_WITH_LOAD_STORE_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 TransformationReplaceCopyMemoryWithLoadStore : public Transformation { - public: - explicit TransformationReplaceCopyMemoryWithLoadStore( - const protobufs::TransformationReplaceCopyMemoryWithLoadStore& message); - - TransformationReplaceCopyMemoryWithLoadStore( - uint32_t fresh_id, const protobufs::InstructionDescriptor& - copy_memory_instruction_descriptor); - - // - |message_.fresh_id| must be fresh. - // - |message_.copy_memory_instruction_descriptor| must refer to an - // OpCopyMemory instruction. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces instruction OpCopyMemory with loading the source variable to an - // intermediate value and storing this value into the target variable of the - // original OpCopyMemory instruction. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationReplaceCopyMemoryWithLoadStore message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_TRANSFORMATION_REPLACE_COPY_MEMORY_WITH_LOAD_STORE_H diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_object_with_store_load.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_object_with_store_load.cpp deleted file mode 100644 index 6bf7d46d4..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_object_with_store_load.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_copy_object_with_store_load.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationReplaceCopyObjectWithStoreLoad:: - TransformationReplaceCopyObjectWithStoreLoad( - const spvtools::fuzz::protobufs:: - TransformationReplaceCopyObjectWithStoreLoad& message) - : message_(message) {} - -TransformationReplaceCopyObjectWithStoreLoad:: - TransformationReplaceCopyObjectWithStoreLoad( - uint32_t copy_object_result_id, uint32_t fresh_variable_id, - uint32_t variable_storage_class, uint32_t variable_initializer_id) { - message_.set_copy_object_result_id(copy_object_result_id); - message_.set_fresh_variable_id(fresh_variable_id); - message_.set_variable_storage_class(variable_storage_class); - message_.set_variable_initializer_id(variable_initializer_id); -} - -bool TransformationReplaceCopyObjectWithStoreLoad::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |message_.fresh_variable_id| must be fresh. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_variable_id())) { - return false; - } - auto copy_object_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.copy_object_result_id()); - - // This must be a defined OpCopyObject instruction. - if (!copy_object_instruction || - copy_object_instruction->opcode() != SpvOpCopyObject) { - return false; - } - - // The opcode of the type_id instruction cannot be a OpTypePointer, - // because we cannot define a pointer to pointer. - if (ir_context->get_def_use_mgr() - ->GetDef(copy_object_instruction->type_id()) - ->opcode() == SpvOpTypePointer) { - return false; - } - - // A pointer type instruction pointing to the value type must be defined. - auto pointer_type_id = fuzzerutil::MaybeGetPointerType( - ir_context, copy_object_instruction->type_id(), - static_cast(message_.variable_storage_class())); - if (!pointer_type_id) { - return false; - } - - // Check that initializer is valid. - const auto* constant_inst = - ir_context->get_def_use_mgr()->GetDef(message_.variable_initializer_id()); - if (!constant_inst || !spvOpcodeIsConstant(constant_inst->opcode()) || - copy_object_instruction->type_id() != constant_inst->type_id()) { - return false; - } - // |message_.variable_storage_class| must be Private or Function. - return message_.variable_storage_class() == SpvStorageClassPrivate || - message_.variable_storage_class() == SpvStorageClassFunction; -} - -void TransformationReplaceCopyObjectWithStoreLoad::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - auto copy_object_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.copy_object_result_id()); - // |copy_object_instruction| must be defined. - assert(copy_object_instruction && - copy_object_instruction->opcode() == SpvOpCopyObject && - "The required OpCopyObject instruction must be defined."); - // Get id used as a source by the OpCopyObject instruction. - uint32_t src_operand = copy_object_instruction->GetSingleWordOperand(2); - // A pointer type instruction pointing to the value type must be defined. - auto pointer_type_id = fuzzerutil::MaybeGetPointerType( - ir_context, copy_object_instruction->type_id(), - static_cast(message_.variable_storage_class())); - assert(pointer_type_id && "The required pointer type must be available."); - - // Adds a global or local variable (according to the storage class). - if (message_.variable_storage_class() == SpvStorageClassPrivate) { - fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_variable_id(), - pointer_type_id, SpvStorageClassPrivate, - message_.variable_initializer_id()); - } else { - auto function_id = ir_context->get_instr_block(copy_object_instruction) - ->GetParent() - ->result_id(); - fuzzerutil::AddLocalVariable(ir_context, message_.fresh_variable_id(), - pointer_type_id, function_id, - message_.variable_initializer_id()); - } - - // First, insert the OpLoad instruction before the OpCopyObject instruction - // and then insert the OpStore instruction before the OpLoad instruction. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_variable_id()); - copy_object_instruction - ->InsertBefore(MakeUnique( - ir_context, SpvOpLoad, copy_object_instruction->type_id(), - message_.copy_object_result_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}}))) - ->InsertBefore(MakeUnique( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}, - {SPV_OPERAND_TYPE_ID, {src_operand}}}))); - // Remove the CopyObject instruction. - ir_context->KillInst(copy_object_instruction); - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - - // Adds the fact that |message_.copy_object_result_id| - // and src_operand (id used by OpCopyObject) are synonymous. - transformation_context->GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(message_.copy_object_result_id(), {}), - MakeDataDescriptor(src_operand, {}), ir_context); -} - -protobufs::Transformation -TransformationReplaceCopyObjectWithStoreLoad::ToMessage() const { - protobufs::Transformation result; - *result.mutable_replace_copy_object_with_store_load() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_object_with_store_load.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_object_with_store_load.h deleted file mode 100644 index db9c74eea..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_copy_object_with_store_load.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_TRANSFORMATION_REPLACE_COPY_OBJECT_WITH_STORE_LOAD_H -#define SPIRV_TOOLS_TRANSFORMATION_REPLACE_COPY_OBJECT_WITH_STORE_LOAD_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 TransformationReplaceCopyObjectWithStoreLoad : public Transformation { - public: - explicit TransformationReplaceCopyObjectWithStoreLoad( - const protobufs::TransformationReplaceCopyObjectWithStoreLoad& message); - - TransformationReplaceCopyObjectWithStoreLoad( - uint32_t copy_object_result_id, uint32_t fresh_variable_id, - uint32_t variable_storage_class, uint32_t variable_initializer_id); - - // - |message_.copy_object_result_id| must be a result id of an OpCopyObject - // instruction. - // - |message_.fresh_variable_id| must be a fresh id given to variable used by - // OpStore. - // - |message_.variable_storage_class| must be either StorageClassPrivate or - // StorageClassFunction. - // - |message_.initializer_id| must be a result id of some constant in the - // module. Its type must be equal to the pointee type of the variable that - // will be created. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces instruction OpCopyObject with storing into a new variable and - // immediately loading from this variable to |result_id| of the original - // OpCopyObject instruction. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationReplaceCopyObjectWithStoreLoad message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_TRANSFORMATION_REPLACE_COPY_OBJECT_WITH_STORE_LOAD_H diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp deleted file mode 100644 index 8ebfbe03f..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_id_with_synonym.h" - -#include - -#include "source/fuzz/data_descriptor.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/id_use_descriptor.h" -#include "source/opt/types.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { - -TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym( - const spvtools::fuzz::protobufs::TransformationReplaceIdWithSynonym& - message) - : message_(message) {} - -TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym( - protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id) { - *message_.mutable_id_use_descriptor() = std::move(id_use_descriptor); - message_.set_synonymous_id(synonymous_id); -} - -bool TransformationReplaceIdWithSynonym::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - auto id_of_interest = message_.id_use_descriptor().id_of_interest(); - - // Does the fact manager know about the synonym? - auto data_descriptor_for_synonymous_id = - MakeDataDescriptor(message_.synonymous_id(), {}); - if (!transformation_context.GetFactManager()->IsSynonymous( - MakeDataDescriptor(id_of_interest, {}), - data_descriptor_for_synonymous_id)) { - return false; - } - - // Does the id use descriptor in the transformation identify an instruction? - auto use_instruction = - FindInstructionContainingUse(message_.id_use_descriptor(), ir_context); - if (!use_instruction) { - return false; - } - - uint32_t type_id_of_interest = - ir_context->get_def_use_mgr()->GetDef(id_of_interest)->type_id(); - uint32_t type_id_synonym = ir_context->get_def_use_mgr() - ->GetDef(message_.synonymous_id()) - ->type_id(); - - // 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)) { - return false; - } - - // Is the use suitable for being replaced in principle? - if (!UseCanBeReplacedWithSynonym( - ir_context, use_instruction, - message_.id_use_descriptor().in_operand_index())) { - return false; - } - - // The transformation is applicable if the synonymous id is available at the - // use point. - return fuzzerutil::IdIsAvailableAtUse( - ir_context, use_instruction, - message_.id_use_descriptor().in_operand_index(), - message_.synonymous_id()); -} - -void TransformationReplaceIdWithSynonym::Apply( - spvtools::opt::IRContext* ir_context, - TransformationContext* /*unused*/) const { - auto instruction_to_change = - FindInstructionContainingUse(message_.id_use_descriptor(), ir_context); - instruction_to_change->SetInOperand( - message_.id_use_descriptor().in_operand_index(), - {message_.synonymous_id()}); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_replace_id_with_synonym() = message_; - return result; -} - -bool TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym( - opt::IRContext* ir_context, opt::Instruction* use_instruction, - uint32_t use_in_operand_index) { - if (spvOpcodeIsAccessChain(use_instruction->opcode()) && - use_in_operand_index > 0) { - // This is an access chain index. If the (sub-)object being accessed by the - // given index has struct type then we cannot replace the use with a - // synonym, as the use needs to be an OpConstant. - - // Get the top-level composite type that is being accessed. - auto object_being_accessed = ir_context->get_def_use_mgr()->GetDef( - use_instruction->GetSingleWordInOperand(0)); - auto pointer_type = - ir_context->get_type_mgr()->GetType(object_being_accessed->type_id()); - assert(pointer_type->AsPointer()); - auto composite_type_being_accessed = - pointer_type->AsPointer()->pointee_type(); - - // Now walk the access chain, tracking the type of each sub-object of the - // composite that is traversed, until the index of interest is reached. - for (uint32_t index_in_operand = 1; index_in_operand < use_in_operand_index; - index_in_operand++) { - // For vectors, matrices and arrays, getting the type of the sub-object is - // trivial. For the struct case, the sub-object type is field-sensitive, - // and depends on the constant index that is used. - if (composite_type_being_accessed->AsVector()) { - composite_type_being_accessed = - composite_type_being_accessed->AsVector()->element_type(); - } else if (composite_type_being_accessed->AsMatrix()) { - composite_type_being_accessed = - composite_type_being_accessed->AsMatrix()->element_type(); - } else if (composite_type_being_accessed->AsArray()) { - composite_type_being_accessed = - composite_type_being_accessed->AsArray()->element_type(); - } else if (composite_type_being_accessed->AsRuntimeArray()) { - composite_type_being_accessed = - composite_type_being_accessed->AsRuntimeArray()->element_type(); - } else { - assert(composite_type_being_accessed->AsStruct()); - auto constant_index_instruction = ir_context->get_def_use_mgr()->GetDef( - use_instruction->GetSingleWordInOperand(index_in_operand)); - assert(constant_index_instruction->opcode() == SpvOpConstant); - uint32_t member_index = - constant_index_instruction->GetSingleWordInOperand(0); - composite_type_being_accessed = - composite_type_being_accessed->AsStruct() - ->element_types()[member_index]; - } - } - - // We have found the composite type being accessed by the index we are - // considering replacing. If it is a struct, then we cannot do the - // replacement as struct indices must be constants. - if (composite_type_being_accessed->AsStruct()) { - return false; - } - } - - if (use_instruction->opcode() == SpvOpFunctionCall && - use_in_operand_index > 0) { - // This is a function call argument. It is not allowed to have pointer - // type. - - // Get the definition of the function being called. - auto function = ir_context->get_def_use_mgr()->GetDef( - use_instruction->GetSingleWordInOperand(0)); - // From the function definition, get the function type. - auto function_type = ir_context->get_def_use_mgr()->GetDef( - function->GetSingleWordInOperand(1)); - // OpTypeFunction's 0-th input operand is the function return type, and the - // function argument types follow. Because the arguments to OpFunctionCall - // start from input operand 1, we can use |use_in_operand_index| to get the - // type associated with this function argument. - auto parameter_type = ir_context->get_type_mgr()->GetType( - function_type->GetSingleWordInOperand(use_in_operand_index)); - if (parameter_type->AsPointer()) { - return false; - } - } - - if (use_instruction->opcode() == SpvOpImageTexelPointer && - use_in_operand_index == 2) { - // The OpImageTexelPointer instruction has a Sample parameter that in some - // situations must be an id for the value 0. To guard against disrupting - // that requirement, we do not replace this argument to that instruction. - return false; - } - - return true; -} - -// 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)); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h deleted file mode 100644 index fe3fac052..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_ -#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_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 TransformationReplaceIdWithSynonym : public Transformation { - public: - explicit TransformationReplaceIdWithSynonym( - const protobufs::TransformationReplaceIdWithSynonym& message); - - TransformationReplaceIdWithSynonym( - protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id); - - // - The fact manager must know that the id identified by - // |message_.id_use_descriptor| is synonomous with - // |message_.synonymous_id|. - // - Replacing the id in |message_.id_use_descriptor| by - // |message_.synonymous_id| must respect SPIR-V's rules about uses being - // dominated by their definitions. - // - The id must not be an index into an access chain whose base object has - // struct type, as such indices must be constants. - // - The id must not be a pointer argument to a function call (because the - // synonym might not be a memory object declaration). - // - |fresh_id_for_temporary| must be 0. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces the use identified by |message_.id_use_descriptor| with the - // synonymous id identified by |message_.synonymous_id|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Checks whether various conditions hold related to the acceptability of - // replacing the id use at |use_in_operand_index| of |use_instruction| with - // a synonym. In particular, this checks that: - // - the id use is not an index into a struct field in an OpAccessChain - such - // indices must be constants, so it is dangerous to replace them. - // - the id use is not a pointer function call argument, on which there are - // restrictions that make replacement problematic. - static bool UseCanBeReplacedWithSynonym(opt::IRContext* ir_context, - opt::Instruction* use_instruction, - 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). - 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_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.cpp deleted file mode 100644 index e78573c7b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_linear_algebra_instruction.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationReplaceLinearAlgebraInstruction:: - TransformationReplaceLinearAlgebraInstruction( - const spvtools::fuzz::protobufs:: - TransformationReplaceLinearAlgebraInstruction& message) - : message_(message) {} - -TransformationReplaceLinearAlgebraInstruction:: - TransformationReplaceLinearAlgebraInstruction( - const std::vector& fresh_ids, - const protobufs::InstructionDescriptor& instruction_descriptor) { - for (auto fresh_id : fresh_ids) { - message_.add_fresh_ids(fresh_id); - } - *message_.mutable_instruction_descriptor() = instruction_descriptor; -} - -bool TransformationReplaceLinearAlgebraInstruction::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - auto instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - - // It must be a linear algebra instruction. - if (!spvOpcodeIsLinearAlgebra(instruction->opcode())) { - return false; - } - - // |message_.fresh_ids.size| must be the exact number of fresh ids needed to - // apply the transformation. - if (static_cast(message_.fresh_ids().size()) != - GetRequiredFreshIdCount(ir_context, instruction)) { - return false; - } - - // All ids in |message_.fresh_ids| must be fresh. - for (uint32_t fresh_id : message_.fresh_ids()) { - if (!fuzzerutil::IsFreshId(ir_context, fresh_id)) { - return false; - } - } - - return true; -} - -void TransformationReplaceLinearAlgebraInstruction::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto linear_algebra_instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - - switch (linear_algebra_instruction->opcode()) { - case SpvOpTranspose: - ReplaceOpTranspose(ir_context, linear_algebra_instruction); - break; - case SpvOpVectorTimesScalar: - ReplaceOpVectorTimesScalar(ir_context, linear_algebra_instruction); - break; - case SpvOpMatrixTimesScalar: - ReplaceOpMatrixTimesScalar(ir_context, linear_algebra_instruction); - break; - case SpvOpVectorTimesMatrix: - ReplaceOpVectorTimesMatrix(ir_context, linear_algebra_instruction); - break; - case SpvOpMatrixTimesVector: - ReplaceOpMatrixTimesVector(ir_context, linear_algebra_instruction); - break; - case SpvOpMatrixTimesMatrix: - ReplaceOpMatrixTimesMatrix(ir_context, linear_algebra_instruction); - break; - case SpvOpOuterProduct: - ReplaceOpOuterProduct(ir_context, linear_algebra_instruction); - break; - case SpvOpDot: - ReplaceOpDot(ir_context, linear_algebra_instruction); - break; - default: - assert(false && "Should be unreachable."); - break; - } - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation -TransformationReplaceLinearAlgebraInstruction::ToMessage() const { - protobufs::Transformation result; - *result.mutable_replace_linear_algebra_instruction() = message_; - return result; -} - -uint32_t TransformationReplaceLinearAlgebraInstruction::GetRequiredFreshIdCount( - opt::IRContext* ir_context, opt::Instruction* instruction) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354): - // Right now we only support certain operations. - switch (instruction->opcode()) { - case SpvOpTranspose: { - // For each matrix row, |2 * matrix_column_count| OpCompositeExtract and 1 - // OpCompositeConstruct will be inserted. - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(0)); - uint32_t matrix_column_count = - ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_count(); - uint32_t matrix_row_count = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_type() - ->AsVector() - ->element_count(); - return matrix_row_count * (2 * matrix_column_count + 1); - } - case SpvOpVectorTimesScalar: - // For each vector component, 1 OpCompositeExtract and 1 OpFMul will be - // inserted. - return 2 * - ir_context->get_type_mgr() - ->GetType(ir_context->get_def_use_mgr() - ->GetDef(instruction->GetSingleWordInOperand(0)) - ->type_id()) - ->AsVector() - ->element_count(); - case SpvOpMatrixTimesScalar: { - // For each matrix column, |1 + column.size| OpCompositeExtract, - // |column.size| OpFMul and 1 OpCompositeConstruct instructions will be - // inserted. - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(0)); - auto matrix_type = - ir_context->get_type_mgr()->GetType(matrix_instruction->type_id()); - return 2 * matrix_type->AsMatrix()->element_count() * - (1 + matrix_type->AsMatrix() - ->element_type() - ->AsVector() - ->element_count()); - } - case SpvOpVectorTimesMatrix: { - // For each vector component, 1 OpCompositeExtract instruction will be - // inserted. For each matrix column, |1 + vector_component_count| - // OpCompositeExtract, |vector_component_count| OpFMul and - // |vector_component_count - 1| OpFAdd instructions will be inserted. - auto vector_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(0)); - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(1)); - uint32_t vector_component_count = - ir_context->get_type_mgr() - ->GetType(vector_instruction->type_id()) - ->AsVector() - ->element_count(); - uint32_t matrix_column_count = - ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_count(); - return vector_component_count * (3 * matrix_column_count + 1); - } - case SpvOpMatrixTimesVector: { - // For each matrix column, |1 + matrix_row_count| OpCompositeExtract - // will be inserted. For each matrix row, |matrix_column_count| OpFMul and - // |matrix_column_count - 1| OpFAdd instructions will be inserted. For - // each vector component, 1 OpCompositeExtract instruction will be - // inserted. - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(0)); - uint32_t matrix_column_count = - ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_count(); - uint32_t matrix_row_count = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_type() - ->AsVector() - ->element_count(); - return 3 * matrix_column_count * matrix_row_count + - 2 * matrix_column_count - matrix_row_count; - } - case SpvOpMatrixTimesMatrix: { - // For each matrix 2 column, 1 OpCompositeExtract, 1 OpCompositeConstruct, - // |3 * matrix_1_row_count * matrix_1_column_count| OpCompositeExtract, - // |matrix_1_row_count * matrix_1_column_count| OpFMul, - // |matrix_1_row_count * (matrix_1_column_count - 1)| OpFAdd instructions - // will be inserted. - auto matrix_1_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(0)); - uint32_t matrix_1_column_count = - ir_context->get_type_mgr() - ->GetType(matrix_1_instruction->type_id()) - ->AsMatrix() - ->element_count(); - uint32_t matrix_1_row_count = - ir_context->get_type_mgr() - ->GetType(matrix_1_instruction->type_id()) - ->AsMatrix() - ->element_type() - ->AsVector() - ->element_count(); - - auto matrix_2_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(1)); - uint32_t matrix_2_column_count = - ir_context->get_type_mgr() - ->GetType(matrix_2_instruction->type_id()) - ->AsMatrix() - ->element_count(); - return matrix_2_column_count * - (2 + matrix_1_row_count * (5 * matrix_1_column_count - 1)); - } - case SpvOpOuterProduct: { - // For each |vector_2| component, |vector_1_component_count + 1| - // OpCompositeExtract, |vector_1_component_count| OpFMul and 1 - // OpCompositeConstruct instructions will be inserted. - auto vector_1_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(0)); - auto vector_2_instruction = ir_context->get_def_use_mgr()->GetDef( - instruction->GetSingleWordInOperand(1)); - uint32_t vector_1_component_count = - ir_context->get_type_mgr() - ->GetType(vector_1_instruction->type_id()) - ->AsVector() - ->element_count(); - uint32_t vector_2_component_count = - ir_context->get_type_mgr() - ->GetType(vector_2_instruction->type_id()) - ->AsVector() - ->element_count(); - return 2 * vector_2_component_count * (vector_1_component_count + 1); - } - case SpvOpDot: - // For each pair of vector components, 2 OpCompositeExtract and 1 OpFMul - // will be inserted. The first two OpFMul instructions will result the - // first OpFAdd instruction to be inserted. For each remaining OpFMul, 1 - // OpFAdd will be inserted. The last OpFAdd instruction is got by changing - // the OpDot instruction. - return 4 * ir_context->get_type_mgr() - ->GetType( - ir_context->get_def_use_mgr() - ->GetDef(instruction->GetSingleWordInOperand(0)) - ->type_id()) - ->AsVector() - ->element_count() - - 2; - default: - assert(false && "Unsupported linear algebra instruction."); - return 0; - } -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpTranspose( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets OpTranspose instruction information. - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - uint32_t matrix_column_count = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_count(); - auto matrix_column_type = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_type(); - auto matrix_column_component_type = - matrix_column_type->AsVector()->element_type(); - uint32_t matrix_row_count = matrix_column_type->AsVector()->element_count(); - auto resulting_matrix_column_type = - ir_context->get_type_mgr() - ->GetType(linear_algebra_instruction->type_id()) - ->AsMatrix() - ->element_type(); - - uint32_t fresh_id_index = 0; - std::vector result_column_ids(matrix_row_count); - for (uint32_t i = 0; i < matrix_row_count; i++) { - std::vector column_component_ids(matrix_column_count); - for (uint32_t j = 0; j < matrix_column_count; j++) { - // Extracts the matrix column. - uint32_t matrix_column_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_column_type), - matrix_column_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}}))); - - // Extracts the matrix column component. - column_component_ids[j] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_column_component_type), - column_component_ids[j], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_column_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - } - - // Inserts the resulting matrix column. - opt::Instruction::OperandList in_operands; - for (auto& column_component_id : column_component_ids) { - in_operands.push_back({SPV_OPERAND_TYPE_ID, {column_component_id}}); - } - result_column_ids[i] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeConstruct, - ir_context->get_type_mgr()->GetId(resulting_matrix_column_type), - result_column_ids[i], opt::Instruction::OperandList(in_operands))); - } - - // The OpTranspose instruction is changed to an OpCompositeConstruct - // instruction. - linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct); - linear_algebra_instruction->SetInOperand(0, {result_column_ids[0]}); - for (uint32_t i = 1; i < result_column_ids.size(); i++) { - linear_algebra_instruction->AddOperand( - {SPV_OPERAND_TYPE_ID, {result_column_ids[i]}}); - } - - fuzzerutil::UpdateModuleIdBound( - ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1)); -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpVectorTimesScalar( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets OpVectorTimesScalar in operands. - auto vector = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - auto scalar = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(1)); - - uint32_t vector_component_count = ir_context->get_type_mgr() - ->GetType(vector->type_id()) - ->AsVector() - ->element_count(); - std::vector float_multiplication_ids(vector_component_count); - uint32_t fresh_id_index = 0; - - for (uint32_t i = 0; i < vector_component_count; i++) { - // Extracts |vector| component. - uint32_t vector_extract_id = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, vector_extract_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, scalar->type_id(), vector_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - // Multiplies the |vector| component with the |scalar|. - uint32_t float_multiplication_id = message_.fresh_ids(fresh_id_index++); - float_multiplication_ids[i] = float_multiplication_id; - fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFMul, scalar->type_id(), float_multiplication_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_extract_id}}, - {SPV_OPERAND_TYPE_ID, {scalar->result_id()}}}))); - } - - // The OpVectorTimesScalar instruction is changed to an OpCompositeConstruct - // instruction. - linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct); - linear_algebra_instruction->SetInOperand(0, {float_multiplication_ids[0]}); - linear_algebra_instruction->SetInOperand(1, {float_multiplication_ids[1]}); - for (uint32_t i = 2; i < float_multiplication_ids.size(); i++) { - linear_algebra_instruction->AddOperand( - {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[i]}}); - } -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpMatrixTimesScalar( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets OpMatrixTimesScalar in operands. - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - auto scalar_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(1)); - - // Gets matrix information. - uint32_t matrix_column_count = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_count(); - auto matrix_column_type = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_type(); - uint32_t matrix_column_size = matrix_column_type->AsVector()->element_count(); - - std::vector composite_construct_ids(matrix_column_count); - uint32_t fresh_id_index = 0; - - for (uint32_t i = 0; i < matrix_column_count; i++) { - // Extracts |matrix| column. - uint32_t matrix_extract_id = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, matrix_extract_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_column_type), - matrix_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - std::vector float_multiplication_ids(matrix_column_size); - - for (uint32_t j = 0; j < matrix_column_size; j++) { - // Extracts |column| component. - uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, column_extract_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, scalar_instruction->type_id(), - column_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_extract_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}}))); - - // Multiplies the |column| component with the |scalar|. - float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_ids[j]); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFMul, scalar_instruction->type_id(), - float_multiplication_ids[j], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {column_extract_id}}, - {SPV_OPERAND_TYPE_ID, {scalar_instruction->result_id()}}}))); - } - - // Constructs a new column multiplied by |scalar|. - opt::Instruction::OperandList composite_construct_in_operands; - for (uint32_t& float_multiplication_id : float_multiplication_ids) { - composite_construct_in_operands.push_back( - {SPV_OPERAND_TYPE_ID, {float_multiplication_id}}); - } - composite_construct_ids[i] = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, composite_construct_ids[i]); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeConstruct, - ir_context->get_type_mgr()->GetId(matrix_column_type), - composite_construct_ids[i], composite_construct_in_operands)); - } - - // The OpMatrixTimesScalar instruction is changed to an OpCompositeConstruct - // instruction. - linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct); - linear_algebra_instruction->SetInOperand(0, {composite_construct_ids[0]}); - linear_algebra_instruction->SetInOperand(1, {composite_construct_ids[1]}); - for (uint32_t i = 2; i < composite_construct_ids.size(); i++) { - linear_algebra_instruction->AddOperand( - {SPV_OPERAND_TYPE_ID, {composite_construct_ids[i]}}); - } -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpVectorTimesMatrix( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets vector information. - auto vector_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - uint32_t vector_component_count = ir_context->get_type_mgr() - ->GetType(vector_instruction->type_id()) - ->AsVector() - ->element_count(); - auto vector_component_type = ir_context->get_type_mgr() - ->GetType(vector_instruction->type_id()) - ->AsVector() - ->element_type(); - - // Extracts vector components. - uint32_t fresh_id_index = 0; - std::vector vector_component_ids(vector_component_count); - for (uint32_t i = 0; i < vector_component_count; i++) { - vector_component_ids[i] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(vector_component_type), - vector_component_ids[i], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - } - - // Gets matrix information. - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(1)); - uint32_t matrix_column_count = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_count(); - auto matrix_column_type = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_type(); - - std::vector result_component_ids(matrix_column_count); - for (uint32_t i = 0; i < matrix_column_count; i++) { - // Extracts matrix column. - uint32_t matrix_extract_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_column_type), - matrix_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - std::vector float_multiplication_ids(vector_component_count); - for (uint32_t j = 0; j < vector_component_count; j++) { - // Extracts column component. - uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(vector_component_type), - column_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_extract_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}}))); - - // Multiplies corresponding vector and column components. - float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFMul, - ir_context->get_type_mgr()->GetId(vector_component_type), - float_multiplication_ids[j], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_component_ids[j]}}, - {SPV_OPERAND_TYPE_ID, {column_extract_id}}}))); - } - - // Adds the multiplication results. - std::vector float_add_ids; - uint32_t float_add_id = message_.fresh_ids(fresh_id_index++); - float_add_ids.push_back(float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, - ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}}, - {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}}))); - for (uint32_t j = 2; j < float_multiplication_ids.size(); j++) { - float_add_id = message_.fresh_ids(fresh_id_index++); - float_add_ids.push_back(float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, - ir_context->get_type_mgr()->GetId(vector_component_type), - float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[j]}}, - {SPV_OPERAND_TYPE_ID, {float_add_ids[j - 2]}}}))); - } - - result_component_ids[i] = float_add_ids.back(); - } - - // The OpVectorTimesMatrix instruction is changed to an OpCompositeConstruct - // instruction. - linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct); - linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]}); - linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]}); - for (uint32_t i = 2; i < result_component_ids.size(); i++) { - linear_algebra_instruction->AddOperand( - {SPV_OPERAND_TYPE_ID, {result_component_ids[i]}}); - } - - fuzzerutil::UpdateModuleIdBound( - ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1)); -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpMatrixTimesVector( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets matrix information. - auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - uint32_t matrix_column_count = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_count(); - auto matrix_column_type = ir_context->get_type_mgr() - ->GetType(matrix_instruction->type_id()) - ->AsMatrix() - ->element_type(); - uint32_t matrix_row_count = matrix_column_type->AsVector()->element_count(); - - // Extracts matrix columns. - uint32_t fresh_id_index = 0; - std::vector matrix_column_ids(matrix_column_count); - for (uint32_t i = 0; i < matrix_column_count; i++) { - matrix_column_ids[i] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_column_type), - matrix_column_ids[i], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - } - - // Gets vector information. - auto vector_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(1)); - auto vector_component_type = ir_context->get_type_mgr() - ->GetType(vector_instruction->type_id()) - ->AsVector() - ->element_type(); - - // Extracts vector components. - std::vector vector_component_ids(matrix_column_count); - for (uint32_t i = 0; i < matrix_column_count; i++) { - vector_component_ids[i] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(vector_component_type), - vector_component_ids[i], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - } - - std::vector result_component_ids(matrix_row_count); - for (uint32_t i = 0; i < matrix_row_count; i++) { - std::vector float_multiplication_ids(matrix_column_count); - for (uint32_t j = 0; j < matrix_column_count; j++) { - // Extracts column component. - uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(vector_component_type), - column_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_column_ids[j]}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - // Multiplies corresponding vector and column components. - float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFMul, - ir_context->get_type_mgr()->GetId(vector_component_type), - float_multiplication_ids[j], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {column_extract_id}}, - {SPV_OPERAND_TYPE_ID, {vector_component_ids[j]}}}))); - } - - // Adds the multiplication results. - std::vector float_add_ids; - uint32_t float_add_id = message_.fresh_ids(fresh_id_index++); - float_add_ids.push_back(float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, - ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}}, - {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}}))); - for (uint32_t j = 2; j < float_multiplication_ids.size(); j++) { - float_add_id = message_.fresh_ids(fresh_id_index++); - float_add_ids.push_back(float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, - ir_context->get_type_mgr()->GetId(vector_component_type), - float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[j]}}, - {SPV_OPERAND_TYPE_ID, {float_add_ids[j - 2]}}}))); - } - - result_component_ids[i] = float_add_ids.back(); - } - - // The OpMatrixTimesVector instruction is changed to an OpCompositeConstruct - // instruction. - linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct); - linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]}); - linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]}); - for (uint32_t i = 2; i < result_component_ids.size(); i++) { - linear_algebra_instruction->AddOperand( - {SPV_OPERAND_TYPE_ID, {result_component_ids[i]}}); - } - - fuzzerutil::UpdateModuleIdBound( - ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1)); -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpMatrixTimesMatrix( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets matrix 1 information. - auto matrix_1_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - uint32_t matrix_1_column_count = - ir_context->get_type_mgr() - ->GetType(matrix_1_instruction->type_id()) - ->AsMatrix() - ->element_count(); - auto matrix_1_column_type = ir_context->get_type_mgr() - ->GetType(matrix_1_instruction->type_id()) - ->AsMatrix() - ->element_type(); - auto matrix_1_column_component_type = - matrix_1_column_type->AsVector()->element_type(); - uint32_t matrix_1_row_count = - matrix_1_column_type->AsVector()->element_count(); - - // Gets matrix 2 information. - auto matrix_2_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(1)); - uint32_t matrix_2_column_count = - ir_context->get_type_mgr() - ->GetType(matrix_2_instruction->type_id()) - ->AsMatrix() - ->element_count(); - auto matrix_2_column_type = ir_context->get_type_mgr() - ->GetType(matrix_2_instruction->type_id()) - ->AsMatrix() - ->element_type(); - - uint32_t fresh_id_index = 0; - std::vector result_column_ids(matrix_2_column_count); - for (uint32_t i = 0; i < matrix_2_column_count; i++) { - // Extracts matrix 2 column. - uint32_t matrix_2_column_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_2_column_type), - matrix_2_column_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_2_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - std::vector column_component_ids(matrix_1_row_count); - for (uint32_t j = 0; j < matrix_1_row_count; j++) { - std::vector float_multiplication_ids(matrix_1_column_count); - for (uint32_t k = 0; k < matrix_1_column_count; k++) { - // Extracts matrix 1 column. - uint32_t matrix_1_column_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_1_column_type), - matrix_1_column_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_1_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {k}}}))); - - // Extracts matrix 1 column component. - uint32_t matrix_1_column_component_id = - message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_1_column_component_type), - matrix_1_column_component_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_1_column_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}}))); - - // Extracts matrix 2 column component. - uint32_t matrix_2_column_component_id = - message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(matrix_1_column_component_type), - matrix_2_column_component_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_2_column_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {k}}}))); - - // Multiplies corresponding matrix 1 and matrix 2 column components. - float_multiplication_ids[k] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFMul, - ir_context->get_type_mgr()->GetId(matrix_1_column_component_type), - float_multiplication_ids[k], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {matrix_1_column_component_id}}, - {SPV_OPERAND_TYPE_ID, {matrix_2_column_component_id}}}))); - } - - // Adds the multiplication results. - std::vector float_add_ids; - uint32_t float_add_id = message_.fresh_ids(fresh_id_index++); - float_add_ids.push_back(float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, - ir_context->get_type_mgr()->GetId(matrix_1_column_component_type), - float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}}, - {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}}))); - for (uint32_t k = 2; k < float_multiplication_ids.size(); k++) { - float_add_id = message_.fresh_ids(fresh_id_index++); - float_add_ids.push_back(float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, - ir_context->get_type_mgr()->GetId(matrix_1_column_component_type), - float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[k]}}, - {SPV_OPERAND_TYPE_ID, {float_add_ids[k - 2]}}}))); - } - - column_component_ids[j] = float_add_ids.back(); - } - - // Inserts the resulting matrix column. - opt::Instruction::OperandList in_operands; - for (auto& column_component_id : column_component_ids) { - in_operands.push_back({SPV_OPERAND_TYPE_ID, {column_component_id}}); - } - result_column_ids[i] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeConstruct, - ir_context->get_type_mgr()->GetId(matrix_1_column_type), - result_column_ids[i], opt::Instruction::OperandList(in_operands))); - } - - // The OpMatrixTimesMatrix instruction is changed to an OpCompositeConstruct - // instruction. - linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct); - linear_algebra_instruction->SetInOperand(0, {result_column_ids[0]}); - linear_algebra_instruction->SetInOperand(1, {result_column_ids[1]}); - for (uint32_t i = 2; i < result_column_ids.size(); i++) { - linear_algebra_instruction->AddOperand( - {SPV_OPERAND_TYPE_ID, {result_column_ids[i]}}); - } - - fuzzerutil::UpdateModuleIdBound( - ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1)); -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpOuterProduct( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets vector 1 information. - auto vector_1_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - uint32_t vector_1_component_count = - ir_context->get_type_mgr() - ->GetType(vector_1_instruction->type_id()) - ->AsVector() - ->element_count(); - auto vector_1_component_type = ir_context->get_type_mgr() - ->GetType(vector_1_instruction->type_id()) - ->AsVector() - ->element_type(); - - // Gets vector 2 information. - auto vector_2_instruction = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(1)); - uint32_t vector_2_component_count = - ir_context->get_type_mgr() - ->GetType(vector_2_instruction->type_id()) - ->AsVector() - ->element_count(); - - uint32_t fresh_id_index = 0; - std::vector result_column_ids(vector_2_component_count); - for (uint32_t i = 0; i < vector_2_component_count; i++) { - // Extracts |vector_2| component. - uint32_t vector_2_component_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(vector_1_component_type), - vector_2_component_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_2_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - std::vector column_component_ids(vector_1_component_count); - for (uint32_t j = 0; j < vector_1_component_count; j++) { - // Extracts |vector_1| component. - uint32_t vector_1_component_id = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - ir_context->get_type_mgr()->GetId(vector_1_component_type), - vector_1_component_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_1_instruction->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}}))); - - // Multiplies |vector_1| and |vector_2| components. - column_component_ids[j] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFMul, - ir_context->get_type_mgr()->GetId(vector_1_component_type), - column_component_ids[j], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_2_component_id}}, - {SPV_OPERAND_TYPE_ID, {vector_1_component_id}}}))); - } - - // Inserts the resulting matrix column. - opt::Instruction::OperandList in_operands; - for (auto& column_component_id : column_component_ids) { - in_operands.push_back({SPV_OPERAND_TYPE_ID, {column_component_id}}); - } - result_column_ids[i] = message_.fresh_ids(fresh_id_index++); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeConstruct, vector_1_instruction->type_id(), - result_column_ids[i], in_operands)); - } - - // The OpOuterProduct instruction is changed to an OpCompositeConstruct - // instruction. - linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct); - linear_algebra_instruction->SetInOperand(0, {result_column_ids[0]}); - linear_algebra_instruction->SetInOperand(1, {result_column_ids[1]}); - for (uint32_t i = 2; i < result_column_ids.size(); i++) { - linear_algebra_instruction->AddOperand( - {SPV_OPERAND_TYPE_ID, {result_column_ids[i]}}); - } - - fuzzerutil::UpdateModuleIdBound( - ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1)); -} - -void TransformationReplaceLinearAlgebraInstruction::ReplaceOpDot( - opt::IRContext* ir_context, - opt::Instruction* linear_algebra_instruction) const { - // Gets OpDot in operands. - auto vector_1 = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(0)); - auto vector_2 = ir_context->get_def_use_mgr()->GetDef( - linear_algebra_instruction->GetSingleWordInOperand(1)); - - uint32_t vectors_component_count = ir_context->get_type_mgr() - ->GetType(vector_1->type_id()) - ->AsVector() - ->element_count(); - std::vector float_multiplication_ids(vectors_component_count); - uint32_t fresh_id_index = 0; - - for (uint32_t i = 0; i < vectors_component_count; i++) { - // Extracts |vector_1| component. - uint32_t vector_1_extract_id = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, vector_1_extract_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - linear_algebra_instruction->type_id(), vector_1_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_1->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - // Extracts |vector_2| component. - uint32_t vector_2_extract_id = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, vector_2_extract_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, - linear_algebra_instruction->type_id(), vector_2_extract_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_2->result_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}}))); - - // Multiplies the pair of components. - float_multiplication_ids[i] = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_ids[i]); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFMul, linear_algebra_instruction->type_id(), - float_multiplication_ids[i], - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {vector_1_extract_id}}, - {SPV_OPERAND_TYPE_ID, {vector_2_extract_id}}}))); - } - - // If the vector has 2 components, then there will be 2 float multiplication - // instructions. - if (vectors_component_count == 2) { - linear_algebra_instruction->SetOpcode(SpvOpFAdd); - linear_algebra_instruction->SetInOperand(0, {float_multiplication_ids[0]}); - linear_algebra_instruction->SetInOperand(1, {float_multiplication_ids[1]}); - } else { - // The first OpFAdd instruction has as operands the first two OpFMul - // instructions. - std::vector float_add_ids; - uint32_t float_add_id = message_.fresh_ids(fresh_id_index++); - float_add_ids.push_back(float_add_id); - fuzzerutil::UpdateModuleIdBound(ir_context, float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, linear_algebra_instruction->type_id(), - float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}}, - {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}}))); - - // The remaining OpFAdd instructions has as operands an OpFMul and an OpFAdd - // instruction. - for (uint32_t i = 2; i < float_multiplication_ids.size() - 1; i++) { - float_add_id = message_.fresh_ids(fresh_id_index++); - fuzzerutil::UpdateModuleIdBound(ir_context, float_add_id); - float_add_ids.push_back(float_add_id); - linear_algebra_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpFAdd, linear_algebra_instruction->type_id(), - float_add_id, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[i]}}, - {SPV_OPERAND_TYPE_ID, {float_add_ids[i - 2]}}}))); - } - - // The last OpFAdd instruction is got by changing some of the OpDot - // instruction attributes. - linear_algebra_instruction->SetOpcode(SpvOpFAdd); - linear_algebra_instruction->SetInOperand( - 0, {float_multiplication_ids[float_multiplication_ids.size() - 1]}); - linear_algebra_instruction->SetInOperand( - 1, {float_add_ids[float_add_ids.size() - 1]}); - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.h deleted file mode 100644 index 05ebdd7fc..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_LINEAR_ALGEBRA_INSTRUCTION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_LINEAR_ALGEBRA_INSTRUCTION_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 TransformationReplaceLinearAlgebraInstruction : public Transformation { - public: - explicit TransformationReplaceLinearAlgebraInstruction( - const protobufs::TransformationReplaceLinearAlgebraInstruction& message); - - TransformationReplaceLinearAlgebraInstruction( - const std::vector& fresh_ids, - const protobufs::InstructionDescriptor& instruction_descriptor); - - // - |message_.fresh_ids| must be fresh ids needed to apply the - // transformation. - // - |message_.instruction_descriptor| must be a linear algebra instruction - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces a linear algebra instruction. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns the number of ids needed to apply the transformation. - static uint32_t GetRequiredFreshIdCount(opt::IRContext* ir_context, - opt::Instruction* instruction); - - private: - protobufs::TransformationReplaceLinearAlgebraInstruction message_; - - // Replaces an OpTranspose instruction. - void ReplaceOpTranspose(opt::IRContext* ir_context, - opt::Instruction* instruction) const; - - // Replaces an OpVectorTimesScalar instruction. - void ReplaceOpVectorTimesScalar(opt::IRContext* ir_context, - opt::Instruction* instruction) const; - - // Replaces an OpMatrixTimesScalar instruction. - void ReplaceOpMatrixTimesScalar(opt::IRContext* ir_context, - opt::Instruction* instruction) const; - - // Replaces an OpVectorTimesMatrix instruction. - void ReplaceOpVectorTimesMatrix(opt::IRContext* ir_context, - opt::Instruction* instruction) const; - - // Replaces an OpMatrixTimesVector instruction. - void ReplaceOpMatrixTimesVector(opt::IRContext* ir_context, - opt::Instruction* instruction) const; - - // Replaces an OpMatrixTimesMatrix instruction. - void ReplaceOpMatrixTimesMatrix(opt::IRContext* ir_context, - opt::Instruction* instruction) const; - - // Replaces an OpOuterProduct instruction. - void ReplaceOpOuterProduct(opt::IRContext* ir_context, - opt::Instruction* instruction) const; - - // Replaces an OpDot instruction. - void ReplaceOpDot(opt::IRContext* ir_context, - opt::Instruction* instruction) const; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_LINEAR_ALGEBRA_INSTRUCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp deleted file mode 100644 index a42ffb11b..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2020 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 "transformation_replace_load_store_with_copy_memory.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/opcode.h" - -namespace spvtools { -namespace fuzz { - -namespace { -const uint32_t kOpStoreOperandIndexTargetVariable = 0; -const uint32_t kOpStoreOperandIndexIntermediateIdToWrite = 1; -const uint32_t kOpLoadOperandIndexSourceVariable = 2; -} // namespace - -TransformationReplaceLoadStoreWithCopyMemory:: - TransformationReplaceLoadStoreWithCopyMemory( - const spvtools::fuzz::protobufs:: - TransformationReplaceLoadStoreWithCopyMemory& message) - : message_(message) {} - -TransformationReplaceLoadStoreWithCopyMemory:: - TransformationReplaceLoadStoreWithCopyMemory( - const protobufs::InstructionDescriptor& load_instruction_descriptor, - const protobufs::InstructionDescriptor& store_instruction_descriptor) { - *message_.mutable_load_instruction_descriptor() = load_instruction_descriptor; - *message_.mutable_store_instruction_descriptor() = - store_instruction_descriptor; -} -bool TransformationReplaceLoadStoreWithCopyMemory::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // This transformation is only applicable to the pair of OpLoad and OpStore - // instructions. - - // The OpLoad instruction must be defined. - auto load_instruction = - FindInstruction(message_.load_instruction_descriptor(), ir_context); - if (!load_instruction || load_instruction->opcode() != SpvOpLoad) { - return false; - } - - // The OpStore instruction must be defined. - auto store_instruction = - FindInstruction(message_.store_instruction_descriptor(), ir_context); - if (!store_instruction || store_instruction->opcode() != SpvOpStore) { - return false; - } - - // Intermediate values of the OpLoad and the OpStore must match. - if (load_instruction->result_id() != - store_instruction->GetSingleWordOperand( - kOpStoreOperandIndexIntermediateIdToWrite)) { - return false; - } - - // Get storage class of the variable pointed by the source operand in OpLoad. - opt::Instruction* source_id = ir_context->get_def_use_mgr()->GetDef( - load_instruction->GetSingleWordOperand(2)); - SpvStorageClass storage_class = fuzzerutil::GetStorageClassFromPointerType( - ir_context, source_id->type_id()); - - // Iterate over all instructions between |load_instruction| and - // |store_instruction|. - for (auto it = load_instruction; it != store_instruction; - it = it->NextNode()) { - //|load_instruction| and |store_instruction| are not in the same block. - if (it == nullptr) { - return false; - } - - // We need to make sure that the value pointed to by the source of the - // OpLoad hasn't changed by the time we see the matching OpStore - // instruction. - if (IsMemoryWritingOpCode(it->opcode())) { - return false; - } else if (IsMemoryBarrierOpCode(it->opcode()) && - !IsStorageClassSafeAcrossMemoryBarriers(storage_class)) { - return false; - } - } - return true; -} - -void TransformationReplaceLoadStoreWithCopyMemory::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // OpLoad and OpStore instructions must be defined. - auto load_instruction = - FindInstruction(message_.load_instruction_descriptor(), ir_context); - assert(load_instruction && load_instruction->opcode() == SpvOpLoad && - "The required OpLoad instruction must be defined."); - auto store_instruction = - FindInstruction(message_.store_instruction_descriptor(), ir_context); - assert(store_instruction && store_instruction->opcode() == SpvOpStore && - "The required OpStore instruction must be defined."); - - // Intermediate values of the OpLoad and the OpStore must match. - assert(load_instruction->result_id() == - store_instruction->GetSingleWordOperand( - kOpStoreOperandIndexIntermediateIdToWrite) && - "OpLoad and OpStore must refer to the same value."); - - // Get the ids of the source operand of the OpLoad and the target operand of - // the OpStore. - uint32_t source_variable_id = - load_instruction->GetSingleWordOperand(kOpLoadOperandIndexSourceVariable); - uint32_t target_variable_id = store_instruction->GetSingleWordOperand( - kOpStoreOperandIndexTargetVariable); - - // Insert the OpCopyMemory instruction before the OpStore instruction. - store_instruction->InsertBefore(MakeUnique( - ir_context, SpvOpCopyMemory, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {target_variable_id}}, - {SPV_OPERAND_TYPE_ID, {source_variable_id}}}))); - - // Remove the OpStore instruction. - ir_context->KillInst(store_instruction); - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -bool TransformationReplaceLoadStoreWithCopyMemory::IsMemoryWritingOpCode( - SpvOp op_code) { - if (spvOpcodeIsAtomicOp(op_code)) { - return op_code != SpvOpAtomicLoad; - } - switch (op_code) { - case SpvOpStore: - case SpvOpCopyMemory: - case SpvOpCopyMemorySized: - return true; - default: - return false; - } -} - -bool TransformationReplaceLoadStoreWithCopyMemory::IsMemoryBarrierOpCode( - SpvOp op_code) { - switch (op_code) { - case SpvOpMemoryBarrier: - case SpvOpMemoryNamedBarrier: - return true; - default: - return false; - } -} - -bool TransformationReplaceLoadStoreWithCopyMemory:: - IsStorageClassSafeAcrossMemoryBarriers(SpvStorageClass storage_class) { - switch (storage_class) { - case SpvStorageClassUniformConstant: - case SpvStorageClassInput: - case SpvStorageClassUniform: - case SpvStorageClassPrivate: - case SpvStorageClassFunction: - return true; - default: - return false; - } -} - -protobufs::Transformation -TransformationReplaceLoadStoreWithCopyMemory::ToMessage() const { - protobufs::Transformation result; - *result.mutable_replace_load_store_with_copy_memory() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_load_store_with_copy_memory.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_load_store_with_copy_memory.h deleted file mode 100644 index 0fb9a0991..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_load_store_with_copy_memory.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2020 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 SPIRV_TOOLS_TRANSFORMATION_REPLACE_LOAD_STORE_WITH_COPY_MEMORY_H -#define SPIRV_TOOLS_TRANSFORMATION_REPLACE_LOAD_STORE_WITH_COPY_MEMORY_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 TransformationReplaceLoadStoreWithCopyMemory : public Transformation { - public: - explicit TransformationReplaceLoadStoreWithCopyMemory( - const protobufs::TransformationReplaceLoadStoreWithCopyMemory& message); - - TransformationReplaceLoadStoreWithCopyMemory( - const protobufs::InstructionDescriptor& load_instruction_descriptor, - const protobufs::InstructionDescriptor& store_instruction_descriptor); - - // - |message_.load_instruction_descriptor| must identify an OpLoad - // instruction. - // - |message_.store_instruction_descriptor| must identify an OpStore - // instruction. - // - The OpStore must write the intermediate value loaded by the OpLoad. - // - The OpLoad and the OpStore must not have certain instruction in between - // (checked by IsMemoryWritingOpCode(), IsMemoryBarrierOpCode(), - // IsStorageClassSafeAcrossMemoryBarriers()). - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Takes a pair of instruction descriptors to OpLoad and OpStore that have the - // same intermediate value and replaces the OpStore with an equivalent - // OpCopyMemory. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - // Checks if the instruction that has an |op_code| might write to - // the source operand of the OpLoad instruction. - static bool IsMemoryWritingOpCode(SpvOp op_code); - - // Checks if the instruction that has an |op_code| is a memory barrier that - // could interfere with the source operand of the OpLoad instruction - static bool IsMemoryBarrierOpCode(SpvOp op_code); - - // Checks if the |storage_class| of the source operand of the OpLoad - // instruction implies that this variable cannot change (due to other threads) - // across memory barriers. - static bool IsStorageClassSafeAcrossMemoryBarriers( - SpvStorageClass storage_class); - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationReplaceLoadStoreWithCopyMemory message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SPIRV_TOOLS_TRANSFORMATION_REPLACE_LOAD_STORE_WITH_COPY_MEMORY_H diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.cpp deleted file mode 100644 index 9db2434b8..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_parameter_with_global.h" - -#include - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationReplaceParameterWithGlobal:: - TransformationReplaceParameterWithGlobal( - const protobufs::TransformationReplaceParameterWithGlobal& message) - : message_(message) {} - -TransformationReplaceParameterWithGlobal:: - TransformationReplaceParameterWithGlobal( - uint32_t function_type_fresh_id, uint32_t parameter_id, - uint32_t global_variable_fresh_id) { - message_.set_function_type_fresh_id(function_type_fresh_id); - message_.set_parameter_id(parameter_id); - message_.set_global_variable_fresh_id(global_variable_fresh_id); -} - -bool TransformationReplaceParameterWithGlobal::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // Check that |parameter_id| is valid. - const auto* param_inst = - ir_context->get_def_use_mgr()->GetDef(message_.parameter_id()); - if (!param_inst || param_inst->opcode() != SpvOpFunctionParameter) { - return false; - } - - // Check that function exists and is not an entry point. - const auto* function = fuzzerutil::GetFunctionFromParameterId( - ir_context, message_.parameter_id()); - if (!function || - fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) { - return false; - } - - // We already know that the function has at least one parameter - - // |parameter_id|. - - // Check that replaced parameter has valid type. - const auto* param_type = - ir_context->get_type_mgr()->GetType(param_inst->type_id()); - assert(param_type && "Parameter has invalid type"); - if (!IsParameterTypeSupported(*param_type)) { - return false; - } - - // Check that initializer for the global variable exists in the module. - if (fuzzerutil::MaybeGetZeroConstant(ir_context, transformation_context, - param_inst->type_id(), false) == 0) { - return false; - } - - // Check that pointer type for the global variable exists in the module. - if (!fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(), - SpvStorageClassPrivate)) { - return false; - } - - return fuzzerutil::IsFreshId(ir_context, message_.function_type_fresh_id()) && - fuzzerutil::IsFreshId(ir_context, - message_.global_variable_fresh_id()) && - message_.function_type_fresh_id() != - message_.global_variable_fresh_id(); -} - -void TransformationReplaceParameterWithGlobal::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - const auto* param_inst = - ir_context->get_def_use_mgr()->GetDef(message_.parameter_id()); - assert(param_inst && "Parameter must exist"); - - // Create global variable to store parameter's value. - fuzzerutil::AddGlobalVariable( - ir_context, message_.global_variable_fresh_id(), - fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(), - SpvStorageClassPrivate), - SpvStorageClassPrivate, - fuzzerutil::MaybeGetZeroConstant(ir_context, *transformation_context, - param_inst->type_id(), false)); - - // Mark the global variable's pointee as irrelevant if replaced parameter is - // irrelevant. - if (transformation_context->GetFactManager()->IdIsIrrelevant( - message_.parameter_id())) { - transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( - message_.global_variable_fresh_id()); - } - - auto* function = fuzzerutil::GetFunctionFromParameterId( - ir_context, message_.parameter_id()); - assert(function && "Function must exist"); - - // Insert an OpLoad instruction right after OpVariable instructions. - auto it = function->begin()->begin(); - while (it != function->begin()->end() && - !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it)) { - ++it; - } - - assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it) && - "Can't insert OpLoad or OpCopyMemory into the first basic block of " - "the function"); - - it.InsertBefore(MakeUnique( - ir_context, SpvOpLoad, param_inst->type_id(), param_inst->result_id(), - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}}})); - - // Calculate the index of the replaced parameter (we need to know this to - // remove operands from the OpFunctionCall). - auto params = fuzzerutil::GetParameters(ir_context, function->result_id()); - auto parameter_index = static_cast(params.size()); - for (uint32_t i = 0, n = static_cast(params.size()); i < n; ++i) { - if (params[i]->result_id() == message_.parameter_id()) { - parameter_index = i; - break; - } - } - - assert(parameter_index != params.size() && - "Parameter must exist in the function"); - - // Update all relevant OpFunctionCall instructions. - for (auto* inst : fuzzerutil::GetCallers(ir_context, function->result_id())) { - assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, inst) && - "Can't insert OpStore right before the function call"); - - // Insert an OpStore before the OpFunctionCall. +1 since the first - // operand of OpFunctionCall is an id of the function. - inst->InsertBefore(MakeUnique( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}}, - {SPV_OPERAND_TYPE_ID, - {inst->GetSingleWordInOperand(parameter_index + 1)}}})); - - // +1 since the first operand of OpFunctionCall is an id of the - // function. - inst->RemoveInOperand(parameter_index + 1); - } - - // Remove the parameter from the function. - fuzzerutil::RemoveParameter(ir_context, message_.parameter_id()); - - // Update function's type. - { - // We use a separate scope here since |old_function_type| might become a - // dangling pointer after the call to the fuzzerutil::UpdateFunctionType. - - auto* old_function_type = fuzzerutil::GetFunctionType(ir_context, function); - assert(old_function_type && "Function has invalid type"); - - // +1 and -1 since the first operand is the return type id. - std::vector parameter_type_ids; - for (uint32_t i = 1; i < old_function_type->NumInOperands(); ++i) { - if (i - 1 != parameter_index) { - parameter_type_ids.push_back( - old_function_type->GetSingleWordInOperand(i)); - } - } - - fuzzerutil::UpdateFunctionType( - ir_context, function->result_id(), message_.function_type_fresh_id(), - old_function_type->GetSingleWordInOperand(0), parameter_type_ids); - } - - // Make sure our changes are analyzed - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationReplaceParameterWithGlobal::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_replace_parameter_with_global() = message_; - return result; -} - -bool TransformationReplaceParameterWithGlobal::IsParameterTypeSupported( - const opt::analysis::Type& type) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403): - // Think about other type instructions we can add here. - switch (type.kind()) { - case opt::analysis::Type::kBool: - case opt::analysis::Type::kInteger: - case opt::analysis::Type::kFloat: - case opt::analysis::Type::kArray: - case opt::analysis::Type::kMatrix: - case opt::analysis::Type::kVector: - return true; - case opt::analysis::Type::kStruct: - return std::all_of(type.AsStruct()->element_types().begin(), - type.AsStruct()->element_types().end(), - [](const opt::analysis::Type* element_type) { - return IsParameterTypeSupported(*element_type); - }); - default: - return false; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.h deleted file mode 100644 index 49e7585ae..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_H_ -#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_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 TransformationReplaceParameterWithGlobal : public Transformation { - public: - explicit TransformationReplaceParameterWithGlobal( - const protobufs::TransformationReplaceParameterWithGlobal& message); - - TransformationReplaceParameterWithGlobal(uint32_t function_type_fresh_id, - uint32_t parameter_id, - uint32_t global_variable_fresh_id); - - // - |function_type_fresh_id| is a fresh id. - // - |parameter_id| is the result id of the parameter to replace. - // - |global_variable_fresh_id| is a fresh id. - // - |function_type_fresh_id| is not equal to |global_variable_fresh_id|. - // - the function that contains |parameter_id| may not be an entry-point - // function. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - Removes parameter with result id |parameter_id| from its function - // - Adds a global variable to store the value for the parameter - // - Add an OpStore instruction before each function call to - // store parameter's value into the variable - // - Adds OpLoad at the beginning of the function to load the - // value from the variable into the old parameter's id - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if the type of the parameter is supported by this - // transformation. - static bool IsParameterTypeSupported(const opt::analysis::Type& type); - - private: - protobufs::TransformationReplaceParameterWithGlobal message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_params_with_struct.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_params_with_struct.cpp deleted file mode 100644 index 8c683a3ce..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_params_with_struct.cpp +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_replace_params_with_struct.h" - -#include - -#include "source/fuzz/fuzzer_util.h" - -namespace spvtools { -namespace fuzz { - -TransformationReplaceParamsWithStruct::TransformationReplaceParamsWithStruct( - const protobufs::TransformationReplaceParamsWithStruct& message) - : message_(message) {} - -TransformationReplaceParamsWithStruct::TransformationReplaceParamsWithStruct( - const std::vector& parameter_id, uint32_t fresh_function_type_id, - uint32_t fresh_parameter_id, - const std::map& caller_id_to_fresh_composite_id) { - message_.set_fresh_function_type_id(fresh_function_type_id); - message_.set_fresh_parameter_id(fresh_parameter_id); - - for (auto id : parameter_id) { - message_.add_parameter_id(id); - } - - *message_.mutable_caller_id_to_fresh_composite_id() = - fuzzerutil::MapToRepeatedUInt32Pair(caller_id_to_fresh_composite_id); -} - -bool TransformationReplaceParamsWithStruct::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - std::vector parameter_id(message_.parameter_id().begin(), - message_.parameter_id().end()); - - // Check that |parameter_id| is neither empty nor it has duplicates. - if (parameter_id.empty() || fuzzerutil::HasDuplicates(parameter_id)) { - return false; - } - - // All ids must correspond to valid parameters of the same function. - // The function can't be an entry-point function. - - // fuzzerutil::GetFunctionFromParameterId requires a valid id. - if (!ir_context->get_def_use_mgr()->GetDef(parameter_id[0])) { - return false; - } - - const auto* function = - fuzzerutil::GetFunctionFromParameterId(ir_context, parameter_id[0]); - if (!function || - fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) { - return false; - } - - // Compute all ids of the function's parameters. - std::unordered_set all_parameter_ids; - for (const auto* param : - fuzzerutil::GetParameters(ir_context, function->result_id())) { - all_parameter_ids.insert(param->result_id()); - } - - // Check that all elements in |parameter_id| are valid. - for (auto id : parameter_id) { - // fuzzerutil::GetFunctionFromParameterId requires a valid id. - if (!ir_context->get_def_use_mgr()->GetDef(id)) { - return false; - } - - // Check that |id| is a result id of one of the |function|'s parameters. - if (!all_parameter_ids.count(id)) { - return false; - } - - // Check that the parameter with result id |id| has supported type. - const auto* type = ir_context->get_type_mgr()->GetType( - fuzzerutil::GetTypeId(ir_context, id)); - assert(type && "Parameter has invalid type"); - if (!IsParameterTypeSupported(*type)) { - return false; - } - } - - // We already know that the function has at least |parameter_id.size()| - // parameters. - - // Check that a relevant OpTypeStruct exists in the module. - if (!MaybeGetRequiredStructType(ir_context)) { - return false; - } - - const auto caller_id_to_fresh_composite_id = - fuzzerutil::RepeatedUInt32PairToMap( - message_.caller_id_to_fresh_composite_id()); - - // Check that |callee_id_to_fresh_composite_id| is valid. - for (const auto* inst : - fuzzerutil::GetCallers(ir_context, function->result_id())) { - // Check that the callee is present in the map. It's ok if the map contains - // more ids that there are callees (those ids will not be used). - if (!caller_id_to_fresh_composite_id.count(inst->result_id())) { - return false; - } - } - - // Check that all fresh ids are unique and fresh. - std::vector fresh_ids = {message_.fresh_function_type_id(), - message_.fresh_parameter_id()}; - - for (const auto& entry : caller_id_to_fresh_composite_id) { - fresh_ids.push_back(entry.second); - } - - return !fuzzerutil::HasDuplicates(fresh_ids) && - std::all_of(fresh_ids.begin(), fresh_ids.end(), - [ir_context](uint32_t id) { - return fuzzerutil::IsFreshId(ir_context, id); - }); -} - -void TransformationReplaceParamsWithStruct::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto* function = fuzzerutil::GetFunctionFromParameterId( - ir_context, message_.parameter_id(0)); - assert(function && - "All parameters' ids should've been checked in the IsApplicable"); - - // Get a type id of the OpTypeStruct used as a type id of the new parameter. - auto struct_type_id = MaybeGetRequiredStructType(ir_context); - assert(struct_type_id && - "IsApplicable should've guaranteed that this value isn't equal to 0"); - - // Add new parameter to the function. - function->AddParameter(MakeUnique( - ir_context, SpvOpFunctionParameter, struct_type_id, - message_.fresh_parameter_id(), opt::Instruction::OperandList())); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_parameter_id()); - - // Compute indices of replaced parameters. This will be used to adjust - // OpFunctionCall instructions and create OpCompositeConstruct instructions at - // every call site. - const auto indices_of_replaced_params = - ComputeIndicesOfReplacedParameters(ir_context); - - const auto caller_id_to_fresh_composite_id = - fuzzerutil::RepeatedUInt32PairToMap( - message_.caller_id_to_fresh_composite_id()); - - // Update all function calls. - for (auto* inst : fuzzerutil::GetCallers(ir_context, function->result_id())) { - // Create a list of operands for the OpCompositeConstruct instruction. - opt::Instruction::OperandList composite_components; - for (auto index : indices_of_replaced_params) { - // +1 since the first in operand to OpFunctionCall is the result id of - // the function. - composite_components.emplace_back( - std::move(inst->GetInOperand(index + 1))); - } - - // Remove arguments from the function call. We do it in a separate loop - // and in decreasing order to make sure we have removed correct operands. - for (auto index : std::set>( - indices_of_replaced_params.begin(), - indices_of_replaced_params.end())) { - // +1 since the first in operand to OpFunctionCall is the result id of - // the function. - inst->RemoveInOperand(index + 1); - } - - // Insert OpCompositeConstruct before the function call. - auto fresh_composite_id = - caller_id_to_fresh_composite_id.at(inst->result_id()); - inst->InsertBefore(MakeUnique( - ir_context, SpvOpCompositeConstruct, struct_type_id, fresh_composite_id, - std::move(composite_components))); - - // Add a new operand to the OpFunctionCall instruction. - inst->AddOperand({SPV_OPERAND_TYPE_ID, {fresh_composite_id}}); - fuzzerutil::UpdateModuleIdBound(ir_context, fresh_composite_id); - } - - // Insert OpCompositeExtract instructions into the entry point block of the - // function and remove replaced parameters. - for (int i = 0; i < message_.parameter_id_size(); ++i) { - const auto* param_inst = - ir_context->get_def_use_mgr()->GetDef(message_.parameter_id(i)); - assert(param_inst && "Parameter id is invalid"); - - // Skip all OpVariable instructions. - auto iter = function->begin()->begin(); - while (iter != function->begin()->end() && - !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract, - iter)) { - ++iter; - } - - assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract, - iter) && - "Can't extract parameter's value from the structure"); - - // Insert OpCompositeExtract instructions to unpack parameters' values from - // the struct type. - iter.InsertBefore(MakeUnique( - ir_context, SpvOpCompositeExtract, param_inst->type_id(), - param_inst->result_id(), - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.fresh_parameter_id()}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {static_cast(i)}}})); - - fuzzerutil::RemoveParameter(ir_context, param_inst->result_id()); - } - - // Update function's type. - { - // We use a separate scope here since |old_function_type| might become a - // dangling pointer after the call to the fuzzerutil::UpdateFunctionType. - - auto* old_function_type = fuzzerutil::GetFunctionType(ir_context, function); - assert(old_function_type && "Function has invalid type"); - - // +1 since the first in operand to OpTypeFunction is the result type id - // of the function. - std::vector parameter_type_ids; - for (uint32_t i = 1; i < old_function_type->NumInOperands(); ++i) { - if (std::find(indices_of_replaced_params.begin(), - indices_of_replaced_params.end(), - i - 1) == indices_of_replaced_params.end()) { - parameter_type_ids.push_back( - old_function_type->GetSingleWordInOperand(i)); - } - } - - parameter_type_ids.push_back(struct_type_id); - - fuzzerutil::UpdateFunctionType( - ir_context, function->result_id(), message_.fresh_function_type_id(), - old_function_type->GetSingleWordInOperand(0), parameter_type_ids); - } - - // Make sure our changes are analyzed - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationReplaceParamsWithStruct::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_replace_params_with_struct() = message_; - return result; -} - -bool TransformationReplaceParamsWithStruct::IsParameterTypeSupported( - const opt::analysis::Type& param_type) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403): - // Consider adding support for more types of parameters. - switch (param_type.kind()) { - case opt::analysis::Type::kBool: - case opt::analysis::Type::kInteger: - case opt::analysis::Type::kFloat: - case opt::analysis::Type::kArray: - case opt::analysis::Type::kVector: - case opt::analysis::Type::kMatrix: - return true; - case opt::analysis::Type::kStruct: - return std::all_of(param_type.AsStruct()->element_types().begin(), - param_type.AsStruct()->element_types().end(), - [](const opt::analysis::Type* type) { - return IsParameterTypeSupported(*type); - }); - default: - return false; - } -} - -uint32_t TransformationReplaceParamsWithStruct::MaybeGetRequiredStructType( - opt::IRContext* ir_context) const { - std::vector component_type_ids; - for (auto id : message_.parameter_id()) { - component_type_ids.push_back(fuzzerutil::GetTypeId(ir_context, id)); - } - - return fuzzerutil::MaybeGetStructType(ir_context, component_type_ids); -} - -std::vector -TransformationReplaceParamsWithStruct::ComputeIndicesOfReplacedParameters( - opt::IRContext* ir_context) const { - assert(!message_.parameter_id().empty() && - "There must be at least one parameter to replace"); - - const auto* function = fuzzerutil::GetFunctionFromParameterId( - ir_context, message_.parameter_id(0)); - assert(function && "|parameter_id|s are invalid"); - - std::vector result; - - auto params = fuzzerutil::GetParameters(ir_context, function->result_id()); - for (auto id : message_.parameter_id()) { - auto it = std::find_if(params.begin(), params.end(), - [id](const opt::Instruction* param) { - return param->result_id() == id; - }); - assert(it != params.end() && "Parameter's id is invalid"); - result.push_back(static_cast(it - params.begin())); - } - - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_params_with_struct.h b/3rdparty/spirv-tools/source/fuzz/transformation_replace_params_with_struct.h deleted file mode 100644 index 7e40de897..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_params_with_struct.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMS_WITH_STRUCT_H_ -#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMS_WITH_STRUCT_H_ - -#include - -#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 TransformationReplaceParamsWithStruct : public Transformation { - public: - explicit TransformationReplaceParamsWithStruct( - const protobufs::TransformationReplaceParamsWithStruct& message); - - TransformationReplaceParamsWithStruct( - const std::vector& parameter_id, - uint32_t fresh_function_type_id, uint32_t fresh_parameter_id, - const std::map& caller_id_to_fresh_composite_id); - - // - Each element of |parameter_id| is a valid result id of some - // OpFunctionParameter instruction. All parameter ids must correspond to - // parameters of the same function. That function may not be an entry-point - // function. - // - Types of all parameters must be supported by this transformation (see - // IsParameterTypeSupported method). - // - |parameter_id| may not be empty or contain duplicates. - // - There must exist an OpTypeStruct instruction containing types of all - // replaced parameters. Type of the i'th component of the struct is equal - // to the type of the instruction with result id |parameter_id[i]|. - // - |caller_id_to_fresh_composite_id| should contain a key for at least every - // result id of an OpFunctionCall instruction that calls the function. - // - |fresh_function_type_id|, |fresh_parameter_id|, - // |caller_id_to_fresh_composite_id| are all fresh and unique ids. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - Creates a new function parameter with result id |fresh_parameter_id|. - // Parameter's type is OpTypeStruct with each components type equal to the - // type of the replaced parameter. - // - OpCompositeConstruct with result id from |fresh_composite_id| is inserted - // before each OpFunctionCall instruction. - // - OpCompositeExtract with result id equal to the result id of the replaced - // parameter is created in the function. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Returns true if parameter's type is supported by this transformation. - static bool IsParameterTypeSupported(const opt::analysis::Type& param_type); - - private: - // Returns a result id of the OpTypeStruct instruction required by this - // transformation (see docs on the IsApplicable method to learn more). - uint32_t MaybeGetRequiredStructType(opt::IRContext* ir_context) const; - - // Returns a vector of indices of parameters to replace. Concretely, i'th - // element is the index of the parameter with result id |parameter_id[i]| in - // its function. - std::vector ComputeIndicesOfReplacedParameters( - opt::IRContext* ir_context) const; - - protobufs::TransformationReplaceParamsWithStruct message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMS_WITH_STRUCT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_function_control.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_set_function_control.cpp deleted file mode 100644 index d01e74347..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_function_control.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_set_function_control.h" - -namespace spvtools { -namespace fuzz { - -TransformationSetFunctionControl::TransformationSetFunctionControl( - const spvtools::fuzz::protobufs::TransformationSetFunctionControl& message) - : message_(message) {} - -TransformationSetFunctionControl::TransformationSetFunctionControl( - uint32_t function_id, uint32_t function_control) { - message_.set_function_id(function_id); - message_.set_function_control(function_control); -} - -bool TransformationSetFunctionControl::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - opt::Instruction* function_def_instruction = - FindFunctionDefInstruction(ir_context); - if (!function_def_instruction) { - // The given function id does not correspond to any function. - return false; - } - uint32_t existing_function_control_mask = - function_def_instruction->GetSingleWordInOperand(0); - - // Check (via an assertion) that function control mask doesn't have any bad - // bits set. - uint32_t acceptable_function_control_bits = - SpvFunctionControlInlineMask | SpvFunctionControlDontInlineMask | - SpvFunctionControlPureMask | SpvFunctionControlConstMask; - // The following is to keep release-mode compilers happy as this variable is - // only used in an assertion. - (void)(acceptable_function_control_bits); - assert(!(message_.function_control() & ~acceptable_function_control_bits) && - "Nonsensical loop control bits were found."); - - // Check (via an assertion) that function control mask does not have both - // Inline and DontInline bits set. - assert(!((message_.function_control() & SpvFunctionControlInlineMask) && - (message_.function_control() & SpvFunctionControlDontInlineMask)) && - "It is not OK to set both the 'Inline' and 'DontInline' bits of a " - "function control mask"); - - // Check that Const and Pure are only present if they were present on the - // original function - for (auto mask_bit : - {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) { - if ((message_.function_control() & mask_bit) && - !(existing_function_control_mask & mask_bit)) { - return false; - } - } - - return true; -} - -void TransformationSetFunctionControl::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - opt::Instruction* function_def_instruction = - FindFunctionDefInstruction(ir_context); - function_def_instruction->SetInOperand(0, {message_.function_control()}); -} - -protobufs::Transformation TransformationSetFunctionControl::ToMessage() const { - protobufs::Transformation result; - *result.mutable_set_function_control() = message_; - return result; -} - -opt::Instruction* TransformationSetFunctionControl ::FindFunctionDefInstruction( - opt::IRContext* ir_context) const { - // Look through all functions for a function whose defining instruction's - // result id matches |message_.function_id|, returning the defining - // instruction if found. - for (auto& function : *ir_context->module()) { - if (function.DefInst().result_id() == message_.function_id()) { - return &function.DefInst(); - } - } - // A nullptr result indicates that no match was found. - return nullptr; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_function_control.h b/3rdparty/spirv-tools/source/fuzz/transformation_set_function_control.h deleted file mode 100644 index 5109f748c..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_function_control.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_ -#define SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_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 TransformationSetFunctionControl : public Transformation { - public: - explicit TransformationSetFunctionControl( - const protobufs::TransformationSetFunctionControl& message); - - TransformationSetFunctionControl(uint32_t function_id, - uint32_t function_control); - - // - |message_.function_id| must be the result id of an OpFunction - // instruction. - // - |message_.function_control| must be a function control mask that sets - // at most one of 'Inline' or 'DontInline', and that may not contain 'Pure' - // (respectively 'Const') unless the existing function control mask contains - // 'Pure' (respectively 'Const'). - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // The function control operand of instruction |message_.function_id| is - // over-written with |message_.function_control|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - opt::Instruction* FindFunctionDefInstruction( - opt::IRContext* ir_context) const; - - protobufs::TransformationSetFunctionControl message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_loop_control.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_set_loop_control.cpp deleted file mode 100644 index 6cf2104d4..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_loop_control.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_set_loop_control.h" - -namespace spvtools { -namespace fuzz { - -TransformationSetLoopControl::TransformationSetLoopControl( - const spvtools::fuzz::protobufs::TransformationSetLoopControl& message) - : message_(message) {} - -TransformationSetLoopControl::TransformationSetLoopControl( - uint32_t block_id, uint32_t loop_control, uint32_t peel_count, - uint32_t partial_count) { - message_.set_block_id(block_id); - message_.set_loop_control(loop_control); - message_.set_peel_count(peel_count); - message_.set_partial_count(partial_count); -} - -bool TransformationSetLoopControl::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - // |message_.block_id| must identify a block that ends with OpLoopMerge. - auto block = ir_context->get_instr_block(message_.block_id()); - if (!block) { - return false; - } - auto merge_inst = block->GetMergeInst(); - if (!merge_inst || merge_inst->opcode() != SpvOpLoopMerge) { - return false; - } - - // We assert that the transformation does not try to set any meaningless bits - // of the loop control mask. - uint32_t all_loop_control_mask_bits_set = - SpvLoopControlUnrollMask | SpvLoopControlDontUnrollMask | - SpvLoopControlDependencyInfiniteMask | - SpvLoopControlDependencyLengthMask | SpvLoopControlMinIterationsMask | - SpvLoopControlMaxIterationsMask | SpvLoopControlIterationMultipleMask | - SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask; - - // The variable is only used in an assertion; the following keeps release-mode - // compilers happy. - (void)(all_loop_control_mask_bits_set); - - // No additional bits should be set. - assert(!(message_.loop_control() & ~all_loop_control_mask_bits_set)); - - // Grab the loop control mask currently associated with the OpLoopMerge - // instruction. - auto existing_loop_control_mask = - merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex); - - // Check that there is no attempt to set one of the loop controls that - // requires guarantees to hold. - for (SpvLoopControlMask mask : - {SpvLoopControlDependencyInfiniteMask, - SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask, - SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) { - // We have a problem if this loop control bit was not set in the original - // loop control mask but is set by the transformation. - if (LoopControlBitIsAddedByTransformation(mask, - existing_loop_control_mask)) { - return false; - } - } - - if ((message_.loop_control() & - (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)) && - !(PeelCountIsSupported(ir_context) && - PartialCountIsSupported(ir_context))) { - // At least one of PeelCount or PartialCount is used, but the SPIR-V version - // in question does not support these loop controls. - return false; - } - - if (message_.peel_count() > 0 && - !(message_.loop_control() & SpvLoopControlPeelCountMask)) { - // Peel count provided, but peel count mask bit not set. - return false; - } - - if (message_.partial_count() > 0 && - !(message_.loop_control() & SpvLoopControlPartialCountMask)) { - // Partial count provided, but partial count mask bit not set. - return false; - } - - // We must not set both 'don't unroll' and one of 'peel count' or 'partial - // count'. - return !((message_.loop_control() & SpvLoopControlDontUnrollMask) && - (message_.loop_control() & - (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask))); -} - -void TransformationSetLoopControl::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - // Grab the loop merge instruction and its associated loop control mask. - auto merge_inst = - ir_context->get_instr_block(message_.block_id())->GetMergeInst(); - auto existing_loop_control_mask = - merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex); - - // We are going to replace the OpLoopMerge's operands with this list. - opt::Instruction::OperandList new_operands; - // We add the existing merge block and continue target ids. - new_operands.push_back(merge_inst->GetInOperand(0)); - new_operands.push_back(merge_inst->GetInOperand(1)); - // We use the loop control mask from the transformation. - new_operands.push_back( - {SPV_OPERAND_TYPE_LOOP_CONTROL, {message_.loop_control()}}); - - // It remains to determine what literals to provide, in association with - // the new loop control mask. - // - // For the loop controls that require guarantees to hold about the number - // of loop iterations, we need to keep, from the original OpLoopMerge, any - // literals associated with loop control bits that are still set. - - uint32_t literal_index = 0; // Indexes into the literals from the original - // instruction. - for (SpvLoopControlMask mask : - {SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask, - SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) { - // Check whether the bit was set in the original loop control mask. - if (existing_loop_control_mask & mask) { - // Check whether the bit is set in the new loop control mask. - if (message_.loop_control() & mask) { - // Add the associated literal to our sequence of replacement operands. - new_operands.push_back( - {SPV_OPERAND_TYPE_LITERAL_INTEGER, - {merge_inst->GetSingleWordInOperand( - kLoopControlFirstLiteralInOperandIndex + literal_index)}}); - } - // Increment our index into the original loop control mask's literals, - // whether or not the bit was set in the new mask. - literal_index++; - } - } - - // If PeelCount is set in the new mask, |message_.peel_count| provides the - // associated peel count. - if (message_.loop_control() & SpvLoopControlPeelCountMask) { - new_operands.push_back( - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.peel_count()}}); - } - - // Similar, but for PartialCount. - if (message_.loop_control() & SpvLoopControlPartialCountMask) { - new_operands.push_back( - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.partial_count()}}); - } - - // Replace the input operands of the OpLoopMerge with the new operands we have - // accumulated. - merge_inst->SetInOperands(std::move(new_operands)); -} - -protobufs::Transformation TransformationSetLoopControl::ToMessage() const { - protobufs::Transformation result; - *result.mutable_set_loop_control() = message_; - return result; -} - -bool TransformationSetLoopControl::LoopControlBitIsAddedByTransformation( - SpvLoopControlMask loop_control_single_bit_mask, - uint32_t existing_loop_control_mask) const { - return !(loop_control_single_bit_mask & existing_loop_control_mask) && - (loop_control_single_bit_mask & message_.loop_control()); -} - -bool TransformationSetLoopControl::PartialCountIsSupported( - opt::IRContext* ir_context) { - // TODO(afd): We capture the universal environments for which this loop - // control is definitely not supported. The check should be refined on - // demand for other target environments. - switch (ir_context->grammar().target_env()) { - case SPV_ENV_UNIVERSAL_1_0: - case SPV_ENV_UNIVERSAL_1_1: - case SPV_ENV_UNIVERSAL_1_2: - case SPV_ENV_UNIVERSAL_1_3: - return false; - default: - return true; - } -} - -bool TransformationSetLoopControl::PeelCountIsSupported( - opt::IRContext* ir_context) { - // TODO(afd): We capture the universal environments for which this loop - // control is definitely not supported. The check should be refined on - // demand for other target environments. - switch (ir_context->grammar().target_env()) { - case SPV_ENV_UNIVERSAL_1_0: - case SPV_ENV_UNIVERSAL_1_1: - case SPV_ENV_UNIVERSAL_1_2: - case SPV_ENV_UNIVERSAL_1_3: - return false; - default: - return true; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_loop_control.h b/3rdparty/spirv-tools/source/fuzz/transformation_set_loop_control.h deleted file mode 100644 index f0c364f98..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_loop_control.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_ -#define SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_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 TransformationSetLoopControl : public Transformation { - public: - const static uint32_t kLoopControlMaskInOperandIndex = 2; - const static uint32_t kLoopControlFirstLiteralInOperandIndex = 3; - - explicit TransformationSetLoopControl( - const protobufs::TransformationSetLoopControl& message); - - TransformationSetLoopControl(uint32_t block_id, uint32_t loop_control, - uint32_t peel_count, uint32_t partial_count); - - // - |message_.block_id| must be a block containing an OpLoopMerge - // instruction. - // - |message_.loop_control| must be a legal loop control mask that - // only uses controls available in the SPIR-V version associated with - // |ir_context|, and must not add loop controls that are only valid in the - // presence of guarantees about what the loop does (e.g. MinIterations). - // - |message_.peel_count| (respectively |message_.partial_count|) must be - // zero PeelCount (respectively PartialCount) is set in - // |message_.loop_control|. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - The loop control operand of the OpLoopMergeInstruction in - // |message_.block_id| is overwritten with |message_.loop_control|. - // - The literals associated with the loop control are updated to reflect any - // controls with associated literals that have been removed (e.g. - // MinIterations), and any that have been added (PeelCount and/or - // PartialCount). - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Does the version of SPIR-V being used support the PartialCount loop - // control? - static bool PartialCountIsSupported(opt::IRContext* ir_context); - - // Does the version of SPIR-V being used support the PeelCount loop control? - static bool PeelCountIsSupported(opt::IRContext* ir_context); - - private: - // Returns true if and only if |loop_single_bit_mask| is *not* set in - // |existing_loop_control| but *is* set in |message_.loop_control|. - bool LoopControlBitIsAddedByTransformation( - SpvLoopControlMask loop_control_single_bit_mask, - uint32_t existing_loop_control_mask) const; - - protobufs::TransformationSetLoopControl message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp deleted file mode 100644 index f52f17014..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_set_memory_operands_mask.h" - -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -namespace { - -const uint32_t kOpLoadMemoryOperandsMaskIndex = 1; -const uint32_t kOpStoreMemoryOperandsMaskIndex = 2; -const uint32_t kOpCopyMemoryFirstMemoryOperandsMaskIndex = 2; -const uint32_t kOpCopyMemorySizedFirstMemoryOperandsMaskIndex = 3; - -} // namespace - -TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask( - const spvtools::fuzz::protobufs::TransformationSetMemoryOperandsMask& - message) - : message_(message) {} - -TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask( - const protobufs::InstructionDescriptor& memory_access_instruction, - uint32_t memory_operands_mask, uint32_t memory_operands_mask_index) { - *message_.mutable_memory_access_instruction() = memory_access_instruction; - message_.set_memory_operands_mask(memory_operands_mask); - message_.set_memory_operands_mask_index(memory_operands_mask_index); -} - -bool TransformationSetMemoryOperandsMask::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - if (message_.memory_operands_mask_index() != 0) { - // The following conditions should never be violated, even if - // transformations end up being replayed in a different way to the manner in - // which they were applied during fuzzing, hence why these are assertions - // rather than applicability checks. - assert(message_.memory_operands_mask_index() == 1); - assert(message_.memory_access_instruction().target_instruction_opcode() == - SpvOpCopyMemory || - message_.memory_access_instruction().target_instruction_opcode() == - SpvOpCopyMemorySized); - assert(MultipleMemoryOperandMasksAreSupported(ir_context)); - } - - auto instruction = - FindInstruction(message_.memory_access_instruction(), ir_context); - if (!instruction) { - return false; - } - if (!IsMemoryAccess(*instruction)) { - return false; - } - - auto original_mask_in_operand_index = GetInOperandIndexForMask( - *instruction, message_.memory_operands_mask_index()); - assert(original_mask_in_operand_index != 0 && - "The given mask index is not valid."); - uint32_t original_mask = - original_mask_in_operand_index < instruction->NumInOperands() - ? instruction->GetSingleWordInOperand(original_mask_in_operand_index) - : static_cast(SpvMemoryAccessMaskNone); - uint32_t new_mask = message_.memory_operands_mask(); - - // Volatile must not be removed - if ((original_mask & SpvMemoryAccessVolatileMask) && - !(new_mask & SpvMemoryAccessVolatileMask)) { - return false; - } - - // Nontemporal can be added or removed, and no other flag is allowed to - // change. We do this by checking that the masks are equal once we set - // their Volatile and Nontemporal flags to the same value (this works - // because valid manipulation of Volatile is checked above, and the manner - // in which Nontemporal is manipulated does not matter). - return (original_mask | SpvMemoryAccessVolatileMask | - SpvMemoryAccessNontemporalMask) == - (new_mask | SpvMemoryAccessVolatileMask | - SpvMemoryAccessNontemporalMask); -} - -void TransformationSetMemoryOperandsMask::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto instruction = - FindInstruction(message_.memory_access_instruction(), ir_context); - auto original_mask_in_operand_index = GetInOperandIndexForMask( - *instruction, message_.memory_operands_mask_index()); - // Either add a new operand, if no mask operand was already present, or - // replace an existing mask operand. - if (original_mask_in_operand_index >= instruction->NumInOperands()) { - // Add first memory operand if it's missing. - if (message_.memory_operands_mask_index() == 1 && - GetInOperandIndexForMask(*instruction, 0) >= - instruction->NumInOperands()) { - instruction->AddOperand( - {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessMaskNone}}); - } - - instruction->AddOperand( - {SPV_OPERAND_TYPE_MEMORY_ACCESS, {message_.memory_operands_mask()}}); - - } else { - instruction->SetInOperand(original_mask_in_operand_index, - {message_.memory_operands_mask()}); - } -} - -protobufs::Transformation TransformationSetMemoryOperandsMask::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_set_memory_operands_mask() = message_; - return result; -} - -bool TransformationSetMemoryOperandsMask::IsMemoryAccess( - const opt::Instruction& instruction) { - switch (instruction.opcode()) { - case SpvOpLoad: - case SpvOpStore: - case SpvOpCopyMemory: - case SpvOpCopyMemorySized: - return true; - default: - return false; - } -} - -uint32_t TransformationSetMemoryOperandsMask::GetInOperandIndexForMask( - const opt::Instruction& instruction, uint32_t mask_index) { - // Get the input operand index associated with the first memory operands mask - // for the instruction. - uint32_t first_mask_in_operand_index = 0; - switch (instruction.opcode()) { - case SpvOpLoad: - first_mask_in_operand_index = kOpLoadMemoryOperandsMaskIndex; - break; - case SpvOpStore: - first_mask_in_operand_index = kOpStoreMemoryOperandsMaskIndex; - break; - case SpvOpCopyMemory: - first_mask_in_operand_index = kOpCopyMemoryFirstMemoryOperandsMaskIndex; - break; - case SpvOpCopyMemorySized: - first_mask_in_operand_index = - kOpCopyMemorySizedFirstMemoryOperandsMaskIndex; - break; - default: - assert(false && "Unknown memory instruction."); - break; - } - // If we are looking for the input operand index of the first mask, return it. - // This will also return a correct value if the operand is missing. - if (mask_index == 0) { - return first_mask_in_operand_index; - } - assert(mask_index == 1 && "Memory operands mask index must be 0 or 1."); - - // Memory mask operands are optional. Thus, if the second operand exists, - // its index will be >= |first_mask_in_operand_index + 1|. We can reason as - // follows to separate the cases where the index of the second operand is - // equal to |first_mask_in_operand_index + 1|: - // - If the first memory operand doesn't exist, its value is equal to None. - // This means that it doesn't have additional operands following it and the - // condition in the if statement below will be satisfied. - // - If the first memory operand exists and has no additional memory operands - // following it, the condition in the if statement below will be satisfied - // and we will return the correct value from the function. - if (first_mask_in_operand_index + 1 >= instruction.NumInOperands()) { - return first_mask_in_operand_index + 1; - } - - // We are looking for the input operand index of the second mask. This is a - // little complicated because, depending on the contents of the first mask, - // there may be some input operands separating the two masks. - uint32_t first_mask = - instruction.GetSingleWordInOperand(first_mask_in_operand_index); - - // Consider each bit that might have an associated extra input operand, and - // count how many there are expected to be. - uint32_t first_mask_extra_operand_count = 0; - for (auto mask_bit : - {SpvMemoryAccessAlignedMask, SpvMemoryAccessMakePointerAvailableMask, - SpvMemoryAccessMakePointerAvailableKHRMask, - SpvMemoryAccessMakePointerVisibleMask, - SpvMemoryAccessMakePointerVisibleKHRMask}) { - if (first_mask & mask_bit) { - first_mask_extra_operand_count++; - } - } - return first_mask_in_operand_index + first_mask_extra_operand_count + 1; -} - -bool TransformationSetMemoryOperandsMask:: - MultipleMemoryOperandMasksAreSupported(opt::IRContext* ir_context) { - // TODO(afd): We capture the universal environments for which this loop - // control is definitely not supported. The check should be refined on - // demand for other target environments. - switch (ir_context->grammar().target_env()) { - case SPV_ENV_UNIVERSAL_1_0: - case SPV_ENV_UNIVERSAL_1_1: - case SPV_ENV_UNIVERSAL_1_2: - case SPV_ENV_UNIVERSAL_1_3: - return false; - default: - return true; - } -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.h b/3rdparty/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.h deleted file mode 100644 index 9f5081bf3..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_ -#define SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_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 TransformationSetMemoryOperandsMask : public Transformation { - public: - explicit TransformationSetMemoryOperandsMask( - const protobufs::TransformationSetMemoryOperandsMask& message); - - TransformationSetMemoryOperandsMask( - const protobufs::InstructionDescriptor& memory_access_instruction, - uint32_t memory_operands_mask, uint32_t memory_operands_mask_index); - - // - |message_.memory_access_instruction| must describe a memory access - // instruction. - // - |message_.memory_operands_mask_index| must be suitable for this memory - // access instruction, e.g. it must be 0 in the case of OpLoad, and may be - // 1 in the case of OpCopyMemory if the SPIR-V version is 1.4 or higher. - // - |message_.memory_operands_mask| must be identical to the original memory - // operands mask, except that Volatile may be added, and Nontemporal may be - // toggled. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Replaces the operands mask identified by - // |message_.memory_operands_mask_index| in the instruction described by - // |message_.memory_access_instruction| with |message_.memory_operands_mask|, - // creating an input operand for the mask if no such operand was present. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - // Helper function that determines whether |instruction| is a memory - // instruction (e.g. OpLoad). - static bool IsMemoryAccess(const opt::Instruction& instruction); - - // Does the version of SPIR-V being used support multiple memory operand - // masks on relevant memory access instructions? - static bool MultipleMemoryOperandMasksAreSupported( - opt::IRContext* ir_context); - - // Helper function to get the input operand index associated with mask number - // |mask_index|. This is a bit tricky if there are multiple masks, because the - // index associated with the second mask depends on whether the first mask - // includes any flags such as Aligned that have corresponding operands. - static uint32_t GetInOperandIndexForMask(const opt::Instruction& instruction, - uint32_t mask_index); - - private: - protobufs::TransformationSetMemoryOperandsMask message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_selection_control.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_set_selection_control.cpp deleted file mode 100644 index bee1e3575..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_selection_control.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_set_selection_control.h" - -namespace spvtools { -namespace fuzz { - -TransformationSetSelectionControl::TransformationSetSelectionControl( - const spvtools::fuzz::protobufs::TransformationSetSelectionControl& message) - : message_(message) {} - -TransformationSetSelectionControl::TransformationSetSelectionControl( - uint32_t block_id, uint32_t selection_control) { - message_.set_block_id(block_id); - message_.set_selection_control(selection_control); -} - -bool TransformationSetSelectionControl::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - assert((message_.selection_control() == SpvSelectionControlMaskNone || - message_.selection_control() == SpvSelectionControlFlattenMask || - message_.selection_control() == SpvSelectionControlDontFlattenMask) && - "Selection control should never be set to something other than " - "'None', 'Flatten' or 'DontFlatten'"); - if (auto block = ir_context->get_instr_block(message_.block_id())) { - if (auto merge_inst = block->GetMergeInst()) { - return merge_inst->opcode() == SpvOpSelectionMerge; - } - } - // Either the block did not exit, or did not end with OpSelectionMerge. - return false; -} - -void TransformationSetSelectionControl::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - ir_context->get_instr_block(message_.block_id()) - ->GetMergeInst() - ->SetInOperand(1, {message_.selection_control()}); -} - -protobufs::Transformation TransformationSetSelectionControl::ToMessage() const { - protobufs::Transformation result; - *result.mutable_set_selection_control() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_set_selection_control.h b/3rdparty/spirv-tools/source/fuzz/transformation_set_selection_control.h deleted file mode 100644 index 21fbdda45..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_set_selection_control.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_ -#define SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_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 TransformationSetSelectionControl : public Transformation { - public: - explicit TransformationSetSelectionControl( - const protobufs::TransformationSetSelectionControl& message); - - TransformationSetSelectionControl(uint32_t block_id, - uint32_t selection_control); - - // - |message_.block_id| must be a block containing an OpSelectionMerge - // instruction. - // - |message_.selection_control| must be one of None, Flatten or - // DontFlatten. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - The selection control operand of the OpSelectionMergeInstruction in - // |message_.block_id| is overwritten with |message_.selection_control|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationSetSelectionControl message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp deleted file mode 100644 index 3c437e432..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_split_block.h" - -#include - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace fuzz { - -TransformationSplitBlock::TransformationSplitBlock( - const spvtools::fuzz::protobufs::TransformationSplitBlock& message) - : message_(message) {} - -TransformationSplitBlock::TransformationSplitBlock( - const protobufs::InstructionDescriptor& instruction_to_split_before, - uint32_t fresh_id) { - *message_.mutable_instruction_to_split_before() = instruction_to_split_before; - message_.set_fresh_id(fresh_id); -} - -bool TransformationSplitBlock::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - // We require the id for the new block to be unused. - return false; - } - auto instruction_to_split_before = - FindInstruction(message_.instruction_to_split_before(), ir_context); - if (!instruction_to_split_before) { - // The instruction describing the block we should split does not exist. - return false; - } - auto block_to_split = - ir_context->get_instr_block(instruction_to_split_before); - assert(block_to_split && - "We should not have managed to find the " - "instruction if it was not contained in a block."); - - if (block_to_split->IsLoopHeader()) { - // We cannot split a loop header block: back-edges would become invalid. - return false; - } - - auto split_before = fuzzerutil::GetIteratorForInstruction( - block_to_split, instruction_to_split_before); - assert(split_before != block_to_split->end() && - "At this point we know the" - " block split point exists."); - - if (split_before->PreviousNode() && - split_before->PreviousNode()->opcode() == SpvOpSelectionMerge) { - // We cannot split directly after a selection merge: this would separate - // the merge from its associated branch or switch operation. - return false; - } - if (split_before->opcode() == SpvOpVariable) { - // We cannot split directly after a variable; variables in a function - // must be contiguous in the entry block. - return false; - } - // We cannot split before an OpPhi unless the OpPhi has exactly one - // associated incoming edge. - if (split_before->opcode() == SpvOpPhi && - split_before->NumInOperands() != 2) { - return false; - } - - // Splitting the block must not separate the definition of an OpSampledImage - // from its use: the SPIR-V data rules require them to be in the same block. - std::set sampled_image_result_ids; - bool before_split = true; - for (auto& instruction : *block_to_split) { - if (&instruction == &*split_before) { - before_split = false; - } - if (before_split) { - if (instruction.opcode() == SpvOpSampledImage) { - sampled_image_result_ids.insert(instruction.result_id()); - } - } else { - if (!instruction.WhileEachInId( - [&sampled_image_result_ids](uint32_t* id) -> bool { - return !sampled_image_result_ids.count(*id); - })) { - return false; - } - } - } - - return true; -} - -void TransformationSplitBlock::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - opt::Instruction* instruction_to_split_before = - FindInstruction(message_.instruction_to_split_before(), ir_context); - opt::BasicBlock* block_to_split = - ir_context->get_instr_block(instruction_to_split_before); - auto split_before = fuzzerutil::GetIteratorForInstruction( - block_to_split, instruction_to_split_before); - assert(split_before != block_to_split->end() && - "If the transformation is applicable, we should have an " - "instruction to split on."); - - // We need to make sure the module's id bound is large enough to add the - // fresh id. - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // Split the block. - auto new_bb = block_to_split->SplitBasicBlock(ir_context, message_.fresh_id(), - split_before); - // The split does not automatically add a branch between the two parts of - // the original block, so we add one. - block_to_split->AddInstruction(MakeUnique( - ir_context, SpvOpBranch, 0, 0, - std::initializer_list{opt::Operand( - spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})})); - // If we split before OpPhi instructions, we need to update their - // predecessor operand so that the block they used to be inside is now the - // predecessor. - new_bb->ForEachPhiInst([block_to_split](opt::Instruction* phi_inst) { - assert( - phi_inst->NumInOperands() == 2 && - "Precondition: a block can only be split before an OpPhi if the block" - "has exactly one predecessor."); - phi_inst->SetInOperand(1, {block_to_split->id()}); - }); - - // If the block being split was dead, the new block arising from the split is - // also dead. - if (transformation_context->GetFactManager()->BlockIsDead( - block_to_split->id())) { - transformation_context->GetFactManager()->AddFactBlockIsDead( - message_.fresh_id()); - } - - // Invalidate all analyses - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationSplitBlock::ToMessage() const { - protobufs::Transformation result; - *result.mutable_split_block() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h deleted file mode 100644 index 3bf6dfd20..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_H_ -#define SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_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 TransformationSplitBlock : public Transformation { - public: - explicit TransformationSplitBlock( - const protobufs::TransformationSplitBlock& message); - - TransformationSplitBlock( - const protobufs::InstructionDescriptor& instruction_to_split_before, - uint32_t fresh_id); - - // - |message_.base_instruction_id| must be the result id of an instruction - // 'base' in some block 'blk'. - // - 'blk' must contain an instruction 'inst' located |message_.offset| - // instructions after 'base' (if |message_.offset| = 0 then 'inst' = - // 'base'). - // - Splitting 'blk' at 'inst', so that all instructions from 'inst' onwards - // appear in a new block that 'blk' directly jumps to must be valid. - // - |message_.fresh_id| must not be used by the module. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // - A new block with label |message_.fresh_id| is inserted right after 'blk' - // in program order. - // - All instructions of 'blk' from 'inst' onwards are moved into the new - // block. - // - 'blk' is made to jump unconditionally to the new block. - // - If 'blk' was dead, the new block is also dead. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationSplitBlock message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_store.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_store.cpp deleted file mode 100644 index f77afe35d..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_store.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_store.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationStore::TransformationStore( - const spvtools::fuzz::protobufs::TransformationStore& message) - : message_(message) {} - -TransformationStore::TransformationStore( - uint32_t pointer_id, uint32_t value_id, - const protobufs::InstructionDescriptor& instruction_to_insert_before) { - message_.set_pointer_id(pointer_id); - message_.set_value_id(value_id); - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; -} - -bool TransformationStore::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // The pointer must exist and have a type. - auto pointer = ir_context->get_def_use_mgr()->GetDef(message_.pointer_id()); - if (!pointer || !pointer->type_id()) { - return false; - } - - // The pointer type must indeed be a pointer. - auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id()); - assert(pointer_type && "Type id must be defined."); - if (pointer_type->opcode() != SpvOpTypePointer) { - return false; - } - - // The pointer must not be read only. - if (pointer->IsReadOnlyPointer()) { - return false; - } - - // We do not want to allow storing to null or undefined pointers. - switch (pointer->opcode()) { - case SpvOpConstantNull: - case SpvOpUndef: - return false; - default: - break; - } - - // Determine which instruction we should be inserting before. - auto insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - // It must exist, ... - if (!insert_before) { - return false; - } - // ... and it must be legitimate to insert a store before it. - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, - insert_before)) { - return false; - } - - // The block we are inserting into needs to be dead, or else the pointee type - // of the pointer we are storing to needs to be irrelevant (otherwise the - // store could impact on the observable behaviour of the module). - if (!transformation_context.GetFactManager()->BlockIsDead( - ir_context->get_instr_block(insert_before)->id()) && - !transformation_context.GetFactManager()->PointeeValueIsIrrelevant( - message_.pointer_id())) { - return false; - } - - // The value being stored needs to exist and have a type. - auto value = ir_context->get_def_use_mgr()->GetDef(message_.value_id()); - if (!value || !value->type_id()) { - return false; - } - - // The type of the value must match the pointee type. - if (pointer_type->GetSingleWordInOperand(1) != value->type_id()) { - return false; - } - - // The pointer needs to be available at the insertion point. - if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, - message_.pointer_id())) { - return false; - } - - // The value needs to be available at the insertion point. - return fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before, - message_.value_id()); -} - -void TransformationStore::Apply(opt::IRContext* ir_context, - TransformationContext* /*unused*/) const { - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.value_id()}}}))); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); -} - -protobufs::Transformation TransformationStore::ToMessage() const { - protobufs::Transformation result; - *result.mutable_store() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_store.h b/3rdparty/spirv-tools/source/fuzz/transformation_store.h deleted file mode 100644 index 6746aab5e..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_store.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_STORE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_STORE_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 TransformationStore : public Transformation { - public: - explicit TransformationStore(const protobufs::TransformationStore& message); - - TransformationStore( - uint32_t pointer_id, 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_.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 - // before which it is valid to insert an OpStore, and where both - // |message_.pointer_id| and |message_.value_id| are available (according - // to dominance rules) - // - Either the insertion point must be in a dead block, or it must be known - // that the pointee value of |message_.pointer_id| is irrelevant - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Adds an instruction of the form: - // OpStore |pointer_id| |value_id| - // before the instruction identified by - // |message_.instruction_to_insert_before|. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationStore message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_STORE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_swap_commutable_operands.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_swap_commutable_operands.cpp deleted file mode 100644 index b7622a239..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_swap_commutable_operands.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_swap_commutable_operands.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationSwapCommutableOperands::TransformationSwapCommutableOperands( - const spvtools::fuzz::protobufs::TransformationSwapCommutableOperands& - message) - : message_(message) {} - -TransformationSwapCommutableOperands::TransformationSwapCommutableOperands( - const protobufs::InstructionDescriptor& instruction_descriptor) { - *message_.mutable_instruction_descriptor() = instruction_descriptor; -} - -bool TransformationSwapCommutableOperands::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/ - ) const { - auto instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - if (instruction == nullptr) return false; - - SpvOp opcode = static_cast( - message_.instruction_descriptor().target_instruction_opcode()); - assert(instruction->opcode() == opcode && - "The located instruction must have the same opcode as in the " - "descriptor."); - return spvOpcodeIsCommutativeBinaryOperator(opcode); -} - -void TransformationSwapCommutableOperands::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/ - ) const { - auto instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - // By design, the instructions defined to be commutative have exactly two - // input parameters. - std::swap(instruction->GetInOperand(0), instruction->GetInOperand(1)); -} - -protobufs::Transformation TransformationSwapCommutableOperands::ToMessage() - const { - protobufs::Transformation result; - *result.mutable_swap_commutable_operands() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_swap_commutable_operands.h b/3rdparty/spirv-tools/source/fuzz/transformation_swap_commutable_operands.h deleted file mode 100644 index 7fe5b7090..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_swap_commutable_operands.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_SWAP_COMMUTABLE_OPERANDS_H_ -#define SOURCE_FUZZ_TRANSFORMATION_SWAP_COMMUTABLE_OPERANDS_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 TransformationSwapCommutableOperands : public Transformation { - public: - explicit TransformationSwapCommutableOperands( - const protobufs::TransformationSwapCommutableOperands& message); - - TransformationSwapCommutableOperands( - const protobufs::InstructionDescriptor& instruction_descriptor); - - // - |message_.instruction_descriptor| must identify an existing - // commutative instruction - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Swaps the commutable operands. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationSwapCommutableOperands message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_SWAP_COMMUTABLE_OPERANDS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_swap_conditional_branch_operands.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_swap_conditional_branch_operands.cpp deleted file mode 100644 index 25f48c4a5..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_swap_conditional_branch_operands.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_swap_conditional_branch_operands.h" -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationSwapConditionalBranchOperands:: - TransformationSwapConditionalBranchOperands( - const spvtools::fuzz::protobufs:: - TransformationSwapConditionalBranchOperands& message) - : message_(message) {} - -TransformationSwapConditionalBranchOperands:: - TransformationSwapConditionalBranchOperands( - const protobufs::InstructionDescriptor& instruction_descriptor, - uint32_t fresh_id) { - *message_.mutable_instruction_descriptor() = instruction_descriptor; - message_.set_fresh_id(fresh_id); -} - -bool TransformationSwapConditionalBranchOperands::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { - const auto* inst = - FindInstruction(message_.instruction_descriptor(), ir_context); - return fuzzerutil::IsFreshId(ir_context, message_.fresh_id()) && inst && - inst->opcode() == SpvOpBranchConditional; -} - -void TransformationSwapConditionalBranchOperands::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - auto* branch_inst = - FindInstruction(message_.instruction_descriptor(), ir_context); - assert(branch_inst); - - auto* block = ir_context->get_instr_block(branch_inst); - assert(block); - - // Compute the last instruction in the |block| that allows us to insert - // OpLogicalNot above it. - auto iter = fuzzerutil::GetIteratorForInstruction(block, branch_inst); - if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLogicalNot, iter)) { - // There might be a merge instruction before OpBranchConditional. - --iter; - } - - assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLogicalNot, iter) && - "We should now be able to insert SpvOpLogicalNot before |iter|"); - - // Get the instruction whose result is used as a condition for - // OpBranchConditional. - const auto* condition_inst = ir_context->get_def_use_mgr()->GetDef( - branch_inst->GetSingleWordInOperand(0)); - assert(condition_inst); - - // We are swapping the labels in OpBranchConditional. This means that we must - // invert the guard as well. We are using OpLogicalNot for that purpose here. - iter.InsertBefore(MakeUnique( - ir_context, SpvOpLogicalNot, condition_inst->type_id(), - message_.fresh_id(), - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {condition_inst->result_id()}}})); - - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // Update OpBranchConditional condition operand. - branch_inst->GetInOperand(0).words[0] = message_.fresh_id(); - - // Swap label operands. - std::swap(branch_inst->GetInOperand(1), branch_inst->GetInOperand(2)); - - // Additionally, swap branch weights if present. - if (branch_inst->NumInOperands() > 3) { - std::swap(branch_inst->GetInOperand(3), branch_inst->GetInOperand(4)); - } - - // Make sure the changes are analyzed. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation -TransformationSwapConditionalBranchOperands::ToMessage() const { - protobufs::Transformation result; - *result.mutable_swap_conditional_branch_operands() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_swap_conditional_branch_operands.h b/3rdparty/spirv-tools/source/fuzz/transformation_swap_conditional_branch_operands.h deleted file mode 100644 index dd68ff8cf..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_swap_conditional_branch_operands.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2020 Vasyl Teliman -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_SWAP_CONDITIONAL_BRANCH_OPERANDS_H_ -#define SOURCE_FUZZ_TRANSFORMATION_SWAP_CONDITIONAL_BRANCH_OPERANDS_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 TransformationSwapConditionalBranchOperands : public Transformation { - public: - explicit TransformationSwapConditionalBranchOperands( - const protobufs::TransformationSwapConditionalBranchOperands& message); - - TransformationSwapConditionalBranchOperands( - const protobufs::InstructionDescriptor& instruction_descriptor, - uint32_t fresh_id); - - // - |message_.instruction_descriptor| must be a valid descriptor of some - // OpBranchConditional instruction in the module. - // - |message_.fresh_id| must be a fresh id. - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Inserts |%fresh_id = OpLogicalNot %bool_type_id %cond_id| before - // |OpBranchConditional %cond_id %branch_a %branch_b [%weight_a %weight_b]|. - // Replaces %cond_id with %fresh_id and swaps %branch_* and %weight_* - // operands. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationSwapConditionalBranchOperands message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_SWAP_CONDITIONAL_BRANCH_OPERANDS_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_toggle_access_chain_instruction.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_toggle_access_chain_instruction.cpp deleted file mode 100644 index ca24a18a9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_toggle_access_chain_instruction.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_toggle_access_chain_instruction.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationToggleAccessChainInstruction:: - TransformationToggleAccessChainInstruction( - const spvtools::fuzz::protobufs:: - TransformationToggleAccessChainInstruction& message) - : message_(message) {} - -TransformationToggleAccessChainInstruction:: - TransformationToggleAccessChainInstruction( - const protobufs::InstructionDescriptor& instruction_descriptor) { - *message_.mutable_instruction_descriptor() = instruction_descriptor; -} - -bool TransformationToggleAccessChainInstruction::IsApplicable( - opt::IRContext* ir_context, const TransformationContext& /*unused*/ - ) const { - auto instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - if (instruction == nullptr) { - return false; - } - - SpvOp opcode = static_cast( - message_.instruction_descriptor().target_instruction_opcode()); - - assert(instruction->opcode() == opcode && - "The located instruction must have the same opcode as in the " - "descriptor."); - - if (opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) { - return true; - } - - return false; -} - -void TransformationToggleAccessChainInstruction::Apply( - opt::IRContext* ir_context, TransformationContext* /*unused*/ - ) const { - auto instruction = - FindInstruction(message_.instruction_descriptor(), ir_context); - SpvOp opcode = instruction->opcode(); - - if (opcode == SpvOpAccessChain) { - instruction->SetOpcode(SpvOpInBoundsAccessChain); - } else { - assert(opcode == SpvOpInBoundsAccessChain && - "The located instruction must be an OpInBoundsAccessChain " - "instruction."); - instruction->SetOpcode(SpvOpAccessChain); - } -} - -protobufs::Transformation -TransformationToggleAccessChainInstruction::ToMessage() const { - protobufs::Transformation result; - *result.mutable_toggle_access_chain_instruction() = message_; - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_toggle_access_chain_instruction.h b/3rdparty/spirv-tools/source/fuzz/transformation_toggle_access_chain_instruction.h deleted file mode 100644 index 9cd8fd6e9..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_toggle_access_chain_instruction.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020 André Perez Maselco -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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_TOGGLE_ACCESS_CHAIN_INSTRUCTION_H_ -#define SOURCE_FUZZ_TRANSFORMATION_TOGGLE_ACCESS_CHAIN_INSTRUCTION_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 TransformationToggleAccessChainInstruction : public Transformation { - public: - explicit TransformationToggleAccessChainInstruction( - const protobufs::TransformationToggleAccessChainInstruction& message); - - TransformationToggleAccessChainInstruction( - const protobufs::InstructionDescriptor& instruction_descriptor); - - // - |message_.instruction_descriptor| must identify an existing - // access chain instruction - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Toggles the access chain instruction. - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - protobufs::TransformationToggleAccessChainInstruction message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_TOGGLE_ACCESS_CHAIN_INSTRUCTION_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp deleted file mode 100644 index b3bd59353..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/transformation_vector_shuffle.h" - -#include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/instruction_descriptor.h" - -namespace spvtools { -namespace fuzz { - -TransformationVectorShuffle::TransformationVectorShuffle( - const spvtools::fuzz::protobufs::TransformationVectorShuffle& message) - : message_(message) {} - -TransformationVectorShuffle::TransformationVectorShuffle( - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id, uint32_t vector1, uint32_t vector2, - const std::vector& component) { - *message_.mutable_instruction_to_insert_before() = - instruction_to_insert_before; - message_.set_fresh_id(fresh_id); - message_.set_vector1(vector1); - message_.set_vector2(vector2); - for (auto a_component : component) { - message_.add_component(a_component); - } -} - -bool TransformationVectorShuffle::IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - // The fresh id must not already be in use. - if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) { - return false; - } - // The instruction before which the shuffle will be inserted must exist. - auto instruction_to_insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); - if (!instruction_to_insert_before) { - return false; - } - // The first vector must be an instruction with a type id - auto vector1_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.vector1()); - if (!vector1_instruction || !vector1_instruction->type_id()) { - return false; - } - // We should be able to create a synonym of |vector1| if it's not irrelevant. - if (!transformation_context.GetFactManager()->IdIsIrrelevant( - message_.vector1()) && - !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, - vector1_instruction)) { - return false; - } - // The second vector must be an instruction with a type id - auto vector2_instruction = - ir_context->get_def_use_mgr()->GetDef(message_.vector2()); - if (!vector2_instruction || !vector2_instruction->type_id()) { - return false; - } - // We should be able to create a synonym of |vector2| if it's not irrelevant. - if (!transformation_context.GetFactManager()->IdIsIrrelevant( - message_.vector2()) && - !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, - vector2_instruction)) { - return false; - } - auto vector1_type = - ir_context->get_type_mgr()->GetType(vector1_instruction->type_id()); - // The first vector instruction's type must actually be a vector type. - if (!vector1_type->AsVector()) { - return false; - } - auto vector2_type = - ir_context->get_type_mgr()->GetType(vector2_instruction->type_id()); - // The second vector instruction's type must actually be a vector type. - if (!vector2_type->AsVector()) { - return false; - } - // The element types of the vectors must be the same. - if (vector1_type->AsVector()->element_type() != - vector2_type->AsVector()->element_type()) { - return false; - } - uint32_t combined_size = vector1_type->AsVector()->element_count() + - vector2_type->AsVector()->element_count(); - for (auto a_compoment : message_.component()) { - // 0xFFFFFFFF is used to represent an undefined component. Unless - // undefined, a component must be less than the combined size of the - // vectors. - if (a_compoment != 0xFFFFFFFF && a_compoment >= combined_size) { - return false; - } - } - // The module must already declare an appropriate type in which to store the - // result of the shuffle. - if (!GetResultTypeId(ir_context, *vector1_type->AsVector()->element_type())) { - return false; - } - // Each of the vectors used in the shuffle must be available at the insertion - // point. - for (auto used_instruction : {vector1_instruction, vector2_instruction}) { - if (auto block = ir_context->get_instr_block(used_instruction)) { - if (!ir_context->GetDominatorAnalysis(block->GetParent()) - ->Dominates(used_instruction, instruction_to_insert_before)) { - return false; - } - } - } - - // It must be legitimate to insert an OpVectorShuffle before the identified - // instruction. - return fuzzerutil::CanInsertOpcodeBeforeInstruction( - SpvOpVectorShuffle, instruction_to_insert_before); -} - -void TransformationVectorShuffle::Apply( - opt::IRContext* ir_context, - TransformationContext* transformation_context) const { - // Make input operands for a shuffle instruction - these comprise the two - // vectors being shuffled, followed by the integer literal components. - opt::Instruction::OperandList shuffle_operands = { - {SPV_OPERAND_TYPE_ID, {message_.vector1()}}, - {SPV_OPERAND_TYPE_ID, {message_.vector2()}}}; - for (auto a_component : message_.component()) { - shuffle_operands.push_back( - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {a_component}}); - } - - uint32_t result_type_id = GetResultTypeId( - ir_context, - *GetVectorType(ir_context, message_.vector1())->element_type()); - - // Add a shuffle instruction right before the instruction identified by - // |message_.instruction_to_insert_before|. - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique( - ir_context, SpvOpVectorShuffle, result_type_id, message_.fresh_id(), - shuffle_operands)); - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); - - // Add synonym facts relating the defined elements of the shuffle result to - // the vector components that they come from. - for (uint32_t component_index = 0; - component_index < static_cast(message_.component_size()); - component_index++) { - uint32_t component = message_.component(component_index); - if (component == 0xFFFFFFFF) { - // This component is undefined, so move on - but first note that the - // overall shuffle result cannot be synonymous with any vector. - continue; - } - - // This describes the element of the result vector associated with - // |component_index|. - protobufs::DataDescriptor descriptor_for_result_component = - MakeDataDescriptor(message_.fresh_id(), {component_index}); - - protobufs::DataDescriptor descriptor_for_source_component; - - // Get a data descriptor for the component of the input vector to which - // |component| refers. - if (component < - GetVectorType(ir_context, message_.vector1())->element_count()) { - // Irrelevant id cannot participate in DataSynonym facts. - if (transformation_context->GetFactManager()->IdIsIrrelevant( - message_.vector1())) { - continue; - } - - descriptor_for_source_component = - MakeDataDescriptor(message_.vector1(), {component}); - } else { - // Irrelevant id cannot participate in DataSynonym facts. - if (transformation_context->GetFactManager()->IdIsIrrelevant( - message_.vector2())) { - continue; - } - - auto index_into_vector_2 = - component - - GetVectorType(ir_context, message_.vector1())->element_count(); - assert( - index_into_vector_2 < - GetVectorType(ir_context, message_.vector2())->element_count() && - "Vector shuffle index is out of bounds."); - descriptor_for_source_component = - MakeDataDescriptor(message_.vector2(), {index_into_vector_2}); - } - - // Add a fact relating this input vector component with the associated - // result component. - transformation_context->GetFactManager()->AddFactDataSynonym( - descriptor_for_result_component, descriptor_for_source_component, - ir_context); - } -} - -protobufs::Transformation TransformationVectorShuffle::ToMessage() const { - protobufs::Transformation result; - *result.mutable_vector_shuffle() = message_; - return result; -} - -uint32_t TransformationVectorShuffle::GetResultTypeId( - opt::IRContext* ir_context, const opt::analysis::Type& element_type) const { - opt::analysis::Vector result_type( - &element_type, static_cast(message_.component_size())); - return ir_context->get_type_mgr()->GetId(&result_type); -} - -opt::analysis::Vector* TransformationVectorShuffle::GetVectorType( - opt::IRContext* ir_context, uint32_t id_of_vector) { - return ir_context->get_type_mgr() - ->GetType(ir_context->get_def_use_mgr()->GetDef(id_of_vector)->type_id()) - ->AsVector(); -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_vector_shuffle.h b/3rdparty/spirv-tools/source/fuzz/transformation_vector_shuffle.h deleted file mode 100644 index f91197615..000000000 --- a/3rdparty/spirv-tools/source/fuzz/transformation_vector_shuffle.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_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" -#include "source/opt/types.h" - -namespace spvtools { -namespace fuzz { - -class TransformationVectorShuffle : public Transformation { - public: - explicit TransformationVectorShuffle( - const protobufs::TransformationVectorShuffle& message); - - TransformationVectorShuffle( - const protobufs::InstructionDescriptor& instruction_to_insert_before, - uint32_t fresh_id, uint32_t vector1, uint32_t vector2, - const std::vector& component); - - // - |message_.fresh_id| must not be in use - // - |message_.instruction_to_insert_before| must identify an instruction - // before which it is legitimate to insert an OpVectorShuffle - // - |message_.vector1| and |message_.vector2| must be instructions of vector - // type, and the element types of these vectors must be the same - // - Each element of |message_.component| must either be 0xFFFFFFFF - // (representing an undefined component), or must be less than the combined - // sizes of the input vectors - // - The module must already contain a vector type with the same element type - // as |message_.vector1| and |message_.vector2|, and with the size of - // |message_component| as its element count - bool IsApplicable( - opt::IRContext* ir_context, - const TransformationContext& transformation_context) const override; - - // Inserts an OpVectorShuffle instruction before - // |message_.instruction_to_insert_before|, shuffles vectors - // |message_.vector1| and |message_.vector2| using the indices provided by - // |message_.component|, into |message_.fresh_id|. Adds a fact to the fact - // manager recording the fact each element of |message_.fresh_id| is - // synonymous with the element of |message_.vector1| or |message_.vector2| - // from which it came (with undefined components being ignored). If the - // result vector is a contiguous sub-range of one of the input vectors, a - // fact is added to record that |message_.fresh_id| is synonymous with this - // sub-range. DataSynonym facts are added only for non-irrelevant vectors - // (e.g. if |vector1| is irrelevant but |vector2| is not, synonyms will be - // created for |vector1| but not |vector2|). - void Apply(opt::IRContext* ir_context, - TransformationContext* transformation_context) const override; - - protobufs::Transformation ToMessage() const override; - - private: - // Returns a type id that already exists in |ir_context| suitable for - // representing the result of the shuffle, where |element_type| is known to - // be the common element type of the vectors to which the shuffle is being - // applied. Returns 0 if no such id exists. - uint32_t GetResultTypeId(opt::IRContext* ir_context, - const opt::analysis::Type& element_type) const; - - static opt::analysis::Vector* GetVectorType(opt::IRContext* ir_context, - uint32_t id_of_vector); - - protobufs::TransformationVectorShuffle message_; -}; - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp b/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp deleted file mode 100644 index 90fd85e96..000000000 --- a/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/fuzz/uniform_buffer_element_descriptor.h" - -#include - -namespace spvtools { -namespace fuzz { - -protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor( - uint32_t descriptor_set, uint32_t binding, - std::vector&& indices) { - protobufs::UniformBufferElementDescriptor result; - result.set_descriptor_set(descriptor_set); - result.set_binding(binding); - for (auto index : indices) { - result.add_index(index); - } - return result; -} - -bool UniformBufferElementDescriptorEquals::operator()( - const protobufs::UniformBufferElementDescriptor* first, - const protobufs::UniformBufferElementDescriptor* second) const { - return first->descriptor_set() == second->descriptor_set() && - first->binding() == second->binding() && - first->index().size() == second->index().size() && - std::equal(first->index().begin(), first->index().end(), - second->index().begin()); -} - -opt::Instruction* FindUniformVariable( - const protobufs::UniformBufferElementDescriptor& - uniform_buffer_element_descriptor, - opt::IRContext* context, bool check_unique) { - opt::Instruction* result = nullptr; - - for (auto& inst : context->types_values()) { - // Consider all global variables with uniform storage class. - if (inst.opcode() != SpvOpVariable) { - continue; - } - if (inst.GetSingleWordInOperand(0) != SpvStorageClassUniform) { - continue; - } - - // Determine whether the variable is decorated with a descriptor set - // matching that in |uniform_buffer_element|. - bool descriptor_set_matches = false; - context->get_decoration_mgr()->ForEachDecoration( - inst.result_id(), SpvDecorationDescriptorSet, - [&descriptor_set_matches, &uniform_buffer_element_descriptor]( - const opt::Instruction& decoration_inst) { - const uint32_t kDescriptorSetOperandIndex = 2; - if (decoration_inst.GetSingleWordInOperand( - kDescriptorSetOperandIndex) == - uniform_buffer_element_descriptor.descriptor_set()) { - descriptor_set_matches = true; - } - }); - if (!descriptor_set_matches) { - // Descriptor set does not match. - continue; - } - - // Determine whether the variable is decorated with a binding matching that - // in |uniform_buffer_element|. - bool binding_matches = false; - context->get_decoration_mgr()->ForEachDecoration( - inst.result_id(), SpvDecorationBinding, - [&binding_matches, &uniform_buffer_element_descriptor]( - const opt::Instruction& decoration_inst) { - const uint32_t kBindingOperandIndex = 2; - if (decoration_inst.GetSingleWordInOperand(kBindingOperandIndex) == - uniform_buffer_element_descriptor.binding()) { - binding_matches = true; - } - }); - if (!binding_matches) { - // Binding does not match. - continue; - } - - // This instruction is a uniform variable with the right descriptor set and - // binding. - if (!check_unique) { - // If we aren't checking uniqueness, return it. - return &inst; - } - - if (result) { - // More than one uniform variable is decorated with the given descriptor - // set and binding. This means the fact is ambiguous. - return nullptr; - } - result = &inst; - } - - // We get here either if no match was found, or if |check_unique| holds and - // exactly one match was found. - assert(result == nullptr || check_unique); - return result; -} - -} // namespace fuzz -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h b/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h deleted file mode 100644 index f5d7320a2..000000000 --- a/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ -#define SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ - -#include - -#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" -#include "source/opt/instruction.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace fuzz { - -// Factory method to create a uniform buffer element descriptor message from -// descriptor set and binding ids and a list of indices. -protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor( - uint32_t descriptor_set, uint32_t binding, std::vector&& indices); - -// Equality function for uniform buffer element descriptors. -struct UniformBufferElementDescriptorEquals { - bool operator()( - const protobufs::UniformBufferElementDescriptor* first, - const protobufs::UniformBufferElementDescriptor* second) const; -}; - -// Returns a pointer to an OpVariable in |context| that is decorated with the -// descriptor set and binding associated with |uniform_buffer_element|. Returns -// nullptr if no such variable exists. If multiple such variables exist, a -// pointer to an arbitrary one of the associated instructions is returned if -// |check_unique| is false, and nullptr is returned if |check_unique| is true. -opt::Instruction* FindUniformVariable( - const protobufs::UniformBufferElementDescriptor& - uniform_buffer_element_descriptor, - opt::IRContext* context, bool check_unique); - -} // namespace fuzz -} // namespace spvtools - -#endif // SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp index 84a0acf46..346134d4d 100644 --- a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp @@ -524,6 +524,7 @@ void DebugInfoManager::AddDebugValueIfVarDeclIsVisible( value_id, 0, index_id, insert_before); assert(added_dbg_value != nullptr); added_dbg_value->UpdateDebugInfoFrom(scope_and_line); + AnalyzeDebugInst(added_dbg_value); } } @@ -567,42 +568,84 @@ bool DebugInfoManager::IsDebugDeclare(Instruction* instr) { GetVariableIdOfDebugValueUsedForDeclare(instr) != 0; } -void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) { - if (!dbg_inst->IsOpenCL100DebugInstr()) return; +void DebugInfoManager::ReplaceAllUsesInDebugScopeWithPredicate( + uint32_t before, uint32_t after, + const std::function& predicate) { + auto scope_id_to_users_itr = scope_id_to_users_.find(before); + if (scope_id_to_users_itr != scope_id_to_users_.end()) { + for (Instruction* inst : scope_id_to_users_itr->second) { + if (predicate(inst)) inst->UpdateLexicalScope(after); + } + scope_id_to_users_[after] = scope_id_to_users_itr->second; + scope_id_to_users_.erase(scope_id_to_users_itr); + } + auto inlinedat_id_to_users_itr = inlinedat_id_to_users_.find(before); + if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) { + for (Instruction* inst : inlinedat_id_to_users_itr->second) { + if (predicate(inst)) inst->UpdateDebugInlinedAt(after); + } + inlinedat_id_to_users_[after] = inlinedat_id_to_users_itr->second; + inlinedat_id_to_users_.erase(inlinedat_id_to_users_itr); + } +} - RegisterDbgInst(dbg_inst); +void DebugInfoManager::ClearDebugScopeAndInlinedAtUses(Instruction* inst) { + auto scope_id_to_users_itr = scope_id_to_users_.find(inst->result_id()); + if (scope_id_to_users_itr != scope_id_to_users_.end()) { + scope_id_to_users_.erase(scope_id_to_users_itr); + } + auto inlinedat_id_to_users_itr = + inlinedat_id_to_users_.find(inst->result_id()); + if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) { + inlinedat_id_to_users_.erase(inlinedat_id_to_users_itr); + } +} - if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) { - assert(GetDebugFunction(dbg_inst->GetSingleWordOperand( +void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { + if (inst->GetDebugScope().GetLexicalScope() != kNoDebugScope) { + auto& users = scope_id_to_users_[inst->GetDebugScope().GetLexicalScope()]; + users.insert(inst); + } + if (inst->GetDebugInlinedAt() != kNoInlinedAt) { + auto& users = inlinedat_id_to_users_[inst->GetDebugInlinedAt()]; + users.insert(inst); + } + + if (!inst->IsOpenCL100DebugInstr()) return; + + RegisterDbgInst(inst); + + if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) { + assert(GetDebugFunction(inst->GetSingleWordOperand( kDebugFunctionOperandFunctionIndex)) == nullptr && "Two DebugFunction instruction exists for a single OpFunction."); - RegisterDbgFunction(dbg_inst); + RegisterDbgFunction(inst); } if (deref_operation_ == nullptr && - dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation && - dbg_inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex) == + inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation && + inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex) == OpenCLDebugInfo100Deref) { - deref_operation_ = dbg_inst; + deref_operation_ = inst; } if (debug_info_none_inst_ == nullptr && - dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) { - debug_info_none_inst_ = dbg_inst; + inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) { + debug_info_none_inst_ = inst; } - if (empty_debug_expr_inst_ == nullptr && IsEmptyDebugExpression(dbg_inst)) { - empty_debug_expr_inst_ = dbg_inst; + if (empty_debug_expr_inst_ == nullptr && IsEmptyDebugExpression(inst)) { + empty_debug_expr_inst_ = inst; } - if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) { + if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) { uint32_t var_id = - dbg_inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); - RegisterDbgDeclare(var_id, dbg_inst); + inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); + RegisterDbgDeclare(var_id, inst); } - if (uint32_t var_id = GetVariableIdOfDebugValueUsedForDeclare(dbg_inst)) { - RegisterDbgDeclare(var_id, dbg_inst); + if (uint32_t var_id = GetVariableIdOfDebugValueUsedForDeclare(inst)) { + RegisterDbgDeclare(var_id, inst); } } @@ -682,6 +725,17 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) { } void DebugInfoManager::ClearDebugInfo(Instruction* instr) { + auto scope_id_to_users_itr = + scope_id_to_users_.find(instr->GetDebugScope().GetLexicalScope()); + if (scope_id_to_users_itr != scope_id_to_users_.end()) { + scope_id_to_users_itr->second.erase(instr); + } + auto inlinedat_id_to_users_itr = + inlinedat_id_to_users_.find(instr->GetDebugInlinedAt()); + if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) { + inlinedat_id_to_users_itr->second.erase(instr); + } + if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) { return; } diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.h b/3rdparty/spirv-tools/source/opt/debug_info_manager.h index cdafc658c..6e7373bc4 100644 --- a/3rdparty/spirv-tools/source/opt/debug_info_manager.h +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.h @@ -171,6 +171,16 @@ class DebugInfoManager { // Returns true if |instr| is a debug declaration instruction. bool IsDebugDeclare(Instruction* instr); + // Replace all uses of |before| id that is an operand of a DebugScope with + // |after| id if those uses (instruction) return true for |predicate|. + void ReplaceAllUsesInDebugScopeWithPredicate( + uint32_t before, uint32_t after, + const std::function& predicate); + + // Removes uses of DebugScope |inst| from |scope_id_to_users_| or uses of + // DebugInlinedAt |inst| from |inlinedat_id_to_users_|. + void ClearDebugScopeAndInlinedAtUses(Instruction* inst); + private: IRContext* context() { return context_; } @@ -228,6 +238,14 @@ class DebugInfoManager { std::unordered_map> var_id_to_dbg_decl_; + // Mapping from DebugScope ids to users. + std::unordered_map> + scope_id_to_users_; + + // Mapping from DebugInlinedAt ids to users. + std::unordered_map> + inlinedat_id_to_users_; + // DebugOperation whose OpCode is OpenCLDebugInfo100Deref. Instruction* deref_operation_; diff --git a/3rdparty/spirv-tools/source/opt/instruction.cpp b/3rdparty/spirv-tools/source/opt/instruction.cpp index f46a4fb8d..961826139 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.cpp +++ b/3rdparty/spirv-tools/source/opt/instruction.cpp @@ -501,6 +501,40 @@ uint32_t Instruction::GetTypeComponent(uint32_t element) const { return subtype; } +void Instruction::UpdateLexicalScope(uint32_t scope) { + dbg_scope_.SetLexicalScope(scope); + for (auto& i : dbg_line_insts_) { + i.dbg_scope_.SetLexicalScope(scope); + } + if (!IsDebugLineInst(opcode()) && + context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) { + context()->get_debug_info_mgr()->AnalyzeDebugInst(this); + } +} + +void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) { + dbg_scope_.SetInlinedAt(new_inlined_at); + for (auto& i : dbg_line_insts_) { + i.dbg_scope_.SetInlinedAt(new_inlined_at); + } + if (!IsDebugLineInst(opcode()) && + context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) { + context()->get_debug_info_mgr()->AnalyzeDebugInst(this); + } +} + +void Instruction::UpdateDebugInfoFrom(const Instruction* from) { + if (from == nullptr) return; + clear_dbg_line_insts(); + if (!from->dbg_line_insts().empty()) + dbg_line_insts().push_back(from->dbg_line_insts()[0]); + SetDebugScope(from->GetDebugScope()); + if (!IsDebugLineInst(opcode()) && + context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) { + context()->get_debug_info_mgr()->AnalyzeDebugInst(this); + } +} + Instruction* Instruction::InsertBefore(std::unique_ptr&& inst) { inst.get()->InsertBefore(this); return inst.release(); diff --git a/3rdparty/spirv-tools/source/opt/instruction.h b/3rdparty/spirv-tools/source/opt/instruction.h index 3b81e3aac..252e8cb55 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.h +++ b/3rdparty/spirv-tools/source/opt/instruction.h @@ -301,14 +301,14 @@ class Instruction : public utils::IntrusiveNodeBase { inline void SetDebugScope(const DebugScope& scope); inline const DebugScope& GetDebugScope() const { return dbg_scope_; } // Updates DebugInlinedAt of DebugScope and OpLine. - inline void UpdateDebugInlinedAt(uint32_t new_inlined_at); + void UpdateDebugInlinedAt(uint32_t new_inlined_at); inline uint32_t GetDebugInlinedAt() const { return dbg_scope_.GetInlinedAt(); } // Updates lexical scope of DebugScope and OpLine. - inline void UpdateLexicalScope(uint32_t scope); + void UpdateLexicalScope(uint32_t scope); // Updates OpLine and DebugScope based on the information of |from|. - inline void UpdateDebugInfoFrom(const Instruction* from); + void UpdateDebugInfoFrom(const Instruction* from); // Remove the |index|-th operand void RemoveOperand(uint32_t index) { operands_.erase(operands_.begin() + index); @@ -670,28 +670,6 @@ inline void Instruction::SetDebugScope(const DebugScope& scope) { } } -inline void Instruction::UpdateLexicalScope(uint32_t scope) { - dbg_scope_.SetLexicalScope(scope); - for (auto& i : dbg_line_insts_) { - i.dbg_scope_.SetLexicalScope(scope); - } -} - -inline void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) { - dbg_scope_.SetInlinedAt(new_inlined_at); - for (auto& i : dbg_line_insts_) { - i.dbg_scope_.SetInlinedAt(new_inlined_at); - } -} - -inline void Instruction::UpdateDebugInfoFrom(const Instruction* from) { - if (from == nullptr) return; - clear_dbg_line_insts(); - if (!from->dbg_line_insts().empty()) - dbg_line_insts().push_back(from->dbg_line_insts()[0]); - SetDebugScope(from->GetDebugScope()); -} - inline void Instruction::SetResultType(uint32_t ty_id) { // TODO(dsinclair): Allow setting a type id if there wasn't one // previously. Need to make room in the operands_ array to place the result, diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index f147b0b73..3e610d707 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -181,6 +181,7 @@ Instruction* IRContext::KillInst(Instruction* inst) { } } if (AreAnalysesValid(kAnalysisDebugInfo)) { + get_debug_info_mgr()->ClearDebugScopeAndInlinedAtUses(inst); get_debug_info_mgr()->ClearDebugInfo(inst); } if (type_mgr_ && IsTypeInst(inst->opcode())) { @@ -247,15 +248,20 @@ bool IRContext::KillDef(uint32_t id) { } bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) { - return ReplaceAllUsesWithPredicate( - before, after, [](Instruction*, uint32_t) { return true; }); + return ReplaceAllUsesWithPredicate(before, after, + [](Instruction*) { return true; }); } bool IRContext::ReplaceAllUsesWithPredicate( uint32_t before, uint32_t after, - const std::function& predicate) { + const std::function& predicate) { if (before == after) return false; + if (AreAnalysesValid(kAnalysisDebugInfo)) { + get_debug_info_mgr()->ReplaceAllUsesInDebugScopeWithPredicate(before, after, + predicate); + } + // Ensure that |after| has been registered as def. assert(get_def_use_mgr()->GetDef(after) && "'after' is not a registered def."); @@ -263,7 +269,7 @@ bool IRContext::ReplaceAllUsesWithPredicate( std::vector> uses_to_update; get_def_use_mgr()->ForEachUse( before, [&predicate, &uses_to_update](Instruction* user, uint32_t index) { - if (predicate(user, index)) { + if (predicate(user)) { uses_to_update.emplace_back(user, index); } }); @@ -301,7 +307,6 @@ bool IRContext::ReplaceAllUsesWithPredicate( } AnalyzeUses(user); } - return true; } diff --git a/3rdparty/spirv-tools/source/opt/ir_context.h b/3rdparty/spirv-tools/source/opt/ir_context.h index 8c1b5d420..5aa25acde 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.h +++ b/3rdparty/spirv-tools/source/opt/ir_context.h @@ -418,13 +418,13 @@ class IRContext { bool ReplaceAllUsesWith(uint32_t before, uint32_t after); // Replace all uses of |before| id with |after| id if those uses - // (instruction, operand pair) return true for |predicate|. Returns true if + // (instruction) return true for |predicate|. Returns true if // any replacement happens. This method does not kill the definition of the // |before| id. If |after| is the same as |before|, does nothing and return // false. bool ReplaceAllUsesWithPredicate( uint32_t before, uint32_t after, - const std::function& predicate); + const std::function& predicate); // Returns true if all of the analyses that are suppose to be valid are // actually valid. diff --git a/3rdparty/spirv-tools/source/opt/simplification_pass.cpp b/3rdparty/spirv-tools/source/opt/simplification_pass.cpp index 001f35437..319ceecfd 100644 --- a/3rdparty/spirv-tools/source/opt/simplification_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/simplification_pass.cpp @@ -90,7 +90,7 @@ bool SimplificationPass::SimplifyFunction(Function* function) { if (inst->opcode() == SpvOpCopyObject) { context()->ReplaceAllUsesWithPredicate( inst->result_id(), inst->GetSingleWordInOperand(0), - [](Instruction* user, uint32_t) { + [](Instruction* user) { const auto opcode = user->opcode(); if (!spvOpcodeIsDebug(opcode) && !spvOpcodeIsDecoration(opcode)) { @@ -137,7 +137,7 @@ bool SimplificationPass::SimplifyFunction(Function* function) { if (inst->opcode() == SpvOpCopyObject) { context()->ReplaceAllUsesWithPredicate( inst->result_id(), inst->GetSingleWordInOperand(0), - [](Instruction* user, uint32_t) { + [](Instruction* user) { const auto opcode = user->opcode(); if (!spvOpcodeIsDebug(opcode) && !spvOpcodeIsDecoration(opcode)) { return true; diff --git a/3rdparty/spirv-tools/source/val/validate_builtins.cpp b/3rdparty/spirv-tools/source/val/validate_builtins.cpp index d86c91e4e..ab232c850 100644 --- a/3rdparty/spirv-tools/source/val/validate_builtins.cpp +++ b/3rdparty/spirv-tools/source/val/validate_builtins.cpp @@ -365,7 +365,7 @@ class BuiltInsValidator { // |referenced_from_inst| - instruction which references id defined by // |referenced_inst| from within a function. spv_result_t ValidateNotCalledWithExecutionModel( - const char* comment, SpvExecutionModel execution_model, + std::string comment, SpvExecutionModel execution_model, const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst); @@ -864,7 +864,7 @@ spv_result_t BuiltInsValidator::ValidateF32ArrHelper( } spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel( - const char* comment, SpvExecutionModel execution_model, + std::string comment, SpvExecutionModel execution_model, const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { @@ -903,6 +903,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { + uint32_t operand = decoration.params()[0]; if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && @@ -911,7 +912,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " to be only used for variables with Input or Output storage " "class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -949,7 +950,12 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( decoration, built_in_inst, /* Any number of components */ 0, [this, &decoration, &referenced_from_inst]( const std::string& message) -> spv_result_t { + uint32_t vuid = + (decoration.params()[0] == SpvBuiltInClipDistance) + ? 4191 + : 4200; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, @@ -971,8 +977,13 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( decoration, built_in_inst, /* Any number of components */ 0, [this, &decoration, &referenced_from_inst]( const std::string& message) -> spv_result_t { + uint32_t vuid = + (decoration.params()[0] == SpvBuiltInClipDistance) + ? 4191 + : 4200; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, @@ -987,8 +998,13 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( decoration, built_in_inst, /* Any number of components */ 0, [this, &decoration, &referenced_from_inst]( const std::string& message) -> spv_result_t { + uint32_t vuid = + (decoration.params()[0] == SpvBuiltInClipDistance) + ? 4191 + : 4200; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, @@ -1003,10 +1019,12 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( } default: { + uint32_t vuid = + (decoration.params()[0] == SpvBuiltInClipDistance) ? 4187 : 4196; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn " + << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " to be used only with Fragment, Vertex, " "TessellationControl, TessellationEvaluation or Geometry " "execution models. " @@ -1035,7 +1053,7 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition( decoration, inst, 4, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the " + << _.VkErrorID(4212) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn FragCoord " "variable needs to be a 4-component 32-bit float " @@ -1059,7 +1077,7 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(4211) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn FragCoord to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1070,6 +1088,7 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4210) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn FragCoord to be used only with " "Fragment execution model. " @@ -1096,7 +1115,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the " + << _.VkErrorID(4215) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn FragDepth " "variable needs to be a 32-bit float scalar. " @@ -1119,7 +1138,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassOutput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(4214) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn FragDepth to be only used for " "variables with Output storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1130,6 +1149,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4213) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn FragDepth to be used only with " "Fragment execution model. " @@ -1144,6 +1164,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( const auto* modes = _.GetExecutionModes(entry_point); if (!modes || !modes->count(SpvExecutionModeDepthReplacing)) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4216) << spvLogStringForEnv(_.context()->target_env) << " spec requires DepthReplacing execution mode to be " "declared when using BuiltIn FragDepth. " @@ -1170,7 +1191,7 @@ spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the " + << _.VkErrorID(4231) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn FrontFacing " "variable needs to be a bool scalar. " @@ -1193,7 +1214,7 @@ spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(4230) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn FrontFacing to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1204,6 +1225,7 @@ spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4229) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn FrontFacing to be used only with " "Fragment execution model. " @@ -1230,6 +1252,7 @@ spv_result_t BuiltInsValidator::ValidateHelperInvocationAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4241) << "According to the Vulkan spec BuiltIn HelperInvocation " "variable needs to be a bool scalar. " << message; @@ -1251,6 +1274,7 @@ spv_result_t BuiltInsValidator::ValidateHelperInvocationAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4240) << "Vulkan spec allows BuiltIn HelperInvocation to be only used " "for variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1261,6 +1285,7 @@ spv_result_t BuiltInsValidator::ValidateHelperInvocationAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4239) << "Vulkan spec allows BuiltIn HelperInvocation to be used only " "with Fragment execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1287,6 +1312,7 @@ spv_result_t BuiltInsValidator::ValidateInvocationIdAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4259) << "According to the Vulkan spec BuiltIn InvocationId " "variable needs to be a 32-bit int scalar. " << message; @@ -1308,6 +1334,7 @@ spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4258) << "Vulkan spec allows BuiltIn InvocationId to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1319,6 +1346,7 @@ spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference( if (execution_model != SpvExecutionModelTessellationControl && execution_model != SpvExecutionModelGeometry) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4257) << "Vulkan spec allows BuiltIn InvocationId to be used only " "with TessellationControl or Geometry execution models. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1344,7 +1372,7 @@ spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the " + << _.VkErrorID(4265) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn InstanceIndex " "variable needs to be a 32-bit int scalar. " @@ -1367,7 +1395,7 @@ spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(4264) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn InstanceIndex to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1378,6 +1406,7 @@ spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelVertex) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4263) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn InstanceIndex to be used only " "with Vertex execution model. " @@ -1404,6 +1433,7 @@ spv_result_t BuiltInsValidator::ValidatePatchVerticesAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4310) << "According to the Vulkan spec BuiltIn PatchVertices " "variable needs to be a 32-bit int scalar. " << message; @@ -1425,6 +1455,7 @@ spv_result_t BuiltInsValidator::ValidatePatchVerticesAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4309) << "Vulkan spec allows BuiltIn PatchVertices to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1436,6 +1467,7 @@ spv_result_t BuiltInsValidator::ValidatePatchVerticesAtReference( if (execution_model != SpvExecutionModelTessellationControl && execution_model != SpvExecutionModelTessellationEvaluation) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4308) << "Vulkan spec allows BuiltIn PatchVertices to be used only " "with TessellationControl or TessellationEvaluation " "execution models. " @@ -1462,6 +1494,7 @@ spv_result_t BuiltInsValidator::ValidatePointCoordAtDefinition( decoration, inst, 2, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4313) << "According to the Vulkan spec BuiltIn PointCoord " "variable needs to be a 2-component 32-bit float " "vector. " @@ -1484,6 +1517,7 @@ spv_result_t BuiltInsValidator::ValidatePointCoordAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4312) << "Vulkan spec allows BuiltIn PointCoord to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1494,6 +1528,7 @@ spv_result_t BuiltInsValidator::ValidatePointCoordAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4311) << "Vulkan spec allows BuiltIn PointCoord to be used only with " "Fragment execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1528,6 +1563,7 @@ spv_result_t BuiltInsValidator::ValidatePointSizeAtReference( storage_class != SpvStorageClassInput && storage_class != SpvStorageClassOutput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4316) << "Vulkan spec allows BuiltIn PointSize to be only used for " "variables with Input or Output storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1539,8 +1575,11 @@ spv_result_t BuiltInsValidator::ValidatePointSizeAtReference( assert(function_id_ == 0); id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, - "Vulkan spec doesn't allow BuiltIn PointSize to be used for " - "variables with Input storage class if execution model is Vertex.", + std::string( + _.VkErrorID(4315) + + "Vulkan spec doesn't allow BuiltIn PointSize to be used for " + "variables with Input storage class if execution model is " + "Vertex."), SpvExecutionModelVertex, decoration, built_in_inst, referenced_from_inst, std::placeholders::_1)); } @@ -1553,6 +1592,7 @@ spv_result_t BuiltInsValidator::ValidatePointSizeAtReference( [this, &referenced_from_inst]( const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4317) << "According to the Vulkan spec BuiltIn PointSize " "variable needs to be a 32-bit float scalar. " << message; @@ -1576,6 +1616,7 @@ spv_result_t BuiltInsValidator::ValidatePointSizeAtReference( const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4317) << "According to the Vulkan spec BuiltIn " "PointSize variable needs to be a 32-bit " "float scalar. " @@ -1590,6 +1631,7 @@ spv_result_t BuiltInsValidator::ValidatePointSizeAtReference( const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4317) << "According to the Vulkan spec BuiltIn " "PointSize variable needs to be a 32-bit " "float scalar. " @@ -1603,6 +1645,7 @@ spv_result_t BuiltInsValidator::ValidatePointSizeAtReference( default: { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4314) << "Vulkan spec allows BuiltIn PointSize to be used only with " "Vertex, TessellationControl, TessellationEvaluation or " "Geometry execution models. " @@ -1650,8 +1693,10 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( assert(function_id_ == 0); id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, - "Vulkan spec doesn't allow BuiltIn Position to be used for variables " - "with Input storage class if execution model is Vertex.", + std::string(_.VkErrorID(4320) + + "Vulkan spec doesn't allow BuiltIn Position to be used " + "for variables " + "with Input storage class if execution model is Vertex."), SpvExecutionModelVertex, decoration, built_in_inst, referenced_from_inst, std::placeholders::_1)); } @@ -1664,6 +1709,7 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( [this, &referenced_from_inst]( const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4321) << "According to the Vulkan spec BuiltIn Position " "variable needs to be a 4-component 32-bit float " "vector. " @@ -1690,6 +1736,7 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4321) << "According to the Vulkan spec BuiltIn Position " "variable needs to be a 4-component 32-bit " "float vector. " @@ -1704,6 +1751,7 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4321) << "According to the Vulkan spec BuiltIn Position " "variable needs to be a 4-component 32-bit " "float vector. " @@ -1717,6 +1765,7 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( default: { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4318) << "Vulkan spec allows BuiltIn Position to be used only " "with Vertex, TessellationControl, TessellationEvaluation" " or Geometry execution models. " @@ -1788,6 +1837,7 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4337) << "According to the Vulkan spec BuiltIn PrimitiveId " "variable needs to be a 32-bit int scalar. " << message; @@ -1799,6 +1849,7 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4337) << "According to the Vulkan spec BuiltIn PrimitiveId " "variable needs to be a 32-bit int scalar. " << message; @@ -1833,23 +1884,29 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference( assert(function_id_ == 0); id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, - "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for " - "variables with Output storage class if execution model is " - "TessellationControl.", + std::string( + _.VkErrorID(4334) + + "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for " + "variables with Output storage class if execution model is " + "TessellationControl."), SpvExecutionModelTessellationControl, decoration, built_in_inst, referenced_from_inst, std::placeholders::_1)); id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, - "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for " - "variables with Output storage class if execution model is " - "TessellationEvaluation.", + std::string( + _.VkErrorID(4334) + + "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for " + "variables with Output storage class if execution model is " + "TessellationEvaluation."), SpvExecutionModelTessellationEvaluation, decoration, built_in_inst, referenced_from_inst, std::placeholders::_1)); id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, - "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for " - "variables with Output storage class if execution model is " - "Fragment.", + std::string( + _.VkErrorID(4334) + + "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for " + "variables with Output storage class if execution model is " + "Fragment."), SpvExecutionModelFragment, decoration, built_in_inst, referenced_from_inst, std::placeholders::_1)); } @@ -1873,6 +1930,7 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference( default: { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4330) << "Vulkan spec allows BuiltIn PrimitiveId to be used only " "with Fragment, TessellationControl, " "TessellationEvaluation or Geometry execution models. " @@ -1900,6 +1958,7 @@ spv_result_t BuiltInsValidator::ValidateSampleIdAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4356) << "According to the Vulkan spec BuiltIn SampleId " "variable needs to be a 32-bit int scalar. " << message; @@ -1921,6 +1980,7 @@ spv_result_t BuiltInsValidator::ValidateSampleIdAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4355) << "Vulkan spec allows BuiltIn SampleId to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1931,6 +1991,7 @@ spv_result_t BuiltInsValidator::ValidateSampleIdAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4354) << "Vulkan spec allows BuiltIn SampleId to be used only with " "Fragment execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1956,6 +2017,7 @@ spv_result_t BuiltInsValidator::ValidateSampleMaskAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4359) << "According to the Vulkan spec BuiltIn SampleMask " "variable needs to be a 32-bit int array. " << message; @@ -1978,6 +2040,7 @@ spv_result_t BuiltInsValidator::ValidateSampleMaskAtReference( storage_class != SpvStorageClassInput && storage_class != SpvStorageClassOutput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4358) << "Vulkan spec allows BuiltIn SampleMask to be only used for " "variables with Input or Output storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -1988,6 +2051,7 @@ spv_result_t BuiltInsValidator::ValidateSampleMaskAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4357) << "Vulkan spec allows BuiltIn SampleMask to be used only " "with " "Fragment execution model. " @@ -2014,6 +2078,7 @@ spv_result_t BuiltInsValidator::ValidateSamplePositionAtDefinition( decoration, inst, 2, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4362) << "According to the Vulkan spec BuiltIn SamplePosition " "variable needs to be a 2-component 32-bit float " "vector. " @@ -2036,6 +2101,7 @@ spv_result_t BuiltInsValidator::ValidateSamplePositionAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4361) << "Vulkan spec allows BuiltIn SamplePosition to be only used " "for " "variables with Input storage class. " @@ -2047,6 +2113,7 @@ spv_result_t BuiltInsValidator::ValidateSamplePositionAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4360) << "Vulkan spec allows BuiltIn SamplePosition to be used only " "with " "Fragment execution model. " @@ -2073,6 +2140,7 @@ spv_result_t BuiltInsValidator::ValidateTessCoordAtDefinition( decoration, inst, 3, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4389) << "According to the Vulkan spec BuiltIn TessCoord " "variable needs to be a 3-component 32-bit float " "vector. " @@ -2095,6 +2163,7 @@ spv_result_t BuiltInsValidator::ValidateTessCoordAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4388) << "Vulkan spec allows BuiltIn TessCoord to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -2105,6 +2174,7 @@ spv_result_t BuiltInsValidator::ValidateTessCoordAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelTessellationEvaluation) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4387) << "Vulkan spec allows BuiltIn TessCoord to be used only with " "TessellationEvaluation execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -2130,6 +2200,7 @@ spv_result_t BuiltInsValidator::ValidateTessLevelOuterAtDefinition( decoration, inst, 4, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4393) << "According to the Vulkan spec BuiltIn TessLevelOuter " "variable needs to be a 4-component 32-bit float " "array. " @@ -2150,6 +2221,7 @@ spv_result_t BuiltInsValidator::ValidateTessLevelInnerAtDefinition( decoration, inst, 2, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4397) << "According to the Vulkan spec BuiltIn TessLevelOuter " "variable needs to be a 2-component 32-bit float " "array. " @@ -2167,6 +2239,7 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { + uint32_t operand = decoration.params()[0]; if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && @@ -2175,7 +2248,7 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " to be only used for variables with Input or Output storage " "class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -2216,10 +2289,11 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( } default: { + uint32_t vuid = (operand == SpvBuiltInTessLevelOuter) ? 4390 : 4394; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn " + << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " to be used only with TessellationControl or " "TessellationEvaluation execution models. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -2246,7 +2320,7 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the " + << _.VkErrorID(4400) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn VertexIndex variable needs to be a " "32-bit int scalar. " @@ -2381,7 +2455,7 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(4399) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn VertexIndex to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -2392,6 +2466,7 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelVertex) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4398) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn VertexIndex to be used only with " "Vertex execution model. " @@ -2422,7 +2497,10 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition( decoration, inst, [this, &decoration, &inst](const std::string& message) -> spv_result_t { + uint32_t vuid = + (decoration.params()[0] == SpvBuiltInLayer) ? 4276 : 4408; return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) @@ -2436,7 +2514,10 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition( decoration, inst, [this, &decoration, &inst](const std::string& message) -> spv_result_t { + uint32_t vuid = + (decoration.params()[0] == SpvBuiltInLayer) ? 4276 : 4408; return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) @@ -2456,6 +2537,7 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { + uint32_t operand = decoration.params()[0]; if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && @@ -2464,7 +2546,7 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " to be only used for variables with Input or Output storage " "class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -2516,17 +2598,18 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << "Using BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " in Vertex or Tessellation execution model requires " "the ShaderViewportIndexLayerEXT capability."; } break; } default: { + uint32_t vuid = (operand == SpvBuiltInLayer) ? 4272 : 4404; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn " + << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " to be used only with Vertex, TessellationEvaluation, " "Geometry, or Fragment execution models. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -2554,12 +2637,28 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition( decoration, inst, 3, [this, &decoration, &inst](const std::string& message) -> spv_result_t { + uint32_t operand = decoration.params()[0]; + uint32_t vuid = 0; + switch (operand) { + case SpvBuiltInGlobalInvocationId: + vuid = 4238; + break; + case SpvBuiltInLocalInvocationId: + vuid = 4283; + break; + case SpvBuiltInNumWorkgroups: + vuid = 4298; + break; + case SpvBuiltInWorkgroupId: + vuid = 4424; + break; + }; return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the " + << _.VkErrorID(vuid) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + operand) << " variable needs to be a 3-component 32-bit int " "vector. " << message; @@ -2577,12 +2676,28 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { + uint32_t operand = decoration.params()[0]; if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { + uint32_t vuid = 0; + switch (operand) { + case SpvBuiltInGlobalInvocationId: + vuid = 4237; + break; + case SpvBuiltInLocalInvocationId: + vuid = 4282; + break; + case SpvBuiltInNumWorkgroups: + vuid = 4297; + break; + case SpvBuiltInWorkgroupId: + vuid = 4423; + break; + }; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) @@ -2599,7 +2714,23 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( bool has_webgpu_model = execution_model == SpvExecutionModelGLCompute; if ((spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) || (spvIsWebGPUEnv(_.context()->target_env) && !has_webgpu_model)) { + uint32_t vuid = 0; + switch (operand) { + case SpvBuiltInGlobalInvocationId: + vuid = 4236; + break; + case SpvBuiltInLocalInvocationId: + vuid = 4281; + break; + case SpvBuiltInNumWorkgroups: + vuid = 4296; + break; + case SpvBuiltInWorkgroupId: + vuid = 4422; + break; + }; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, @@ -2793,6 +2924,7 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition( if (spvIsVulkanEnv(_.context()->target_env) && !spvOpcodeIsConstant(inst.opcode())) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4426) << "Vulkan spec requires BuiltIn WorkgroupSize to be a " "constant. " << GetIdDesc(inst) << " is not a constant."; @@ -2802,7 +2934,7 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition( decoration, inst, 3, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the " + << _.VkErrorID(4427) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn WorkgroupSize variable needs to be a " "3-component 32-bit int vector. " @@ -2824,6 +2956,7 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelGLCompute) { 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, diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index 0739148e4..1d09066b7 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/3rdparty/spirv-tools/source/val/validation_state.cpp @@ -1319,5 +1319,181 @@ bool ValidationState_t::IsValidStorageClass( return true; } +#define VUID_WRAP(vuid) "[" #vuid "] " + +// Currently no 2 VUID share the same id, so no need for |reference| +std::string ValidationState_t::VkErrorID(uint32_t id, + const char* /*reference*/) const { + if (!spvIsVulkanEnv(context_->target_env)) { + return ""; + } + + // This large switch case is only searched when an error has occured. + // If an id is changed, the old case must be modified or removed. Each string + // here is interpreted as being "implemented" + + // Clang format adds spaces between hyphens + // clang-format off + switch (id) { + case 4187: + return VUID_WRAP(VUID-ClipDistance-ClipDistance-04187); + case 4191: + return VUID_WRAP(VUID-ClipDistance-ClipDistance-04191); + case 4196: + return VUID_WRAP(VUID-CullDistance-CullDistance-04196); + case 4200: + return VUID_WRAP(VUID-CullDistance-CullDistance-04200); + case 4210: + return VUID_WRAP(VUID-FragCoord-FragCoord-04210); + case 4211: + return VUID_WRAP(VUID-FragCoord-FragCoord-04211); + case 4212: + return VUID_WRAP(VUID-FragCoord-FragCoord-04212); + case 4213: + return VUID_WRAP(VUID-FragDepth-FragDepth-04213); + case 4214: + return VUID_WRAP(VUID-FragDepth-FragDepth-04214); + case 4215: + return VUID_WRAP(VUID-FragDepth-FragDepth-04215); + case 4216: + return VUID_WRAP(VUID-FragDepth-FragDepth-04216); + case 4229: + return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229); + case 4230: + return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230); + case 4231: + return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231); + case 4236: + return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236); + case 4237: + return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04237); + case 4238: + return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04238); + case 4239: + return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04239); + case 4240: + return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240); + case 4241: + return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241); + case 4257: + return VUID_WRAP(VUID-InvocationId-InvocationId-04257); + case 4258: + return VUID_WRAP(VUID-InvocationId-InvocationId-04258); + case 4259: + return VUID_WRAP(VUID-InvocationId-InvocationId-04259); + case 4263: + return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04263); + case 4264: + return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264); + case 4265: + return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265); + case 4272: + return VUID_WRAP(VUID-Layer-Layer-04272); + case 4276: + return VUID_WRAP(VUID-Layer-Layer-04276); + case 4281: + return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04281); + case 4282: + return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282); + case 4283: + return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283); + case 4296: + return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04296); + case 4297: + return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297); + case 4298: + return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298); + case 4308: + return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308); + case 4309: + return VUID_WRAP(VUID-PatchVertices-PatchVertices-04309); + case 4310: + return VUID_WRAP(VUID-PatchVertices-PatchVertices-04310); + case 4311: + return VUID_WRAP(VUID-PointCoord-PointCoord-04311); + case 4312: + return VUID_WRAP(VUID-PointCoord-PointCoord-04312); + case 4313: + return VUID_WRAP(VUID-PointCoord-PointCoord-04313); + case 4314: + return VUID_WRAP(VUID-PointSize-PointSize-04314); + case 4315: + return VUID_WRAP(VUID-PointSize-PointSize-04315); + case 4316: + return VUID_WRAP(VUID-PointSize-PointSize-04316); + case 4317: + return VUID_WRAP(VUID-PointSize-PointSize-04317); + case 4318: + return VUID_WRAP(VUID-Position-Position-04318); + case 4320: + return VUID_WRAP(VUID-Position-Position-04320); + case 4321: + return VUID_WRAP(VUID-Position-Position-04321); + case 4330: + return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04330); + case 4334: + return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334); + case 4337: + return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337); + case 4354: + return VUID_WRAP(VUID-SampleId-SampleId-04354); + case 4355: + return VUID_WRAP(VUID-SampleId-SampleId-04355); + case 4356: + return VUID_WRAP(VUID-SampleId-SampleId-04356); + case 4357: + return VUID_WRAP(VUID-SampleMask-SampleMask-04357); + case 4358: + return VUID_WRAP(VUID-SampleMask-SampleMask-04358); + case 4359: + return VUID_WRAP(VUID-SampleMask-SampleMask-04359); + case 4360: + return VUID_WRAP(VUID-SamplePosition-SamplePosition-04360); + case 4361: + return VUID_WRAP(VUID-SamplePosition-SamplePosition-04361); + case 4362: + return VUID_WRAP(VUID-SamplePosition-SamplePosition-04362); + case 4387: + return VUID_WRAP(VUID-TessCoord-TessCoord-04387); + case 4388: + return VUID_WRAP(VUID-TessCoord-TessCoord-04388); + case 4389: + return VUID_WRAP(VUID-TessCoord-TessCoord-04389); + case 4390: + return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04390); + case 4393: + return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04393); + case 4394: + return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04394); + case 4397: + return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04397); + case 4398: + return VUID_WRAP(VUID-VertexIndex-VertexIndex-04398); + case 4399: + return VUID_WRAP(VUID-VertexIndex-VertexIndex-04399); + case 4400: + return VUID_WRAP(VUID-VertexIndex-VertexIndex-04400); + case 4404: + return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04404); + case 4408: + return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04408); + case 4422: + return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04422); + case 4423: + return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04423); + case 4424: + return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04424); + case 4425: + return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04425); + case 4426: + return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426); + case 4427: + return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427); + default: + return ""; // unknown id + }; + // clang-format on +} + } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/val/validation_state.h b/3rdparty/spirv-tools/source/val/validation_state.h index e5d31acf6..e852c524c 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.h +++ b/3rdparty/spirv-tools/source/val/validation_state.h @@ -707,6 +707,17 @@ class ValidationState_t { // Validates the storage class for the target environment. bool IsValidStorageClass(SpvStorageClass storage_class) const; + // Takes a Vulkan Valid Usage ID (VUID) as |id| and optional |reference| and + // will return a non-empty string only if ID is known and targeting Vulkan. + // VUIDs are found in the Vulkan-Docs repo in the form "[[VUID-ref-ref-id]]" + // where "id" is always an 5 char long number (with zeros padding) and matches + // to |id|. |reference| is used if there is a "common validity" and the VUID + // shares the same |id| value. + // + // More details about Vulkan validation can be found in Vulkan Guide: + // https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/validation_overview.md + std::string VkErrorID(uint32_t id, const char* reference = nullptr) const; + private: ValidationState_t(const ValidationState_t&);