1 // Copyright (c) 2020 Vasyl Teliman 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SOURCE_FUZZ_TRANSFORMATION_PROPAGATE_INSTRUCTION_UP_H_ 16 #define SOURCE_FUZZ_TRANSFORMATION_PROPAGATE_INSTRUCTION_UP_H_ 17 18 #include <map> 19 20 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" 21 #include "source/fuzz/transformation.h" 22 #include "source/fuzz/transformation_context.h" 23 #include "source/opt/ir_context.h" 24 25 namespace spvtools { 26 namespace fuzz { 27 28 class TransformationPropagateInstructionUp : public Transformation { 29 public: 30 explicit TransformationPropagateInstructionUp( 31 protobufs::TransformationPropagateInstructionUp message); 32 33 TransformationPropagateInstructionUp( 34 uint32_t block_id, 35 const std::map<uint32_t, uint32_t>& predecessor_id_to_fresh_id); 36 37 // - |block_id| must be a valid result id of some OpLabel instruction. 38 // - |block_id| must have at least one predecessor 39 // - |block_id| must contain an instruction that can be propagated using this 40 // transformation 41 // - the instruction can be propagated if: 42 // - it's not an OpPhi 43 // - it is supported by this transformation 44 // - it depends only on instructions from different basic blocks or on 45 // OpPhi instructions from the same basic block 46 // - it should be possible to insert the propagated instruction at the end of 47 // each |block_id|'s predecessor 48 // - |predecessor_id_to_fresh_id| must have an entry for at least every 49 // predecessor of |block_id| 50 // - each value in the |predecessor_id_to_fresh_id| map must be a fresh id 51 // - all fresh ids in the |predecessor_id_to_fresh_id| must be unique 52 bool IsApplicable( 53 opt::IRContext* ir_context, 54 const TransformationContext& transformation_context) const override; 55 56 // Inserts a copy of the propagated instruction into each |block_id|'s 57 // predecessor. Replaces the original instruction with an OpPhi referring 58 // inserted copies. 59 void Apply(opt::IRContext* ir_context, 60 TransformationContext* transformation_context) const override; 61 62 std::unordered_set<uint32_t> GetFreshIds() const override; 63 64 protobufs::Transformation ToMessage() const override; 65 66 // Returns true if this transformation can be applied to the block with id 67 // |block_id|. Concretely, returns true iff: 68 // - |block_id| is a valid id of some block in the module 69 // - |block_id| has predecessors 70 // - |block_id| contains an instruction that can be propagated 71 // - it is possible to insert the propagated instruction into every 72 // |block_id|'s predecessor 73 static bool IsApplicableToBlock(opt::IRContext* ir_context, 74 uint32_t block_id); 75 76 private: 77 // Returns the instruction that will be propagated into the predecessors of 78 // the |block_id|. Returns nullptr if no such an instruction exists. 79 static opt::Instruction* GetInstructionToPropagate(opt::IRContext* ir_context, 80 uint32_t block_id); 81 82 // Returns true if |opcode| is supported by this transformation. 83 static bool IsOpcodeSupported(SpvOp opcode); 84 85 protobufs::TransformationPropagateInstructionUp message_; 86 }; 87 88 } // namespace fuzz 89 } // namespace spvtools 90 91 #endif // SOURCE_FUZZ_TRANSFORMATION_PROPAGATE_INSTRUCTION_UP_H_ 92