SPIRV-Tools/source/fuzz/transformation_propagate_instruction_up.h
Vasyl Teliman b7056e7e03
spirv-fuzz: FuzzerPassPropagateInstructionsUp (#3478)
Given an instruction (that may use an OpPhi result from the same block as an input operand), try to clone the instruction into each predecessor block, replacing the input operand with the corresponding OpPhi input operand in each case, if necessary.

Fixes #3458.
2020-08-11 10:24:32 +01:00

90 lines
3.6 KiB
C++

// 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_PROPAGATE_INSTRUCTION_UP_H_
#define SOURCE_FUZZ_TRANSFORMATION_PROPAGATE_INSTRUCTION_UP_H_
#include <map>
#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 TransformationPropagateInstructionUp : public Transformation {
public:
explicit TransformationPropagateInstructionUp(
const protobufs::TransformationPropagateInstructionUp& message);
TransformationPropagateInstructionUp(
uint32_t block_id,
const std::map<uint32_t, uint32_t>& predecessor_id_to_fresh_id);
// - |block_id| must be a valid result id of some OpLabel instruction.
// - |block_id| must have at least one predecessor
// - |block_id| must contain an instruction that can be propagated using this
// transformation
// - the instruction can be propagated if:
// - it's not an OpPhi
// - it is supported by this transformation
// - it depends only on instructions from different basic blocks or on
// OpPhi instructions from the same basic block
// - it should be possible to insert the propagated instruction at the end of
// each |block_id|'s predecessor
// - |predecessor_id_to_fresh_id| must have an entry for at least every
// predecessor of |block_id|
// - each value in the |predecessor_id_to_fresh_id| map must be a fresh id
// - all fresh ids in the |predecessor_id_to_fresh_id| must be unique
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Inserts a copy of the propagated instruction into each |block_id|'s
// predecessor. Replaces the original instruction with an OpPhi referring
// inserted copies.
void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override;
// Returns true if this transformation can be applied to the block with id
// |block_id|. Concretely, returns true iff:
// - |block_id| is a valid id of some block in the module
// - |block_id| has predecessors
// - |block_id| contains an instruction that can be propagated
// - it is possible to insert the propagated instruction into every
// |block_id|'s predecessor
static bool IsApplicableToBlock(opt::IRContext* ir_context,
uint32_t block_id);
private:
// Returns the instruction that will be propagated into the predecessors of
// the |block_id|. Returns nullptr if no such an instruction exists.
static opt::Instruction* GetInstructionToPropagate(opt::IRContext* ir_context,
uint32_t block_id);
// Returns true if |opcode| is supported by this transformation.
static bool IsOpcodeSupported(SpvOp opcode);
protobufs::TransformationPropagateInstructionUp message_;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_TRANSFORMATION_PROPAGATE_INSTRUCTION_UP_H_