spirv-fuzz: Fuzzer pass to randomly apply loop preheaders (#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 #3621.
This commit is contained in:
Stefano Milizia 2020-08-14 13:44:28 +02:00 committed by GitHub
parent 72ea7bec4a
commit eade36db22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 122 additions and 0 deletions

View File

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

View File

@ -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"
@ -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);

View File

@ -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};
@ -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_ =

View File

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

View File

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

View File

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