135 lines
4.8 KiB
C++
135 lines
4.8 KiB
C++
// Copyright 2021 The Tint Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT 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 FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_REDUCE_MUTATOR_H_
|
|
#define FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_REDUCE_MUTATOR_H_
|
|
|
|
#include <memory>
|
|
#include <random>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "fuzzers/tint_spirv_tools_fuzzer/mutator.h"
|
|
|
|
#include "source/reduce/reduction_opportunity_finder.h"
|
|
|
|
namespace tint {
|
|
namespace fuzzers {
|
|
namespace spvtools_fuzzer {
|
|
|
|
/// Mutates SPIR-V binary by running spirv-reduce tool.
|
|
///
|
|
/// The initial `binary` must be valid according to `target_env`. Applies at
|
|
/// most `reductions_batch_size` reductions at a time. This parameter is ignored
|
|
/// if its value is 0. Uses a random subset of reduction opportunity finders by
|
|
/// default. This can be overridden with the `enable_all_reductions` parameter.
|
|
class SpirvReduceMutator : public Mutator {
|
|
public:
|
|
/// Constructor.
|
|
/// @param target_env - the target environment for the `binary`.
|
|
/// @param binary - SPIR-V binary. Must be valid.
|
|
/// @param seed - the seed for the RNG.
|
|
/// @param reductions_batch_size - the number of reduction passes that will be
|
|
/// applied during a single call to `Mutate`. If it's equal to 0 then we
|
|
/// apply the passes until we reach the threshold for the total number of
|
|
/// applied passes.
|
|
/// @param enable_all_reductions - whether to use all reduction passes or only
|
|
/// a randomly selected subset of them.
|
|
/// @param validate_after_each_reduction - whether to validate after each
|
|
/// applied reduction.
|
|
SpirvReduceMutator(spv_target_env target_env,
|
|
std::vector<uint32_t> binary,
|
|
uint32_t seed,
|
|
uint32_t reductions_batch_size,
|
|
bool enable_all_reductions,
|
|
bool validate_after_each_reduction);
|
|
|
|
Result Mutate() override;
|
|
std::vector<uint32_t> GetBinary() const override;
|
|
void LogErrors(const std::string* path, uint32_t count) const override;
|
|
std::string GetErrors() const override;
|
|
|
|
private:
|
|
template <typename T, typename... Args>
|
|
void MaybeAddFinder(Args&&... args) {
|
|
if (enable_all_reductions_ || std::uniform_int_distribution<>(0, 1)(rng_)) {
|
|
finders_.push_back(std::make_unique<T>(std::forward<Args>(args)...));
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
T* GetRandomElement(std::vector<T>* arr) {
|
|
assert(!arr->empty() && "Can't get random element from an empty vector");
|
|
auto index =
|
|
std::uniform_int_distribution<size_t>(0, arr->size() - 1)(rng_);
|
|
return &(*arr)[index];
|
|
}
|
|
|
|
template <typename T>
|
|
T* GetRandomElement(std::vector<std::unique_ptr<T>>* arr) {
|
|
assert(!arr->empty() && "Can't get random element from an empty vector");
|
|
auto index =
|
|
std::uniform_int_distribution<size_t>(0, arr->size() - 1)(rng_);
|
|
return (*arr)[index].get();
|
|
}
|
|
|
|
bool ApplyReduction(
|
|
spvtools::reduce::ReductionOpportunity* reduction_opportunity);
|
|
|
|
// The SPIR-V binary that is being reduced.
|
|
std::unique_ptr<spvtools::opt::IRContext> ir_context_;
|
|
|
|
// The selected subset of reduction opportunity finders.
|
|
std::vector<std::unique_ptr<spvtools::reduce::ReductionOpportunityFinder>>
|
|
finders_;
|
|
|
|
// Random number generator initialized with `seed_`.
|
|
std::mt19937 rng_;
|
|
|
|
// All the errors produced by the reducer.
|
|
std::stringstream errors_;
|
|
|
|
// Whether the last call to the `Mutate` method produced the valid binary.
|
|
bool is_valid_;
|
|
|
|
// The number of reductions to apply on a single call to `Mutate`.
|
|
const uint32_t reductions_batch_size_;
|
|
|
|
// The total number of applied reductions.
|
|
uint32_t total_applied_reductions_;
|
|
|
|
// Whether we want to use all the reduction opportunity finders and not just a
|
|
// subset of them.
|
|
const bool enable_all_reductions_;
|
|
|
|
// Whether we want to validate all the binary after each reduction.
|
|
const bool validate_after_each_reduction_;
|
|
|
|
// The original binary that was used to initialize this mutator.
|
|
// Useful for debugging.
|
|
const std::vector<uint32_t> original_binary_;
|
|
|
|
// The seed that was used to initialize the random number generator.
|
|
// Useful for debugging.
|
|
const uint32_t seed_;
|
|
};
|
|
|
|
} // namespace spvtools_fuzzer
|
|
} // namespace fuzzers
|
|
} // namespace tint
|
|
|
|
#endif // FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_REDUCE_MUTATOR_H_
|