spirv-fuzz: Implement vector shuffle fuzzer pass (#3412)

Fixes #3108.
This commit is contained in:
André Perez 2020-06-16 07:21:31 -03:00 committed by GitHub
parent 12a4fb3bc1
commit 9494703546
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 208 additions and 12 deletions

View File

@ -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
@ -150,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

View File

@ -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"
@ -224,6 +225,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
MaybeAddPass<FuzzerPassAddStores>(&passes, ir_context.get(),
&transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddVectorShuffleInstructions>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassApplyIdSynonyms>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);

View File

@ -40,6 +40,7 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingNoContractionDecoration = {
5, 70};
const std::pair<uint32_t, uint32_t> kChanceOfAddingStore = {5, 50};
const std::pair<uint32_t, uint32_t> kChanceOfAddingVectorType = {20, 70};
const std::pair<uint32_t, uint32_t> kChanceOfAddingVectorShuffle = {20, 70};
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingBranchWeights = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingFunctionControl = {20,
70};
@ -126,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_ =

View File

@ -136,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_;
}
@ -201,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<uint32_t, uint32_t> GetRandomBranchWeights() {
std::pair<uint32_t, uint32_t> branch_weights = {0, 0};
@ -225,6 +216,29 @@ class FuzzerContext {
return branch_weights;
}
std::vector<uint32_t> GetRandomComponentsForVectorShuffle(
uint32_t max_component_index) {
// Component count must be in range [2, 4].
std::vector<uint32_t> 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;
@ -254,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_;

View File

@ -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<opt::Instruction*> 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<uint32_t> 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<uint32_t>(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

View File

@ -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_