Skip to content

Commit

Permalink
spirv-fuzz: Fuzzer pass to randomly apply loop preheaders (KhronosGro…
Browse files Browse the repository at this point in the history
…up#3668)

This PR introduces FuzzerPassAddLoopPreheaders, which:
- Finds existing loop headers
- If they have no simple preheader (where simple means that the
  preheader itself is not a loop header), randomly decides whether
  to add one.

Fixes KhronosGroup#3621.
  • Loading branch information
stefanomil authored Aug 14, 2020
1 parent 72ea7be commit eade36d
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 0 deletions.
2 changes: 2 additions & 0 deletions source/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ if(SPIRV_BUILD_FUZZER)
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_parameters.h
fuzzer_pass_add_relaxed_decorations.h
Expand Down Expand Up @@ -189,6 +190,7 @@ if(SPIRV_BUILD_FUZZER)
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_parameters.cpp
fuzzer_pass_add_relaxed_decorations.cpp
Expand Down
4 changes: 4 additions & 0 deletions source/fuzz/fuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#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_parameters.h"
#include "source/fuzz/fuzzer_pass_add_stores.h"
Expand Down Expand Up @@ -242,6 +243,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
MaybeAddPass<FuzzerPassAddLocalVariables>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddLoopPreheaders>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddParameters>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
Expand Down
3 changes: 3 additions & 0 deletions source/fuzz/fuzzer_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingImageSampleUnusedComponents =
{20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingLoad = {5, 50};
const std::pair<uint32_t, uint32_t> kChanceOfAddingLocalVariable = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingLoopPreheader = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
const std::pair<uint32_t, uint32_t> kChanceOfAddingNoContractionDecoration = {
5, 70};
Expand Down Expand Up @@ -165,6 +166,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
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_ =
Expand Down
4 changes: 4 additions & 0 deletions source/fuzz/fuzzer_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ class FuzzerContext {
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_;
}
Expand Down Expand Up @@ -348,6 +351,7 @@ class FuzzerContext {
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_parameters;
Expand Down
66 changes: 66 additions & 0 deletions source/fuzz/fuzzer_pass_add_loop_preheaders.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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<uint32_t> 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
43 changes: 43 additions & 0 deletions source/fuzz/fuzzer_pass_add_loop_preheaders.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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

0 comments on commit eade36d

Please sign in to comment.