mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-24 00:40:14 +00:00
spirv-fuzz: TransformationMoveInstructionDown (#3477)
Swaps an instruction with the next instruction in the block. Fixes #3457.
This commit is contained in:
parent
b78f4b1518
commit
92a71657fc
@ -72,6 +72,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_outline_functions.h
|
||||
fuzzer_pass_permute_blocks.h
|
||||
fuzzer_pass_permute_function_parameters.h
|
||||
fuzzer_pass_permute_instructions.h
|
||||
fuzzer_pass_permute_phi_operands.h
|
||||
fuzzer_pass_push_ids_through_variables.h
|
||||
fuzzer_pass_replace_copy_memories_with_loads_stores.h
|
||||
@ -134,6 +135,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_load.h
|
||||
transformation_merge_blocks.h
|
||||
transformation_move_block_down.h
|
||||
transformation_move_instruction_down.h
|
||||
transformation_outline_function.h
|
||||
transformation_permute_function_parameters.h
|
||||
transformation_permute_phi_operands.h
|
||||
@ -203,6 +205,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_outline_functions.cpp
|
||||
fuzzer_pass_permute_blocks.cpp
|
||||
fuzzer_pass_permute_function_parameters.cpp
|
||||
fuzzer_pass_permute_instructions.cpp
|
||||
fuzzer_pass_permute_phi_operands.cpp
|
||||
fuzzer_pass_push_ids_through_variables.cpp
|
||||
fuzzer_pass_replace_copy_memories_with_loads_stores.cpp
|
||||
@ -264,6 +267,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_load.cpp
|
||||
transformation_merge_blocks.cpp
|
||||
transformation_move_block_down.cpp
|
||||
transformation_move_instruction_down.cpp
|
||||
transformation_outline_function.cpp
|
||||
transformation_permute_function_parameters.cpp
|
||||
transformation_permute_phi_operands.cpp
|
||||
|
@ -54,6 +54,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_instructions.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"
|
||||
@ -281,6 +282,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
MaybeAddPass<FuzzerPassPermuteFunctionParameters>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassPermuteInstructions>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassPushIdsThroughVariables>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
|
@ -76,6 +76,7 @@ const std::pair<uint32_t, uint32_t> kChanceOfMergingBlocks = {20, 95};
|
||||
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> kChanceOfPermutingInstructions = {20, 70};
|
||||
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};
|
||||
@ -214,6 +215,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfObfuscatingConstant);
|
||||
chance_of_outlining_function_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfOutliningFunction);
|
||||
chance_of_permuting_instructions_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfPermutingInstructions);
|
||||
chance_of_permuting_parameters_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfPermutingParameters);
|
||||
chance_of_permuting_phi_operands_ =
|
||||
|
@ -206,6 +206,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfOutliningFunction() {
|
||||
return chance_of_outlining_function_;
|
||||
}
|
||||
uint32_t GetChanceOfPermutingInstructions() {
|
||||
return chance_of_permuting_instructions_;
|
||||
}
|
||||
uint32_t GetChanceOfPermutingParameters() {
|
||||
return chance_of_permuting_parameters_;
|
||||
}
|
||||
@ -364,6 +367,7 @@ class FuzzerContext {
|
||||
uint32_t chance_of_moving_block_down_;
|
||||
uint32_t chance_of_obfuscating_constant_;
|
||||
uint32_t chance_of_outlining_function_;
|
||||
uint32_t chance_of_permuting_instructions_;
|
||||
uint32_t chance_of_permuting_parameters_;
|
||||
uint32_t chance_of_permuting_phi_operands_;
|
||||
uint32_t chance_of_pushing_id_through_variable_;
|
||||
|
64
source/fuzz/fuzzer_pass_permute_instructions.cpp
Normal file
64
source/fuzz/fuzzer_pass_permute_instructions.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 "source/fuzz/fuzzer_pass_permute_instructions.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/transformation_move_instruction_down.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassPermuteInstructions::FuzzerPassPermuteInstructions(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
||||
transformations) {}
|
||||
|
||||
FuzzerPassPermuteInstructions::~FuzzerPassPermuteInstructions() = default;
|
||||
|
||||
void FuzzerPassPermuteInstructions::Apply() {
|
||||
// We are iterating over all instructions in all basic blocks.
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
for (auto& block : function) {
|
||||
// We need to collect all instructions in the block into a separate vector
|
||||
// since application of the transformation below might invalidate
|
||||
// iterators.
|
||||
std::vector<opt::Instruction*> instructions;
|
||||
for (auto& instruction : block) {
|
||||
instructions.push_back(&instruction);
|
||||
}
|
||||
|
||||
// We consider all instructions in reverse to increase the possible number
|
||||
// of applied transformations.
|
||||
for (auto it = instructions.rbegin(); it != instructions.rend(); ++it) {
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfPermutingInstructions())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (MaybeApplyTransformation(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(GetIRContext(), *it)))) {
|
||||
// Apply the transformation as many times as possible.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
40
source/fuzz/fuzzer_pass_permute_instructions.h
Normal file
40
source/fuzz/fuzzer_pass_permute_instructions.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_INSTRUCTIONS_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_INSTRUCTIONS_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Permutes instructions in every block of all while preserving the module's
|
||||
// semantics.
|
||||
class FuzzerPassPermuteInstructions : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassPermuteInstructions(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassPermuteInstructions() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_INSTRUCTIONS_H_
|
@ -408,6 +408,7 @@ message Transformation {
|
||||
TransformationReplaceCopyMemoryWithLoadStore replace_copy_memory_with_load_store = 61;
|
||||
TransformationReplaceLoadStoreWithCopyMemory replace_load_store_with_copy_memory = 62;
|
||||
TransformationAddLoopPreheader add_loop_preheader = 63;
|
||||
TransformationMoveInstructionDown move_instruction_down = 64;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@ -1124,6 +1125,15 @@ message TransformationMoveBlockDown {
|
||||
uint32 block_id = 1;
|
||||
}
|
||||
|
||||
message TransformationMoveInstructionDown {
|
||||
|
||||
// Swaps |instruction| with the next instruction in the block.
|
||||
|
||||
// The instruction to move down.
|
||||
InstructionDescriptor instruction = 1;
|
||||
|
||||
}
|
||||
|
||||
message TransformationOutlineFunction {
|
||||
|
||||
// A transformation that outlines a single-entry single-exit region of a
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "source/fuzz/transformation_load.h"
|
||||
#include "source/fuzz/transformation_merge_blocks.h"
|
||||
#include "source/fuzz/transformation_move_block_down.h"
|
||||
#include "source/fuzz/transformation_move_instruction_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"
|
||||
@ -194,6 +195,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
return MakeUnique<TransformationMergeBlocks>(message.merge_blocks());
|
||||
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
|
||||
return MakeUnique<TransformationMoveBlockDown>(message.move_block_down());
|
||||
case protobufs::Transformation::TransformationCase::kMoveInstructionDown:
|
||||
return MakeUnique<TransformationMoveInstructionDown>(
|
||||
message.move_instruction_down());
|
||||
case protobufs::Transformation::TransformationCase::kOutlineFunction:
|
||||
return MakeUnique<TransformationOutlineFunction>(
|
||||
message.outline_function());
|
||||
|
219
source/fuzz/transformation_move_instruction_down.cpp
Normal file
219
source/fuzz/transformation_move_instruction_down.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
// 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_move_instruction_down.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationMoveInstructionDown::TransformationMoveInstructionDown(
|
||||
const protobufs::TransformationMoveInstructionDown& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationMoveInstructionDown::TransformationMoveInstructionDown(
|
||||
const protobufs::InstructionDescriptor& instruction) {
|
||||
*message_.mutable_instruction() = instruction;
|
||||
}
|
||||
|
||||
bool TransformationMoveInstructionDown::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// |instruction| must be valid.
|
||||
auto* inst = FindInstruction(message_.instruction(), ir_context);
|
||||
if (!inst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Instruction's opcode must be supported by this transformation.
|
||||
if (!IsOpcodeSupported(inst->opcode())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* inst_block = ir_context->get_instr_block(inst);
|
||||
assert(inst_block &&
|
||||
"Global instructions and function parameters are not supported");
|
||||
|
||||
auto inst_it = fuzzerutil::GetIteratorForInstruction(inst_block, inst);
|
||||
assert(inst_it != inst_block->end() &&
|
||||
"Can't get an iterator for the instruction");
|
||||
|
||||
// |instruction| can't be the last instruction in the block.
|
||||
auto successor_it = ++inst_it;
|
||||
if (successor_it == inst_block->end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we can insert |instruction| after |inst_it|.
|
||||
auto successors_successor_it = ++inst_it;
|
||||
if (successors_successor_it == inst_block->end() ||
|
||||
!fuzzerutil::CanInsertOpcodeBeforeInstruction(inst->opcode(),
|
||||
successors_successor_it)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that |instruction|'s successor doesn't depend on the |instruction|.
|
||||
if (inst->result_id()) {
|
||||
for (uint32_t i = 0; i < successor_it->NumInOperands(); ++i) {
|
||||
const auto& operand = successor_it->GetInOperand(i);
|
||||
if (operand.type == SPV_OPERAND_TYPE_ID &&
|
||||
operand.words[0] == inst->result_id()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransformationMoveInstructionDown::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
auto* inst = FindInstruction(message_.instruction(), ir_context);
|
||||
assert(inst &&
|
||||
"The instruction should've been validated in the IsApplicable");
|
||||
|
||||
auto inst_it = fuzzerutil::GetIteratorForInstruction(
|
||||
ir_context->get_instr_block(inst), inst);
|
||||
|
||||
// Move the instruction down in the block.
|
||||
inst->InsertAfter(&*++inst_it);
|
||||
|
||||
ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationMoveInstructionDown::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_move_instruction_down() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TransformationMoveInstructionDown::IsOpcodeSupported(SpvOp opcode) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3605):
|
||||
// We only support "simple" instructions that work don't with memory.
|
||||
// We should extend this so that we support the ones that modify the memory
|
||||
// too.
|
||||
switch (opcode) {
|
||||
case SpvOpNop:
|
||||
case SpvOpUndef:
|
||||
case SpvOpAccessChain:
|
||||
case SpvOpInBoundsAccessChain:
|
||||
case SpvOpArrayLength:
|
||||
case SpvOpVectorExtractDynamic:
|
||||
case SpvOpVectorInsertDynamic:
|
||||
case SpvOpVectorShuffle:
|
||||
case SpvOpCompositeConstruct:
|
||||
case SpvOpCompositeExtract:
|
||||
case SpvOpCompositeInsert:
|
||||
case SpvOpCopyObject:
|
||||
case SpvOpTranspose:
|
||||
case SpvOpConvertFToU:
|
||||
case SpvOpConvertFToS:
|
||||
case SpvOpConvertSToF:
|
||||
case SpvOpConvertUToF:
|
||||
case SpvOpUConvert:
|
||||
case SpvOpSConvert:
|
||||
case SpvOpFConvert:
|
||||
case SpvOpQuantizeToF16:
|
||||
case SpvOpSatConvertSToU:
|
||||
case SpvOpSatConvertUToS:
|
||||
case SpvOpBitcast:
|
||||
case SpvOpSNegate:
|
||||
case SpvOpFNegate:
|
||||
case SpvOpIAdd:
|
||||
case SpvOpFAdd:
|
||||
case SpvOpISub:
|
||||
case SpvOpFSub:
|
||||
case SpvOpIMul:
|
||||
case SpvOpFMul:
|
||||
case SpvOpUDiv:
|
||||
case SpvOpSDiv:
|
||||
case SpvOpFDiv:
|
||||
case SpvOpUMod:
|
||||
case SpvOpSRem:
|
||||
case SpvOpSMod:
|
||||
case SpvOpFRem:
|
||||
case SpvOpFMod:
|
||||
case SpvOpVectorTimesScalar:
|
||||
case SpvOpMatrixTimesScalar:
|
||||
case SpvOpVectorTimesMatrix:
|
||||
case SpvOpMatrixTimesVector:
|
||||
case SpvOpMatrixTimesMatrix:
|
||||
case SpvOpOuterProduct:
|
||||
case SpvOpDot:
|
||||
case SpvOpIAddCarry:
|
||||
case SpvOpISubBorrow:
|
||||
case SpvOpUMulExtended:
|
||||
case SpvOpSMulExtended:
|
||||
case SpvOpAny:
|
||||
case SpvOpAll:
|
||||
case SpvOpIsNan:
|
||||
case SpvOpIsInf:
|
||||
case SpvOpIsFinite:
|
||||
case SpvOpIsNormal:
|
||||
case SpvOpSignBitSet:
|
||||
case SpvOpLessOrGreater:
|
||||
case SpvOpOrdered:
|
||||
case SpvOpUnordered:
|
||||
case SpvOpLogicalEqual:
|
||||
case SpvOpLogicalNotEqual:
|
||||
case SpvOpLogicalOr:
|
||||
case SpvOpLogicalAnd:
|
||||
case SpvOpLogicalNot:
|
||||
case SpvOpSelect:
|
||||
case SpvOpIEqual:
|
||||
case SpvOpINotEqual:
|
||||
case SpvOpUGreaterThan:
|
||||
case SpvOpSGreaterThan:
|
||||
case SpvOpUGreaterThanEqual:
|
||||
case SpvOpSGreaterThanEqual:
|
||||
case SpvOpULessThan:
|
||||
case SpvOpSLessThan:
|
||||
case SpvOpULessThanEqual:
|
||||
case SpvOpSLessThanEqual:
|
||||
case SpvOpFOrdEqual:
|
||||
case SpvOpFUnordEqual:
|
||||
case SpvOpFOrdNotEqual:
|
||||
case SpvOpFUnordNotEqual:
|
||||
case SpvOpFOrdLessThan:
|
||||
case SpvOpFUnordLessThan:
|
||||
case SpvOpFOrdGreaterThan:
|
||||
case SpvOpFUnordGreaterThan:
|
||||
case SpvOpFOrdLessThanEqual:
|
||||
case SpvOpFUnordLessThanEqual:
|
||||
case SpvOpFOrdGreaterThanEqual:
|
||||
case SpvOpFUnordGreaterThanEqual:
|
||||
case SpvOpShiftRightLogical:
|
||||
case SpvOpShiftRightArithmetic:
|
||||
case SpvOpShiftLeftLogical:
|
||||
case SpvOpBitwiseOr:
|
||||
case SpvOpBitwiseXor:
|
||||
case SpvOpBitwiseAnd:
|
||||
case SpvOpNot:
|
||||
case SpvOpBitFieldInsert:
|
||||
case SpvOpBitFieldSExtract:
|
||||
case SpvOpBitFieldUExtract:
|
||||
case SpvOpBitReverse:
|
||||
case SpvOpBitCount:
|
||||
case SpvOpCopyLogical:
|
||||
case SpvOpPtrEqual:
|
||||
case SpvOpPtrNotEqual:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
62
source/fuzz/transformation_move_instruction_down.h
Normal file
62
source/fuzz/transformation_move_instruction_down.h
Normal file
@ -0,0 +1,62 @@
|
||||
// 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_MOVE_INSTRUCTION_DOWN_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_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 TransformationMoveInstructionDown : public Transformation {
|
||||
public:
|
||||
explicit TransformationMoveInstructionDown(
|
||||
const protobufs::TransformationMoveInstructionDown& message);
|
||||
|
||||
explicit TransformationMoveInstructionDown(
|
||||
const protobufs::InstructionDescriptor& instruction);
|
||||
|
||||
// - |instruction| should be a descriptor of a valid instruction in the module
|
||||
// - |instruction|'s opcode should be supported by this transformation
|
||||
// - neither |instruction| nor its successor may be the last instruction in
|
||||
// the block
|
||||
// - |instruction|'s successor may not be dependent on the |instruction|
|
||||
// - it should be possible to insert |instruction|'s opcode after its
|
||||
// successor
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// Swaps |instruction| with its successor.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
// Returns true if the |opcode| is supported by this transformation (i.e.
|
||||
// we can move an instruction with this opcode).
|
||||
static bool IsOpcodeSupported(SpvOp opcode);
|
||||
|
||||
protobufs::TransformationMoveInstructionDown message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_H_
|
@ -63,6 +63,7 @@ if (${SPIRV_BUILD_FUZZER})
|
||||
transformation_load_test.cpp
|
||||
transformation_merge_blocks_test.cpp
|
||||
transformation_move_block_down_test.cpp
|
||||
transformation_move_instruction_down_test.cpp
|
||||
transformation_outline_function_test.cpp
|
||||
transformation_permute_function_parameters_test.cpp
|
||||
transformation_permute_phi_operands_test.cpp
|
||||
|
165
test/fuzz/transformation_move_instruction_down_test.cpp
Normal file
165
test/fuzz/transformation_move_instruction_down_test.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
// 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_move_instruction_down.h"
|
||||
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationMoveInstructionDownTest, 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
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpTypeBool
|
||||
%17 = OpConstantFalse %16
|
||||
%20 = OpUndef %6
|
||||
%13 = OpTypePointer Function %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%12 = OpVariable %13 Function
|
||||
%10 = OpIAdd %6 %9 %9
|
||||
%11 = OpISub %6 %9 %10
|
||||
OpStore %12 %10
|
||||
%14 = OpLoad %6 %12
|
||||
%15 = OpIMul %6 %9 %14
|
||||
OpSelectionMerge %19 None
|
||||
OpBranchConditional %17 %18 %19
|
||||
%18 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%22 = OpIAdd %6 %15 %15
|
||||
%21 = OpIAdd %6 %15 %15
|
||||
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);
|
||||
|
||||
// Instruction descriptor is invalid.
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(30, SpvOpNop, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Opcode is not supported.
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(5, SpvOpLabel, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(12, SpvOpVariable, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(11, SpvOpStore, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(14, SpvOpLoad, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Can't move the last instruction in the block.
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(15, SpvOpBranchConditional, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Can't move the instruction if the next instruction is the last one in the
|
||||
// block.
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(21, SpvOpIAdd, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Can't insert instruction's opcode after its successor.
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(15, SpvOpIMul, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Instruction's successor depends on the instruction.
|
||||
ASSERT_FALSE(TransformationMoveInstructionDown(
|
||||
MakeInstructionDescriptor(10, SpvOpIAdd, 0))
|
||||
.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
{
|
||||
TransformationMoveInstructionDown transformation(
|
||||
MakeInstructionDescriptor(11, SpvOpISub, 0));
|
||||
ASSERT_TRUE(
|
||||
transformation.IsApplicable(context.get(), transformation_context));
|
||||
transformation.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
}
|
||||
{
|
||||
TransformationMoveInstructionDown transformation(
|
||||
MakeInstructionDescriptor(22, SpvOpIAdd, 0));
|
||||
ASSERT_TRUE(
|
||||
transformation.IsApplicable(context.get(), transformation_context));
|
||||
transformation.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
}
|
||||
|
||||
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
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpTypeBool
|
||||
%17 = OpConstantFalse %16
|
||||
%20 = OpUndef %6
|
||||
%13 = OpTypePointer Function %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%12 = OpVariable %13 Function
|
||||
%10 = OpIAdd %6 %9 %9
|
||||
OpStore %12 %10
|
||||
%11 = OpISub %6 %9 %10
|
||||
%14 = OpLoad %6 %12
|
||||
%15 = OpIMul %6 %9 %14
|
||||
OpSelectionMerge %19 None
|
||||
OpBranchConditional %17 %18 %19
|
||||
%18 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%21 = OpIAdd %6 %15 %15
|
||||
%22 = OpIAdd %6 %15 %15
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
Loading…
Reference in New Issue
Block a user