mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
parent
36b5bb701d
commit
8e586e46a2
@ -64,6 +64,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_outline_functions.h
|
||||
fuzzer_pass_permute_blocks.h
|
||||
fuzzer_pass_permute_function_parameters.h
|
||||
fuzzer_pass_permute_phi_operands.h
|
||||
fuzzer_pass_push_ids_through_variables.h
|
||||
fuzzer_pass_replace_linear_algebra_instructions.h
|
||||
fuzzer_pass_split_blocks.h
|
||||
@ -116,6 +117,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_move_block_down.h
|
||||
transformation_outline_function.h
|
||||
transformation_permute_function_parameters.h
|
||||
transformation_permute_phi_operands.h
|
||||
transformation_push_id_through_variable.h
|
||||
transformation_replace_boolean_constant_with_constant_binary.h
|
||||
transformation_replace_constant_with_uniform.h
|
||||
@ -168,6 +170,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_outline_functions.cpp
|
||||
fuzzer_pass_permute_blocks.cpp
|
||||
fuzzer_pass_permute_function_parameters.cpp
|
||||
fuzzer_pass_permute_phi_operands.cpp
|
||||
fuzzer_pass_push_ids_through_variables.cpp
|
||||
fuzzer_pass_replace_linear_algebra_instructions.cpp
|
||||
fuzzer_pass_split_blocks.cpp
|
||||
@ -219,6 +222,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_move_block_down.cpp
|
||||
transformation_outline_function.cpp
|
||||
transformation_permute_function_parameters.cpp
|
||||
transformation_permute_phi_operands.cpp
|
||||
transformation_push_id_through_variable.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary.cpp
|
||||
transformation_replace_constant_with_uniform.cpp
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "source/fuzz/fuzzer_pass_outline_functions.h"
|
||||
#include "source/fuzz/fuzzer_pass_permute_blocks.h"
|
||||
#include "source/fuzz/fuzzer_pass_permute_function_parameters.h"
|
||||
#include "source/fuzz/fuzzer_pass_permute_phi_operands.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"
|
||||
@ -305,6 +306,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
MaybeAddPass<FuzzerPassAddNoContractionDecorations>(
|
||||
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassPermutePhiOperands>(
|
||||
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassSwapCommutableOperands>(
|
||||
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
|
@ -63,6 +63,7 @@ const std::pair<uint32_t, uint32_t> kChanceOfMovingBlockDown = {20, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfObfuscatingConstant = {10, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfOutliningFunction = {10, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfPermutingParameters = {30, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfPermutingPhiOperands = {30, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfPushingIdThroughVariable = {5, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
|
||||
const std::pair<uint32_t, uint32_t>
|
||||
@ -165,6 +166,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfOutliningFunction);
|
||||
chance_of_permuting_parameters_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfPermutingParameters);
|
||||
chance_of_permuting_phi_operands_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfPermutingPhiOperands);
|
||||
chance_of_pushing_id_through_variable_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfPushingIdThroughVariable);
|
||||
chance_of_replacing_id_with_synonym_ =
|
||||
|
@ -185,6 +185,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfPermutingParameters() {
|
||||
return chance_of_permuting_parameters_;
|
||||
}
|
||||
uint32_t GetChanceOfPermutingPhiOperands() {
|
||||
return chance_of_permuting_phi_operands_;
|
||||
}
|
||||
uint32_t GetChanceOfPushingIdThroughVariable() {
|
||||
return chance_of_pushing_id_through_variable_;
|
||||
}
|
||||
@ -290,6 +293,7 @@ class FuzzerContext {
|
||||
uint32_t chance_of_obfuscating_constant_;
|
||||
uint32_t chance_of_outlining_function_;
|
||||
uint32_t chance_of_permuting_parameters_;
|
||||
uint32_t chance_of_permuting_phi_operands_;
|
||||
uint32_t chance_of_pushing_id_through_variable_;
|
||||
uint32_t chance_of_replacing_id_with_synonym_;
|
||||
uint32_t chance_of_replacing_linear_algebra_instructions_;
|
||||
|
64
source/fuzz/fuzzer_pass_permute_phi_operands.cpp
Normal file
64
source/fuzz/fuzzer_pass_permute_phi_operands.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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 <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_pass_permute_phi_operands.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/transformation_permute_phi_operands.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassPermutePhiOperands::FuzzerPassPermutePhiOperands(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
||||
transformations) {}
|
||||
|
||||
FuzzerPassPermutePhiOperands::~FuzzerPassPermutePhiOperands() = default;
|
||||
|
||||
void FuzzerPassPermutePhiOperands::Apply() {
|
||||
ForEachInstructionWithInstructionDescriptor(
|
||||
[this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/,
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& /*unused*/) {
|
||||
const auto& inst = *inst_it;
|
||||
|
||||
if (inst.opcode() != SpvOpPhi) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfPermutingPhiOperands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a vector of indices for each pair of operands in the |inst|.
|
||||
// OpPhi always has an even number of operands.
|
||||
std::vector<uint32_t> permutation(inst.NumInOperands() / 2);
|
||||
std::iota(permutation.begin(), permutation.end(), 0);
|
||||
GetFuzzerContext()->Shuffle(&permutation);
|
||||
|
||||
ApplyTransformation(TransformationPermutePhiOperands(
|
||||
inst.result_id(), std::move(permutation)));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
40
source/fuzz/fuzzer_pass_permute_phi_operands.h
Normal file
40
source/fuzz/fuzzer_pass_permute_phi_operands.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_PERMUTE_PHI_OPERANDS_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_PHI_OPERANDS_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Iterates over all instructions in the module and randomly decides for each
|
||||
// OpPhi instruction whether to permute its operands.
|
||||
class FuzzerPassPermutePhiOperands : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassPermutePhiOperands(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassPermutePhiOperands() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_PHI_OPERANDS_H_
|
@ -12,6 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
#include "source/opt/build_module.h"
|
||||
@ -652,6 +655,26 @@ void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
{SPV_OPERAND_TYPE_ID, {initializer_id}}}));
|
||||
}
|
||||
|
||||
bool HasDuplicates(const std::vector<uint32_t>& arr) {
|
||||
return std::unordered_set<uint32_t>(arr.begin(), arr.end()).size() !=
|
||||
arr.size();
|
||||
}
|
||||
|
||||
bool IsPermutationOfRange(const std::vector<uint32_t>& arr, uint32_t lo,
|
||||
uint32_t hi) {
|
||||
if (arr.empty()) {
|
||||
return lo > hi;
|
||||
}
|
||||
|
||||
if (HasDuplicates(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto min_max = std::minmax_element(arr.begin(), arr.end());
|
||||
return arr.size() == hi - lo + 1 && *min_max.first == lo &&
|
||||
*min_max.second == hi;
|
||||
}
|
||||
|
||||
} // namespace fuzzerutil
|
||||
|
||||
} // namespace fuzz
|
||||
|
@ -252,6 +252,15 @@ void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
uint32_t type_id, uint32_t function_id,
|
||||
uint32_t initializer_id);
|
||||
|
||||
// Returns true if the vector |arr| has duplicates.
|
||||
bool HasDuplicates(const std::vector<uint32_t>& arr);
|
||||
|
||||
// Checks that the given vector |arr| contains a permutation of a range
|
||||
// [lo, hi]. That being said, all elements in the range are present without
|
||||
// duplicates. If |arr| is empty, returns true iff |lo > hi|.
|
||||
bool IsPermutationOfRange(const std::vector<uint32_t>& arr, uint32_t lo,
|
||||
uint32_t hi);
|
||||
|
||||
} // namespace fuzzerutil
|
||||
|
||||
} // namespace fuzz
|
||||
|
@ -379,6 +379,7 @@ message Transformation {
|
||||
TransformationAddSpecConstantOp add_spec_constant_op = 48;
|
||||
TransformationReplaceLinearAlgebraInstruction replace_linear_algebra_instruction = 49;
|
||||
TransformationSwapConditionalBranchOperands swap_conditional_branch_operands = 50;
|
||||
TransformationPermutePhiOperands permute_phi_operands = 51;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@ -1005,6 +1006,19 @@ message TransformationPermuteFunctionParameters {
|
||||
|
||||
}
|
||||
|
||||
message TransformationPermutePhiOperands {
|
||||
|
||||
// Permutes operands of some OpPhi instruction.
|
||||
|
||||
// Result id of the instruction to apply the transformation to.
|
||||
uint32 result_id = 1;
|
||||
|
||||
// A sequence of numbers in the range [0, n/2 - 1] where |n| is the number
|
||||
// of operands of the OpPhi instruction with |result_id|.
|
||||
repeated uint32 permutation = 2;
|
||||
|
||||
}
|
||||
|
||||
message TransformationPushIdThroughVariable {
|
||||
|
||||
// A transformation that makes |value_synonym_id| and |value_id| to be
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "source/fuzz/transformation_move_block_down.h"
|
||||
#include "source/fuzz/transformation_outline_function.h"
|
||||
#include "source/fuzz/transformation_permute_function_parameters.h"
|
||||
#include "source/fuzz/transformation_permute_phi_operands.h"
|
||||
#include "source/fuzz/transformation_push_id_through_variable.h"
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
@ -170,6 +171,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
kPermuteFunctionParameters:
|
||||
return MakeUnique<TransformationPermuteFunctionParameters>(
|
||||
message.permute_function_parameters());
|
||||
case protobufs::Transformation::TransformationCase::kPermutePhiOperands:
|
||||
return MakeUnique<TransformationPermutePhiOperands>(
|
||||
message.permute_phi_operands());
|
||||
case protobufs::Transformation::TransformationCase::kPushIdThroughVariable:
|
||||
return MakeUnique<TransformationPushIdThroughVariable>(
|
||||
message.push_id_through_variable());
|
||||
|
@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
@ -53,7 +52,8 @@ bool TransformationPermuteFunctionParameters::IsApplicable(
|
||||
const auto* function_type = fuzzerutil::GetFunctionType(ir_context, function);
|
||||
assert(function_type && "Function type is null");
|
||||
|
||||
const auto& permutation = message_.permutation();
|
||||
std::vector<uint32_t> permutation(message_.permutation().begin(),
|
||||
message_.permutation().end());
|
||||
|
||||
// Don't take return type into account
|
||||
auto arg_size = function_type->NumInOperands() - 1;
|
||||
@ -63,21 +63,20 @@ bool TransformationPermuteFunctionParameters::IsApplicable(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that all indices are valid
|
||||
// and unique integers from the [0, n-1] set
|
||||
std::unordered_set<uint32_t> unique_indices;
|
||||
for (auto index : permutation) {
|
||||
// We don't compare |index| with 0 since it's an unsigned integer
|
||||
if (index >= arg_size) {
|
||||
return false;
|
||||
}
|
||||
// Check that permutation doesn't have duplicated values.
|
||||
assert(!fuzzerutil::HasDuplicates(permutation) &&
|
||||
"Permutation has duplicates");
|
||||
|
||||
unique_indices.insert(index);
|
||||
// Check that elements in permutation are in range [0, arg_size - 1].
|
||||
//
|
||||
// We must check whether the permutation is empty first because in that case
|
||||
// |arg_size - 1| will produce |std::numeric_limits<uint32_t>::max()| since
|
||||
// it's an unsigned integer.
|
||||
if (!permutation.empty() &&
|
||||
!fuzzerutil::IsPermutationOfRange(permutation, 0, arg_size - 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that permutation doesn't have duplicated values
|
||||
assert(unique_indices.size() == arg_size && "Permutation has duplicates");
|
||||
|
||||
// Check that new function's type is valid:
|
||||
// - Has the same number of operands
|
||||
// - Has the same result type as the old one
|
||||
|
94
source/fuzz/transformation_permute_phi_operands.cpp
Normal file
94
source/fuzz/transformation_permute_phi_operands.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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 <vector>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/transformation_permute_phi_operands.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationPermutePhiOperands::TransformationPermutePhiOperands(
|
||||
const spvtools::fuzz::protobufs::TransformationPermutePhiOperands& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationPermutePhiOperands::TransformationPermutePhiOperands(
|
||||
uint32_t result_id, const std::vector<uint32_t>& permutation) {
|
||||
message_.set_result_id(result_id);
|
||||
|
||||
for (auto index : permutation) {
|
||||
message_.add_permutation(index);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransformationPermutePhiOperands::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// Check that |message_.result_id| is valid.
|
||||
const auto* inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.result_id());
|
||||
if (!inst || inst->opcode() != SpvOpPhi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that |message_.permutation| has expected size.
|
||||
auto expected_permutation_size = inst->NumInOperands() / 2;
|
||||
if (static_cast<uint32_t>(message_.permutation().size()) !=
|
||||
expected_permutation_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that |message_.permutation| has elements in range
|
||||
// [0, expected_permutation_size - 1].
|
||||
std::vector<uint32_t> permutation(message_.permutation().begin(),
|
||||
message_.permutation().end());
|
||||
assert(!fuzzerutil::HasDuplicates(permutation) &&
|
||||
"Permutation has duplicates");
|
||||
|
||||
// We must check whether the permutation is empty first because in that case
|
||||
// |expected_permutation_size - 1| will produce
|
||||
// |std::numeric_limits<uint32_t>::max()| since it's an unsigned integer.
|
||||
return permutation.empty() ||
|
||||
fuzzerutil::IsPermutationOfRange(permutation, 0,
|
||||
expected_permutation_size - 1);
|
||||
}
|
||||
|
||||
void TransformationPermutePhiOperands::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.result_id());
|
||||
assert(inst);
|
||||
|
||||
opt::Instruction::OperandList permuted_operands;
|
||||
permuted_operands.reserve(inst->NumInOperands());
|
||||
|
||||
for (auto index : message_.permutation()) {
|
||||
permuted_operands.push_back(std::move(inst->GetInOperand(2 * index)));
|
||||
permuted_operands.push_back(std::move(inst->GetInOperand(2 * index + 1)));
|
||||
}
|
||||
|
||||
inst->SetInOperands(std::move(permuted_operands));
|
||||
|
||||
// Make sure our changes are analyzed
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationPermutePhiOperands::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_permute_phi_operands() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
56
source/fuzz/transformation_permute_phi_operands.h
Normal file
56
source/fuzz/transformation_permute_phi_operands.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_PERMUTE_PHI_OPERANDS_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_PERMUTE_PHI_OPERANDS_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 TransformationPermutePhiOperands : public Transformation {
|
||||
public:
|
||||
explicit TransformationPermutePhiOperands(
|
||||
const protobufs::TransformationPermutePhiOperands& message);
|
||||
|
||||
TransformationPermutePhiOperands(uint32_t result_id,
|
||||
const std::vector<uint32_t>& permutation);
|
||||
|
||||
// - |result_id| must be a valid id of some OpPhi instruction in the module.
|
||||
// - |permutation| must contain elements in the range [0, n/2 - 1] where |n|
|
||||
// is a number of operands to the instruction with |result_id|. All elements
|
||||
// must be unique (i.e. |permutation.size() == n / 2|).
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// Permutes operands of the OpPhi instruction with |result_id| according to
|
||||
// the elements in |permutation|.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationPermutePhiOperands message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_PERMUTE_PHI_OPERANDS_H_
|
@ -58,6 +58,7 @@ if (${SPIRV_BUILD_FUZZER})
|
||||
transformation_move_block_down_test.cpp
|
||||
transformation_outline_function_test.cpp
|
||||
transformation_permute_function_parameters_test.cpp
|
||||
transformation_permute_phi_operands_test.cpp
|
||||
transformation_push_id_through_variable_test.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
||||
transformation_replace_constant_with_uniform_test.cpp
|
||||
|
@ -220,10 +220,17 @@ TEST(TransformationPermuteFunctionParametersTest, BasicTest) {
|
||||
ASSERT_FALSE(TransformationPermuteFunctionParameters(22, 0, {0, 1})
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Permutation has invalid values
|
||||
// Permutation has invalid values 1
|
||||
ASSERT_FALSE(TransformationPermuteFunctionParameters(22, 0, {3, 1, 0})
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Permutation has invalid values 2
|
||||
ASSERT_DEATH(TransformationPermuteFunctionParameters(22, 0, {2, 2, 1})
|
||||
.IsApplicable(context.get(), transformation_context),
|
||||
"Permutation has duplicates");
|
||||
#endif
|
||||
|
||||
// Type id is not an OpTypeFunction instruction
|
||||
ASSERT_FALSE(TransformationPermuteFunctionParameters(22, 42, {2, 1, 0})
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
154
test/fuzz/transformation_permute_phi_operands_test.cpp
Normal file
154
test/fuzz/transformation_permute_phi_operands_test.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_permute_phi_operands.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationPermutePhiOperandsTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%11 = OpConstant %6 1
|
||||
%14 = OpTypeBool
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
%12 = OpLoad %6 %8
|
||||
%13 = OpLoad %6 %10
|
||||
%15 = OpSLessThan %14 %12 %13
|
||||
OpSelectionMerge %17 None
|
||||
OpBranchConditional %15 %16 %21
|
||||
%16 = OpLabel
|
||||
%18 = OpLoad %6 %10
|
||||
%19 = OpLoad %6 %8
|
||||
%20 = OpIAdd %6 %19 %18
|
||||
OpBranch %17
|
||||
%21 = OpLabel
|
||||
%22 = OpLoad %6 %10
|
||||
%23 = OpLoad %6 %8
|
||||
%24 = OpISub %6 %23 %22
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%25 = OpPhi %6 %20 %16 %24 %21
|
||||
OpStore %8 %25
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
spvtools::ValidatorOptions validator_options;
|
||||
TransformationContext transformation_context(&fact_manager,
|
||||
validator_options);
|
||||
|
||||
// Result id is invalid.
|
||||
ASSERT_FALSE(TransformationPermutePhiOperands(26, {}).IsApplicable(
|
||||
context.get(), transformation_context));
|
||||
|
||||
// Result id is not of an OpPhi instruction.
|
||||
ASSERT_FALSE(TransformationPermutePhiOperands(24, {}).IsApplicable(
|
||||
context.get(), transformation_context));
|
||||
|
||||
// Result id is not of an OpPhi instruction.
|
||||
ASSERT_FALSE(TransformationPermutePhiOperands(24, {}).IsApplicable(
|
||||
context.get(), transformation_context));
|
||||
|
||||
// Permutation has invalid size.
|
||||
ASSERT_FALSE(TransformationPermutePhiOperands(25, {0, 1, 2})
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Permutation has duplicates.
|
||||
ASSERT_DEATH(TransformationPermutePhiOperands(25, {0, 0})
|
||||
.IsApplicable(context.get(), transformation_context),
|
||||
"Permutation has duplicates");
|
||||
#endif
|
||||
|
||||
// Permutation's values are not in range.
|
||||
ASSERT_FALSE(TransformationPermutePhiOperands(25, {1, 2})
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
TransformationPermutePhiOperands transformation(25, {1, 0});
|
||||
ASSERT_TRUE(
|
||||
transformation.IsApplicable(context.get(), transformation_context));
|
||||
transformation.Apply(context.get(), &transformation_context);
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%11 = OpConstant %6 1
|
||||
%14 = OpTypeBool
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
%12 = OpLoad %6 %8
|
||||
%13 = OpLoad %6 %10
|
||||
%15 = OpSLessThan %14 %12 %13
|
||||
OpSelectionMerge %17 None
|
||||
OpBranchConditional %15 %16 %21
|
||||
%16 = OpLabel
|
||||
%18 = OpLoad %6 %10
|
||||
%19 = OpLoad %6 %8
|
||||
%20 = OpIAdd %6 %19 %18
|
||||
OpBranch %17
|
||||
%21 = OpLabel
|
||||
%22 = OpLoad %6 %10
|
||||
%23 = OpLoad %6 %8
|
||||
%24 = OpISub %6 %23 %22
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%25 = OpPhi %6 %24 %21 %20 %16
|
||||
OpStore %8 %25
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
Loading…
Reference in New Issue
Block a user