diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 70abe50d9..4037413cb 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2020.4-dev", "SPIRV-Tools v2020.4-dev 2cdcab3215d654e18c3b6d5f12bd94e7e64fb8b1" +"v2020.4-dev", "SPIRV-Tools v2020.4-dev 685eeed2529a1671c875d204406decacdff43cb3" diff --git a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt index efd82e431..2eae79aaa 100644 --- a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt @@ -49,6 +49,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_pass_add_local_variables.h fuzzer_pass_add_no_contraction_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 @@ -64,6 +65,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_pass_permute_blocks.h fuzzer_pass_permute_function_parameters.h fuzzer_pass_push_ids_through_variables.h + fuzzer_pass_replace_linear_algebra_instructions.h fuzzer_pass_split_blocks.h fuzzer_pass_swap_commutable_operands.h fuzzer_pass_toggle_access_chain_instruction.h @@ -117,6 +119,7 @@ if(SPIRV_BUILD_FUZZER) transformation_replace_boolean_constant_with_constant_binary.h transformation_replace_constant_with_uniform.h transformation_replace_id_with_synonym.h + transformation_replace_linear_algebra_instruction.h transformation_set_function_control.h transformation_set_loop_control.h transformation_set_memory_operands_mask.h @@ -148,6 +151,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_pass_add_local_variables.cpp fuzzer_pass_add_no_contraction_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 @@ -163,6 +167,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_pass_permute_blocks.cpp fuzzer_pass_permute_function_parameters.cpp fuzzer_pass_push_ids_through_variables.cpp + fuzzer_pass_replace_linear_algebra_instructions.cpp fuzzer_pass_split_blocks.cpp fuzzer_pass_swap_commutable_operands.cpp fuzzer_pass_toggle_access_chain_instruction.cpp @@ -215,6 +220,7 @@ if(SPIRV_BUILD_FUZZER) transformation_replace_boolean_constant_with_constant_binary.cpp transformation_replace_constant_with_uniform.cpp transformation_replace_id_with_synonym.cpp + transformation_replace_linear_algebra_instruction.cpp transformation_set_function_control.cpp transformation_set_loop_control.cpp transformation_set_memory_operands_mask.cpp diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp index 801fae3e2..420926a57 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer.cpp @@ -33,6 +33,7 @@ #include "source/fuzz/fuzzer_pass_add_local_variables.h" #include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h" #include "source/fuzz/fuzzer_pass_add_stores.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" @@ -47,6 +48,7 @@ #include "source/fuzz/fuzzer_pass_permute_blocks.h" #include "source/fuzz/fuzzer_pass_permute_function_parameters.h" #include "source/fuzz/fuzzer_pass_push_ids_through_variables.h" +#include "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h" #include "source/fuzz/fuzzer_pass_split_blocks.h" #include "source/fuzz/fuzzer_pass_swap_commutable_operands.h" #include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h" @@ -223,6 +225,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run( 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); @@ -253,6 +258,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run( 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); diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp index 923c25554..ef0de5ee1 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp @@ -40,6 +40,7 @@ const std::pair kChanceOfAddingNoContractionDecoration = { 5, 70}; const std::pair kChanceOfAddingStore = {5, 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}; @@ -64,6 +65,8 @@ const std::pair kChanceOfOutliningFunction = {10, 90}; const std::pair kChanceOfPermutingParameters = {30, 90}; const std::pair kChanceOfPushingIdThroughVariable = {5, 50}; const std::pair kChanceOfReplacingIdWithSynonym = {10, 90}; +const std::pair + kChanceOfReplacingLinearAlgebraInstructions = {10, 90}; const std::pair kChanceOfSplittingBlock = {40, 95}; const std::pair kChanceOfTogglingAccessChainInstruction = { 20, 90}; @@ -124,6 +127,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator, chance_of_adding_no_contraction_decoration_ = ChooseBetweenMinAndMax(kChanceOfAddingNoContractionDecoration); 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_ = @@ -162,6 +167,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator, ChooseBetweenMinAndMax(kChanceOfPushingIdThroughVariable); chance_of_replacing_id_with_synonym_ = ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym); + chance_of_replacing_linear_algebra_instructions_ = + ChooseBetweenMinAndMax(kChanceOfReplacingLinearAlgebraInstructions); chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock); chance_of_toggling_access_chain_instruction_ = ChooseBetweenMinAndMax(kChanceOfTogglingAccessChainInstruction); @@ -171,6 +178,16 @@ 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) { diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h index b1392e7eb..5f1d3beb3 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_context.h @@ -100,6 +100,9 @@ class FuzzerContext { // 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() { @@ -133,6 +136,9 @@ class FuzzerContext { return chance_of_adding_no_contraction_decoration_; } uint32_t GetChanceOfAddingStore() { return chance_of_adding_store_; } + uint32_t GetChanceOfAddingVectorShuffle() { + return chance_of_adding_vector_shuffle_; + } uint32_t GetChanceOfAddingVectorType() { return chance_of_adding_vector_type_; } @@ -185,6 +191,9 @@ class FuzzerContext { uint32_t GetChanceOfReplacingIdWithSynonym() { return chance_of_replacing_id_with_synonym_; } + uint32_t GetChanceOfReplacingLinearAlgebraInstructions() { + return chance_of_replacing_linear_algebra_instructions_; + } uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; } uint32_t GetChanceOfTogglingAccessChainInstruction() { return chance_of_toggling_access_chain_instruction_; @@ -195,18 +204,6 @@ class FuzzerContext { uint32_t GetMaximumEquivalenceClassSizeForDataSynonymFactClosure() { return max_equivalence_class_size_for_data_synonym_fact_closure_; } - uint32_t GetRandomIndexForAccessChain(uint32_t composite_size_bound) { - return random_generator_->RandomUint32(composite_size_bound); - } - 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_); - } std::pair GetRandomBranchWeights() { std::pair branch_weights = {0, 0}; @@ -219,6 +216,29 @@ class FuzzerContext { 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 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 GetRandomSizeForNewArray() { // Ensure that the array size is non-zero. return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1; @@ -248,6 +268,7 @@ class FuzzerContext { uint32_t chance_of_adding_matrix_type_; uint32_t chance_of_adding_no_contraction_decoration_; uint32_t chance_of_adding_store_; + 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_; @@ -268,6 +289,7 @@ class FuzzerContext { uint32_t chance_of_permuting_parameters_; uint32_t chance_of_pushing_id_through_variable_; uint32_t chance_of_replacing_id_with_synonym_; + uint32_t chance_of_replacing_linear_algebra_instructions_; uint32_t chance_of_splitting_block_; uint32_t chance_of_toggling_access_chain_instruction_; 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 new file mode 100644 index 000000000..21b5310c0 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp @@ -0,0 +1,133 @@ +// 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, + [instruction_descriptor]( + opt::IRContext* ir_context, + opt::Instruction* instruction) -> bool { + if (!instruction->type_id()) { + return false; + } + + if (!ir_context->get_type_mgr() + ->GetType(instruction->type_id()) + ->AsVector()) { + 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 new file mode 100644 index 000000000..99b9f244c --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h @@ -0,0 +1,39 @@ +// 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_replace_linear_algebra_instructions.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp new file mode 100644 index 000000000..1c7b8285b --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp @@ -0,0 +1,64 @@ +// 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 supported linear algebra + // instruction. In this case, the transformation is randomly applied. + GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354): + // Right now we only support certain operations. When this issue is + // addressed the following conditional can use the function + // |spvOpcodeIsLinearAlgebra|. + if (instruction->opcode() != SpvOpVectorTimesScalar && + instruction->opcode() != SpvOpDot) { + return; + } + + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext() + ->GetChanceOfReplacingLinearAlgebraInstructions())) { + return; + } + + 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 new file mode 100644 index 000000000..2c6126cd1 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h @@ -0,0 +1,40 @@ +// 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/protobufs/spvtoolsfuzz.proto b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto index 052af162a..57d85ab7f 100644 --- a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto +++ b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -377,6 +377,7 @@ message Transformation { TransformationAdjustBranchWeights adjust_branch_weights = 46; TransformationPushIdThroughVariable push_id_through_variable = 47; TransformationAddSpecConstantOp add_spec_constant_op = 48; + TransformationReplaceLinearAlgebraInstruction replace_linear_algebra_instruction = 49; // Add additional option using the next available number. } } @@ -1081,6 +1082,33 @@ message TransformationReplaceIdWithSynonym { } +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. + // This transformation is only applicable if the described instruction has one of the following opcodes. + // Supported: + // OpVectorTimesScalar + // OpDot + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354): + // Right now we only support certain operations. When this issue is addressed + // the supporting comments can be removed. + // To be supported in the future: + // OpTranspose + // OpMatrixTimesScalar + // OpVectorTimesMatrix + // OpMatrixTimesVector + // OpMatrixTimesMatrix + // OpOuterProduct + InstructionDescriptor instruction_descriptor = 2; + +} + message TransformationSetFunctionControl { // A transformation that sets the function control operand of an OpFunction diff --git a/3rdparty/spirv-tools/source/fuzz/transformation.cpp b/3rdparty/spirv-tools/source/fuzz/transformation.cpp index 71e234890..99f77d252 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation.cpp @@ -56,6 +56,7 @@ #include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" #include "source/fuzz/transformation_replace_constant_with_uniform.h" #include "source/fuzz/transformation_replace_id_with_synonym.h" +#include "source/fuzz/transformation_replace_linear_algebra_instruction.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" @@ -182,6 +183,10 @@ std::unique_ptr Transformation::FromMessage( 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::kSetFunctionControl: return MakeUnique( message.set_function_control()); 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 new file mode 100644 index 000000000..14ed502ff --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.cpp @@ -0,0 +1,275 @@ +// 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); + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354): + // Right now we only support certain operations. When this issue is addressed + // the following conditional can use the function |spvOpcodeIsLinearAlgebra|. + // It must be a supported linear algebra instruction. + if (instruction->opcode() != SpvOpVectorTimesScalar && + instruction->opcode() != SpvOpDot) { + 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 i = 0; i < static_cast(message_.fresh_ids().size()); + i++) { + if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_ids(i))) { + 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 SpvOpVectorTimesScalar: + ReplaceOpVectorTimesScalar(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 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 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::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::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 new file mode 100644 index 000000000..de280e40f --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.h @@ -0,0 +1,67 @@ +// 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 OpVectorTimesScalar instruction. + void ReplaceOpVectorTimesScalar(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/opcode.cpp b/3rdparty/spirv-tools/source/opcode.cpp index 80fe3b3a9..079def626 100644 --- a/3rdparty/spirv-tools/source/opcode.cpp +++ b/3rdparty/spirv-tools/source/opcode.cpp @@ -650,6 +650,22 @@ bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode) { } } +bool spvOpcodeIsLinearAlgebra(SpvOp opcode) { + switch (opcode) { + case SpvOpTranspose: + case SpvOpVectorTimesScalar: + case SpvOpMatrixTimesScalar: + case SpvOpVectorTimesMatrix: + case SpvOpMatrixTimesVector: + case SpvOpMatrixTimesMatrix: + case SpvOpOuterProduct: + case SpvOpDot: + return true; + default: + return false; + } +} + std::vector spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) { switch (opcode) { case SpvOpMemoryBarrier: diff --git a/3rdparty/spirv-tools/source/opcode.h b/3rdparty/spirv-tools/source/opcode.h index b4f02718f..0d8ec9257 100644 --- a/3rdparty/spirv-tools/source/opcode.h +++ b/3rdparty/spirv-tools/source/opcode.h @@ -134,6 +134,9 @@ bool spvOpcodeIsDebug(SpvOp opcode); // where the order of the operands is irrelevant. bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode); +// Returns true for opcodes that represents linear algebra instructions. +bool spvOpcodeIsLinearAlgebra(SpvOp opcode); + // Returns a vector containing the indices of the memory semantics // operands for |opcode|. std::vector spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode); diff --git a/3rdparty/spirv-tools/source/operand.cpp b/3rdparty/spirv-tools/source/operand.cpp index 755ad6ac7..09105958e 100644 --- a/3rdparty/spirv-tools/source/operand.cpp +++ b/3rdparty/spirv-tools/source/operand.cpp @@ -455,7 +455,7 @@ bool spvIsInIdType(spv_operand_type_t type) { return false; } switch (type) { - // Blacklist non-input IDs. + // Deny non-input IDs. case SPV_OPERAND_TYPE_TYPE_ID: case SPV_OPERAND_TYPE_RESULT_ID: return false; diff --git a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp index db2b67b92..760d8e843 100644 --- a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp @@ -131,11 +131,11 @@ void AggressiveDCEPass::AddStores(uint32_t ptrId) { } bool AggressiveDCEPass::AllExtensionsSupported() const { - // If any extension not in whitelist, return false + // If any extension not in allowlist, return false for (auto& ei : get_module()->extensions()) { const char* extName = reinterpret_cast(&ei.GetInOperand(0).words[0]); - if (extensions_whitelist_.find(extName) == extensions_whitelist_.end()) + if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } return true; @@ -882,14 +882,14 @@ bool AggressiveDCEPass::ProcessGlobalValues() { AggressiveDCEPass::AggressiveDCEPass() = default; Pass::Status AggressiveDCEPass::Process() { - // Initialize extensions whitelist + // Initialize extensions allowlist InitExtensions(); return ProcessImpl(); } void AggressiveDCEPass::InitExtensions() { - extensions_whitelist_.clear(); - extensions_whitelist_.insert({ + extensions_allowlist_.clear(); + extensions_allowlist_.insert({ "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader", diff --git a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h index c043a96f4..131e33a26 100644 --- a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h +++ b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h @@ -87,7 +87,7 @@ class AggressiveDCEPass : public MemPass { // to the live instruction worklist. void AddStores(uint32_t ptrId); - // Initialize extensions whitelist + // Initialize extensions allowlist void InitExtensions(); // Return true if all extensions in this module are supported by this pass. @@ -191,7 +191,7 @@ class AggressiveDCEPass : public MemPass { std::vector to_kill_; // Extensions supported by this pass. - std::unordered_set extensions_whitelist_; + std::unordered_set extensions_allowlist_; }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp index 16d9fd563..0054f5764 100644 --- a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp @@ -41,6 +41,7 @@ bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) { bool condIsConst; Instruction* cInst = get_def_use_mgr()->GetDef(condId); switch (cInst->opcode()) { + case SpvOpConstantNull: case SpvOpConstantFalse: { *condVal = false; condIsConst = true; diff --git a/3rdparty/spirv-tools/source/opt/function.h b/3rdparty/spirv-tools/source/opt/function.h index d569bf9a7..f5035f08b 100644 --- a/3rdparty/spirv-tools/source/opt/function.h +++ b/3rdparty/spirv-tools/source/opt/function.h @@ -72,6 +72,10 @@ class Function { // Delete all basic blocks that contain no instructions. inline void RemoveEmptyBlocks(); + // Removes a parameter from the function with result id equal to |id|. + // Does nothing if the function doesn't have such a parameter. + inline void RemoveParameter(uint32_t id); + // Saves the given function end instruction. inline void SetFunctionEnd(std::unique_ptr end_inst); @@ -219,6 +223,14 @@ inline void Function::RemoveEmptyBlocks() { blocks_.erase(first_empty, std::end(blocks_)); } +inline void Function::RemoveParameter(uint32_t id) { + params_.erase(std::remove_if(params_.begin(), params_.end(), + [id](const std::unique_ptr& param) { + return param->result_id() == id; + }), + params_.end()); +} + inline void Function::SetFunctionEnd(std::unique_ptr end_inst) { end_inst_ = std::move(end_inst); } diff --git a/3rdparty/spirv-tools/source/opt/instruction_list.h b/3rdparty/spirv-tools/source/opt/instruction_list.h index ea1cc7c46..417cbd768 100644 --- a/3rdparty/spirv-tools/source/opt/instruction_list.h +++ b/3rdparty/spirv-tools/source/opt/instruction_list.h @@ -61,6 +61,16 @@ class InstructionList : public utils::IntrusiveList { : utils::IntrusiveList::iterator(i) {} iterator(Instruction* i) : utils::IntrusiveList::iterator(i) {} + iterator& operator++() { + utils::IntrusiveList::iterator::operator++(); + return *this; + } + + iterator& operator--() { + utils::IntrusiveList::iterator::operator--(); + return *this; + } + // DEPRECATED: Please use MoveBefore with an InstructionList instead. // // Moves the nodes in |list| to the list that |this| points to. The diff --git a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp index 0afe79858..05704c148 100644 --- a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp @@ -281,7 +281,7 @@ void LocalAccessChainConvertPass::Initialize() { // Initialize collections supported_ref_ptrs_.clear(); - // Initialize extension whitelist + // Initialize extension allowlist InitExtensions(); } @@ -292,11 +292,11 @@ bool LocalAccessChainConvertPass::AllExtensionsSupported() const { if (context()->get_feature_mgr()->HasCapability( SpvCapabilityVariablePointers)) return false; - // If any extension not in whitelist, return false + // If any extension not in allowlist, return false for (auto& ei : get_module()->extensions()) { const char* extName = reinterpret_cast(&ei.GetInOperand(0).words[0]); - if (extensions_whitelist_.find(extName) == extensions_whitelist_.end()) + if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } return true; @@ -336,8 +336,8 @@ Pass::Status LocalAccessChainConvertPass::Process() { } void LocalAccessChainConvertPass::InitExtensions() { - extensions_whitelist_.clear(); - extensions_whitelist_.insert({ + extensions_allowlist_.clear(); + extensions_allowlist_.insert({ "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader", diff --git a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h index e3592bf0c..552062e52 100644 --- a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h +++ b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h @@ -110,7 +110,7 @@ class LocalAccessChainConvertPass : public MemPass { // Returns a status to indicate success or failure, and change or no change. Status ConvertLocalAccessChains(Function* func); - // Initialize extensions whitelist + // Initialize extensions allowlist void InitExtensions(); // Return true if all extensions in this module are allowed by this pass. @@ -124,7 +124,7 @@ class LocalAccessChainConvertPass : public MemPass { std::unordered_set supported_ref_ptrs_; // Extensions supported by this pass. - std::unordered_set extensions_whitelist_; + std::unordered_set extensions_allowlist_; }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp index b5435bb7a..401dad8e3 100644 --- a/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp @@ -168,16 +168,16 @@ void LocalSingleBlockLoadStoreElimPass::Initialize() { // Clear collections supported_ref_ptrs_.clear(); - // Initialize extensions whitelist + // Initialize extensions allowlist InitExtensions(); } bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const { - // If any extension not in whitelist, return false + // If any extension not in allowlist, return false for (auto& ei : get_module()->extensions()) { const char* extName = reinterpret_cast(&ei.GetInOperand(0).words[0]); - if (extensions_whitelist_.find(extName) == extensions_whitelist_.end()) + if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } return true; @@ -214,8 +214,8 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process() { } void LocalSingleBlockLoadStoreElimPass::InitExtensions() { - extensions_whitelist_.clear(); - extensions_whitelist_.insert({ + extensions_allowlist_.clear(); + extensions_allowlist_.insert({ "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader", diff --git a/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.h b/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.h index 0fe7732a8..ea72816a8 100644 --- a/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.h +++ b/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.h @@ -63,7 +63,7 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass { // where possible. Assumes logical addressing. bool LocalSingleBlockLoadStoreElim(Function* func); - // Initialize extensions whitelist + // Initialize extensions allowlist void InitExtensions(); // Return true if all extensions in this module are supported by this pass. @@ -94,7 +94,7 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass { std::unordered_set pinned_vars_; // Extensions supported by this pass. - std::unordered_set extensions_whitelist_; + std::unordered_set extensions_allowlist_; // Variables that are only referenced by supported operations for this // pass ie. loads and stores. diff --git a/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp index 4c71ce1ca..3f6185347 100644 --- a/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp @@ -46,11 +46,11 @@ bool LocalSingleStoreElimPass::LocalSingleStoreElim(Function* func) { } bool LocalSingleStoreElimPass::AllExtensionsSupported() const { - // If any extension not in whitelist, return false + // If any extension not in allowlist, return false for (auto& ei : get_module()->extensions()) { const char* extName = reinterpret_cast(&ei.GetInOperand(0).words[0]); - if (extensions_whitelist_.find(extName) == extensions_whitelist_.end()) + if (extensions_allowlist_.find(extName) == extensions_allowlist_.end()) return false; } return true; @@ -74,12 +74,12 @@ Pass::Status LocalSingleStoreElimPass::ProcessImpl() { LocalSingleStoreElimPass::LocalSingleStoreElimPass() = default; Pass::Status LocalSingleStoreElimPass::Process() { - InitExtensionWhiteList(); + InitExtensionAllowList(); return ProcessImpl(); } -void LocalSingleStoreElimPass::InitExtensionWhiteList() { - extensions_whitelist_.insert({ +void LocalSingleStoreElimPass::InitExtensionAllowList() { + extensions_allowlist_.insert({ "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader", diff --git a/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.h b/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.h index 4cf8bbb86..a7cdd1920 100644 --- a/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.h +++ b/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.h @@ -57,8 +57,8 @@ class LocalSingleStoreElimPass : public Pass { // any resulting dead code. bool LocalSingleStoreElim(Function* func); - // Initialize extensions whitelist - void InitExtensionWhiteList(); + // Initialize extensions allowlist + void InitExtensionAllowList(); // Return true if all extensions in this module are allowed by this pass. bool AllExtensionsSupported() const; @@ -94,7 +94,7 @@ class LocalSingleStoreElimPass : public Pass { const std::vector& uses); // Extensions supported by this pass. - std::unordered_set extensions_whitelist_; + std::unordered_set extensions_allowlist_; }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp b/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp index 11f7e9cfa..ed0dd28f4 100644 --- a/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp +++ b/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp @@ -485,10 +485,27 @@ void Loop::ComputeLoopStructuredOrder( if (include_pre_header && GetPreHeaderBlock()) ordered_loop_blocks->push_back(loop_preheader_); - cfg.ForEachBlockInReversePostOrder( - loop_header_, [ordered_loop_blocks, this](BasicBlock* bb) { - if (IsInsideLoop(bb)) ordered_loop_blocks->push_back(bb); - }); + + bool is_shader = + context_->get_feature_mgr()->HasCapability(SpvCapabilityShader); + if (!is_shader) { + cfg.ForEachBlockInReversePostOrder( + loop_header_, [ordered_loop_blocks, this](BasicBlock* bb) { + if (IsInsideLoop(bb)) ordered_loop_blocks->push_back(bb); + }); + } else { + // If this is a shader, it is possible that there are unreachable merge and + // continue blocks that must be copied to retain the structured order. + // The structured order will include these. + std::list order; + cfg.ComputeStructuredOrder(loop_header_->GetParent(), loop_header_, &order); + for (BasicBlock* bb : order) { + if (bb == GetMergeBlock()) { + break; + } + ordered_loop_blocks->push_back(bb); + } + } if (include_merge && GetMergeBlock()) ordered_loop_blocks->push_back(loop_merge_); } diff --git a/3rdparty/spirv-tools/utils/check_symbol_exports.py b/3rdparty/spirv-tools/utils/check_symbol_exports.py index e14c2eb89..bcd77da68 100755 --- a/3rdparty/spirv-tools/utils/check_symbol_exports.py +++ b/3rdparty/spirv-tools/utils/check_symbol_exports.py @@ -55,11 +55,11 @@ def check_library(library): # _Z[0-9]+spv[A-Z_] : C++ symbol starting with spv[A-Z_] symbol_ok_pattern = re.compile(r'^(spv[A-Z]|_ZN|_Z[0-9]+spv[A-Z_])') - # In addition, the following pattern whitelists global functions that are added + # In addition, the following pattern allowlists global functions that are added # by the protobuf compiler: # - AddDescriptors_spvtoolsfuzz_2eproto() # - InitDefaults_spvtoolsfuzz_2eproto() - symbol_whitelist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov') + symbol_allowlist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov') seen = set() result = 0 @@ -70,7 +70,7 @@ def check_library(library): if symbol not in seen: seen.add(symbol) #print("look at '{}'".format(symbol)) - if not (symbol_whitelist_pattern.match(symbol) or symbol_ok_pattern.match(symbol)): + if not (symbol_allowlist_pattern.match(symbol) or symbol_ok_pattern.match(symbol)): print('{}: error: Unescaped exported symbol: {}'.format(PROG, symbol)) result = 1 return result