// Copyright (c) 2015-2016 The Khronos Group Inc. // // 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_VAL_BASIC_BLOCK_H_ #define SOURCE_VAL_BASIC_BLOCK_H_ #include <cstdint> #include <bitset> #include <functional> #include <memory> #include <vector> #include "source/latest_version_spirv_header.h" namespace spvtools { namespace val { enum BlockType : uint32_t { kBlockTypeUndefined, kBlockTypeHeader, kBlockTypeLoop, kBlockTypeMerge, kBlockTypeBreak, kBlockTypeContinue, kBlockTypeReturn, kBlockTypeCOUNT ///< Total number of block types. (must be the last element) }; class Instruction; // This class represents a basic block in a SPIR-V module class BasicBlock { public: /// Constructor for a BasicBlock /// /// @param[in] id The ID of the basic block explicit BasicBlock(uint32_t id); /// Returns the id of the BasicBlock uint32_t id() const { return id_; } /// Returns the predecessors of the BasicBlock const std::vector<BasicBlock*>* predecessors() const { return &predecessors_; } /// Returns the predecessors of the BasicBlock std::vector<BasicBlock*>* predecessors() { return &predecessors_; } /// Returns the successors of the BasicBlock const std::vector<BasicBlock*>* successors() const { return &successors_; } /// Returns the successors of the BasicBlock std::vector<BasicBlock*>* successors() { return &successors_; } /// Returns true if the block is reachable in the CFG bool reachable() const { return reachable_; } /// Returns true if BasicBlock is of the given type bool is_type(BlockType type) const { if (type == kBlockTypeUndefined) return type_.none(); return type_.test(type); } /// Sets the reachability of the basic block in the CFG void set_reachable(bool reachability) { reachable_ = reachability; } /// Sets the type of the BasicBlock void set_type(BlockType type) { if (type == kBlockTypeUndefined) type_.reset(); else type_.set(type); } /// Sets the immedate dominator of this basic block /// /// @param[in] dom_block The dominator block void SetImmediateDominator(BasicBlock* dom_block); /// Sets the immedate post dominator of this basic block /// /// @param[in] pdom_block The post dominator block void SetImmediatePostDominator(BasicBlock* pdom_block); /// Returns the immedate dominator of this basic block BasicBlock* immediate_dominator(); /// Returns the immedate dominator of this basic block const BasicBlock* immediate_dominator() const; /// Returns the immedate post dominator of this basic block BasicBlock* immediate_post_dominator(); /// Returns the immedate post dominator of this basic block const BasicBlock* immediate_post_dominator() const; /// Ends the block without a successor void RegisterBranchInstruction(SpvOp branch_instruction); /// Returns the label instruction for the block, or nullptr if not set. const Instruction* label() const { return label_; } //// Registers the label instruction for the block. void set_label(const Instruction* t) { label_ = t; } /// Registers the terminator instruction for the block. void set_terminator(const Instruction* t) { terminator_ = t; } /// Returns the terminator instruction for the block. const Instruction* terminator() const { return terminator_; } /// Adds @p next BasicBlocks as successors of this BasicBlock void RegisterSuccessors( const std::vector<BasicBlock*>& next = std::vector<BasicBlock*>()); /// Returns true if the id of the BasicBlock matches bool operator==(const BasicBlock& other) const { return other.id_ == id_; } /// Returns true if the id of the BasicBlock matches bool operator==(const uint32_t& other_id) const { return other_id == id_; } /// Returns true if this block dominates the other block. /// Assumes dominators have been computed. bool dominates(const BasicBlock& other) const; /// Returns true if this block postdominates the other block. /// Assumes dominators have been computed. bool postdominates(const BasicBlock& other) const; /// @brief A BasicBlock dominator iterator class /// /// This iterator will iterate over the (post)dominators of the block class DominatorIterator : public std::iterator<std::forward_iterator_tag, BasicBlock*> { public: /// @brief Constructs the end of dominator iterator /// /// This will create an iterator which will represent the element /// before the root node of the dominator tree DominatorIterator(); /// @brief Constructs an iterator for the given block which points to /// @p block /// /// @param block The block which is referenced by the iterator /// @param dominator_func This function will be called to get the immediate /// (post)dominator of the current block DominatorIterator( const BasicBlock* block, std::function<const BasicBlock*(const BasicBlock*)> dominator_func); /// @brief Advances the iterator DominatorIterator& operator++(); /// @brief Returns the current element const BasicBlock*& operator*(); friend bool operator==(const DominatorIterator& lhs, const DominatorIterator& rhs); private: const BasicBlock* current_; std::function<const BasicBlock*(const BasicBlock*)> dom_func_; }; /// Returns a dominator iterator which points to the current block const DominatorIterator dom_begin() const; /// Returns a dominator iterator which points to the current block DominatorIterator dom_begin(); /// Returns a dominator iterator which points to one element past the first /// block const DominatorIterator dom_end() const; /// Returns a dominator iterator which points to one element past the first /// block DominatorIterator dom_end(); /// Returns a post dominator iterator which points to the current block const DominatorIterator pdom_begin() const; /// Returns a post dominator iterator which points to the current block DominatorIterator pdom_begin(); /// Returns a post dominator iterator which points to one element past the /// last block const DominatorIterator pdom_end() const; /// Returns a post dominator iterator which points to one element past the /// last block DominatorIterator pdom_end(); private: /// Id of the BasicBlock const uint32_t id_; /// Pointer to the immediate dominator of the BasicBlock BasicBlock* immediate_dominator_; /// Pointer to the immediate dominator of the BasicBlock BasicBlock* immediate_post_dominator_; /// The set of predecessors of the BasicBlock std::vector<BasicBlock*> predecessors_; /// The set of successors of the BasicBlock std::vector<BasicBlock*> successors_; /// The type of the block std::bitset<kBlockTypeCOUNT> type_; /// True if the block is reachable in the CFG bool reachable_; /// label of this block, if any. const Instruction* label_; /// Terminator of this block. const Instruction* terminator_; }; /// @brief Returns true if the iterators point to the same element or if both /// iterators point to the @p dom_end block bool operator==(const BasicBlock::DominatorIterator& lhs, const BasicBlock::DominatorIterator& rhs); /// @brief Returns true if the iterators point to different elements and they /// do not both point to the @p dom_end block bool operator!=(const BasicBlock::DominatorIterator& lhs, const BasicBlock::DominatorIterator& rhs); } // namespace val } // namespace spvtools #endif // SOURCE_VAL_BASIC_BLOCK_H_