| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- // Copyright (c) 2020 Google LLC
- //
- // 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_FLATTEN_CONDITIONAL_BRANCH_H_
- #define SOURCE_FUZZ_TRANSFORMATION_FLATTEN_CONDITIONAL_BRANCH_H_
- #include "source/fuzz/transformation.h"
- namespace spvtools {
- namespace fuzz {
- class TransformationFlattenConditionalBranch : public Transformation {
- public:
- explicit TransformationFlattenConditionalBranch(
- protobufs::TransformationFlattenConditionalBranch message);
- TransformationFlattenConditionalBranch(
- uint32_t header_block_id, bool true_branch_first,
- uint32_t fresh_id_for_bvec2_selector,
- uint32_t fresh_id_for_bvec3_selector,
- uint32_t fresh_id_for_bvec4_selector,
- const std::vector<protobufs::SideEffectWrapperInfo>&
- side_effect_wrappers_info);
- // - |message_.header_block_id| must be the label id of a reachable selection
- // header, which ends with an OpBranchConditional instruction.
- // - The condition of the OpBranchConditional instruction must not be an
- // irrelevant id.
- // - The header block and the merge block must describe a single-entry,
- // single-exit region.
- // - The region must not contain barrier or OpSampledImage instructions.
- // - The region must not contain selection or loop constructs.
- // - The region must not define ids that are the base objects for existing
- // synonym facts.
- // - For each instruction that requires additional fresh ids, then:
- // - if the instruction is mapped to the required ids for enclosing it by
- // |message_.side_effect_wrapper_info|, these must be valid (the
- // fresh ids must be non-zero, fresh and distinct);
- // - if there is no such mapping, the transformation context must have
- // overflow ids available.
- bool IsApplicable(
- opt::IRContext* ir_context,
- const TransformationContext& transformation_context) const override;
- // Flattens the selection construct with header |message_.header_block_id|,
- // changing any OpPhi in the block where the flow converges to OpSelect and
- // enclosing any instruction with side effects in conditionals so that
- // they are only executed when they should.
- void Apply(opt::IRContext* ir_context,
- TransformationContext* transformation_context) const override;
- std::unordered_set<uint32_t> GetFreshIds() const override;
- protobufs::Transformation ToMessage() const override;
- // Returns true if the conditional headed by |header| can be flattened,
- // according to the conditions of the IsApplicable method, assuming that
- // enough fresh ids would be provided. In this case, it fills the
- // |instructions_that_need_ids| set with all the instructions that would
- // require fresh ids.
- // Returns false otherwise.
- // Assumes that |header| is the header of a conditional, so its last two
- // instructions are OpSelectionMerge and OpBranchConditional.
- static bool GetProblematicInstructionsIfConditionalCanBeFlattened(
- opt::IRContext* ir_context, opt::BasicBlock* header,
- const TransformationContext& transformation_context,
- std::set<opt::Instruction*>* instructions_that_need_ids);
- // Returns true iff the given instruction needs a placeholder to be enclosed
- // inside a conditional. So, it returns:
- // - true if the instruction has a non-void result id,
- // - false if the instruction does not have a result id or has a void result
- // id.
- // Assumes that the instruction has side effects, requiring it to be enclosed
- // inside a conditional, and that it can be enclosed inside a conditional
- // keeping the module valid. Assumes that, if the instruction has a void
- // result type, its result id is not used in the module.
- static bool InstructionNeedsPlaceholder(opt::IRContext* ir_context,
- const opt::Instruction& instruction);
- // Returns true if and only if the SPIR-V version is such that the arguments
- // to OpSelect are restricted to only scalars, pointers (if the appropriate
- // capability is enabled) and component-wise vectors.
- static bool OpSelectArgumentsAreRestricted(opt::IRContext* ir_context);
- // Find the first block where flow converges (it is not necessarily the merge
- // block) by walking the true branch until reaching a block that post-
- // dominates the header.
- // This is necessary because a potential common set of blocks at the end of
- // the construct should not be duplicated.
- static uint32_t FindConvergenceBlock(opt::IRContext* ir_context,
- const opt::BasicBlock& header_block);
- private:
- // Returns an unordered_map mapping instructions to the info required to
- // enclose them inside a conditional. It maps the instructions to the
- // corresponding entry in |message_.side_effect_wrapper_info|.
- std::unordered_map<opt::Instruction*, protobufs::SideEffectWrapperInfo>
- GetInstructionsToWrapperInfo(opt::IRContext* ir_context) const;
- // Splits the given block, adding a new selection construct so that the given
- // instruction is only executed if the boolean value of |condition_id| matches
- // the value of |exec_if_cond_true|.
- // Assumes that all parameters are consistent.
- // 2 fresh ids are required if the instruction does not have a result id (the
- // first two ids in |wrapper_info| must be valid fresh ids), 5 otherwise.
- // Returns the merge block created.
- //
- // |dead_blocks| and |irrelevant_ids| are used to record the ids of blocks
- // and instructions for which dead block and irrelevant id facts should
- // ultimately be created.
- static opt::BasicBlock* EncloseInstructionInConditional(
- opt::IRContext* ir_context,
- const TransformationContext& transformation_context,
- opt::BasicBlock* block, opt::Instruction* instruction,
- const protobufs::SideEffectWrapperInfo& wrapper_info,
- uint32_t condition_id, bool exec_if_cond_true,
- std::vector<uint32_t>* dead_blocks,
- std::vector<uint32_t>* irrelevant_ids);
- // Turns every OpPhi instruction of |convergence_block| -- the convergence
- // block for |header_block| (both in |ir_context|) into an OpSelect
- // instruction.
- void RewriteOpPhiInstructionsAtConvergenceBlock(
- const opt::BasicBlock& header_block, uint32_t convergence_block_id,
- opt::IRContext* ir_context) const;
- // Adds an OpCompositeExtract instruction to the start of |block| in
- // |ir_context|, with result id given by |fresh_id|. The instruction will
- // make a |dimension|-dimensional boolean vector with
- // |branch_condition_operand| at every component.
- static void AddBooleanVectorConstructorToBlock(
- uint32_t fresh_id, uint32_t dimension,
- const opt::Operand& branch_condition_operand, opt::IRContext* ir_context,
- opt::BasicBlock* block);
- // Returns true if the given instruction either has no side effects or it can
- // be handled by being enclosed in a conditional.
- static bool InstructionCanBeHandled(opt::IRContext* ir_context,
- const opt::Instruction& instruction);
- protobufs::TransformationFlattenConditionalBranch message_;
- };
- } // namespace fuzz
- } // namespace spvtools
- #endif // SOURCE_FUZZ_TRANSFORMATION_FLATTEN_CONDITIONAL_BRANCH_H_
|