| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- // Copyright (c) 2017 Google 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_OPT_DOMINATOR_TREE_H_
- #define SOURCE_OPT_DOMINATOR_TREE_H_
- #include <algorithm>
- #include <cstdint>
- #include <map>
- #include <utility>
- #include <vector>
- #include "source/opt/cfg.h"
- #include "source/opt/tree_iterator.h"
- namespace spvtools {
- namespace opt {
- // This helper struct forms the nodes in the tree, with each node containing its
- // children. It also contains two values, for the pre and post indexes in the
- // tree which are used to compare two nodes.
- struct DominatorTreeNode {
- explicit DominatorTreeNode(BasicBlock* bb)
- : bb_(bb),
- parent_(nullptr),
- children_({}),
- dfs_num_pre_(-1),
- dfs_num_post_(-1) {}
- using iterator = std::vector<DominatorTreeNode*>::iterator;
- using const_iterator = std::vector<DominatorTreeNode*>::const_iterator;
- // depth first preorder iterator.
- using df_iterator = TreeDFIterator<DominatorTreeNode>;
- using const_df_iterator = TreeDFIterator<const DominatorTreeNode>;
- // depth first postorder iterator.
- using post_iterator = PostOrderTreeDFIterator<DominatorTreeNode>;
- using const_post_iterator = PostOrderTreeDFIterator<const DominatorTreeNode>;
- iterator begin() { return children_.begin(); }
- iterator end() { return children_.end(); }
- const_iterator begin() const { return cbegin(); }
- const_iterator end() const { return cend(); }
- const_iterator cbegin() const { return children_.begin(); }
- const_iterator cend() const { return children_.end(); }
- // Depth first preorder iterator using this node as root.
- df_iterator df_begin() { return df_iterator(this); }
- df_iterator df_end() { return df_iterator(); }
- const_df_iterator df_begin() const { return df_cbegin(); }
- const_df_iterator df_end() const { return df_cend(); }
- const_df_iterator df_cbegin() const { return const_df_iterator(this); }
- const_df_iterator df_cend() const { return const_df_iterator(); }
- // Depth first postorder iterator using this node as root.
- post_iterator post_begin() { return post_iterator::begin(this); }
- post_iterator post_end() { return post_iterator::end(nullptr); }
- const_post_iterator post_begin() const { return post_cbegin(); }
- const_post_iterator post_end() const { return post_cend(); }
- const_post_iterator post_cbegin() const {
- return const_post_iterator::begin(this);
- }
- const_post_iterator post_cend() const {
- return const_post_iterator::end(nullptr);
- }
- inline uint32_t id() const { return bb_->id(); }
- BasicBlock* bb_;
- DominatorTreeNode* parent_;
- std::vector<DominatorTreeNode*> children_;
- // These indexes are used to compare two given nodes. A node is a child or
- // grandchild of another node if its preorder index is greater than the
- // first nodes preorder index AND if its postorder index is less than the
- // first nodes postorder index.
- int dfs_num_pre_;
- int dfs_num_post_;
- };
- // A class representing a tree of BasicBlocks in a given function, where each
- // node is dominated by its parent.
- class DominatorTree {
- public:
- // Map OpLabel ids to dominator tree nodes
- using DominatorTreeNodeMap = std::map<uint32_t, DominatorTreeNode>;
- using iterator = TreeDFIterator<DominatorTreeNode>;
- using const_iterator = TreeDFIterator<const DominatorTreeNode>;
- using post_iterator = PostOrderTreeDFIterator<DominatorTreeNode>;
- using const_post_iterator = PostOrderTreeDFIterator<const DominatorTreeNode>;
- // List of DominatorTreeNode to define the list of roots
- using DominatorTreeNodeList = std::vector<DominatorTreeNode*>;
- using roots_iterator = DominatorTreeNodeList::iterator;
- using roots_const_iterator = DominatorTreeNodeList::const_iterator;
- DominatorTree() : postdominator_(false) {}
- explicit DominatorTree(bool post) : postdominator_(post) {}
- // Depth first iterators.
- // Traverse the dominator tree in a depth first pre-order.
- // The pseudo-block is ignored.
- iterator begin() { return ++iterator(GetRoot()); }
- iterator end() { return iterator(); }
- const_iterator begin() const { return cbegin(); }
- const_iterator end() const { return cend(); }
- const_iterator cbegin() const { return ++const_iterator(GetRoot()); }
- const_iterator cend() const { return const_iterator(); }
- // Traverse the dominator tree in a depth first post-order.
- // The pseudo-block is ignored.
- post_iterator post_begin() { return post_iterator::begin(GetRoot()); }
- post_iterator post_end() { return post_iterator::end(GetRoot()); }
- const_post_iterator post_begin() const { return post_cbegin(); }
- const_post_iterator post_end() const { return post_cend(); }
- const_post_iterator post_cbegin() const {
- return const_post_iterator::begin(GetRoot());
- }
- const_post_iterator post_cend() const {
- return const_post_iterator::end(GetRoot());
- }
- roots_iterator roots_begin() { return roots_.begin(); }
- roots_iterator roots_end() { return roots_.end(); }
- roots_const_iterator roots_begin() const { return roots_cbegin(); }
- roots_const_iterator roots_end() const { return roots_cend(); }
- roots_const_iterator roots_cbegin() const { return roots_.begin(); }
- roots_const_iterator roots_cend() const { return roots_.end(); }
- // Get the unique root of the tree.
- // It is guaranteed to work on a dominator tree.
- // post-dominator might have a list.
- DominatorTreeNode* GetRoot() {
- assert(roots_.size() == 1);
- return *roots_.begin();
- }
- const DominatorTreeNode* GetRoot() const {
- assert(roots_.size() == 1);
- return *roots_.begin();
- }
- const DominatorTreeNodeList& Roots() const { return roots_; }
- // Dumps the tree in the graphvis dot format into the |out_stream|.
- void DumpTreeAsDot(std::ostream& out_stream) const;
- // Build the (post-)dominator tree for the given control flow graph
- // |cfg| and the function |f|. |f| must exist in the |cfg|. Any
- // existing data in the dominator tree will be overwritten
- void InitializeTree(const CFG& cfg, const Function* f);
- // Check if the basic block |a| dominates the basic block |b|.
- bool Dominates(const BasicBlock* a, const BasicBlock* b) const;
- // Check if the basic block id |a| dominates the basic block id |b|.
- bool Dominates(uint32_t a, uint32_t b) const;
- // Check if the dominator tree node |a| dominates the dominator tree node |b|.
- bool Dominates(const DominatorTreeNode* a, const DominatorTreeNode* b) const;
- // Check if the basic block |a| strictly dominates the basic block |b|.
- bool StrictlyDominates(const BasicBlock* a, const BasicBlock* b) const;
- // Check if the basic block id |a| strictly dominates the basic block id |b|.
- bool StrictlyDominates(uint32_t a, uint32_t b) const;
- // Check if the dominator tree node |a| strictly dominates the dominator tree
- // node |b|.
- bool StrictlyDominates(const DominatorTreeNode* a,
- const DominatorTreeNode* b) const;
- // Returns the immediate dominator of basic block |a|.
- BasicBlock* ImmediateDominator(const BasicBlock* A) const;
- // Returns the immediate dominator of basic block id |a|.
- BasicBlock* ImmediateDominator(uint32_t a) const;
- // Returns true if the basic block |a| is reachable by this tree. A node would
- // be unreachable if it cannot be reached by traversal from the start node or
- // for a postdominator tree, cannot be reached from the exit nodes.
- inline bool ReachableFromRoots(const BasicBlock* a) const {
- if (!a) return false;
- return ReachableFromRoots(a->id());
- }
- // Returns true if the basic block id |a| is reachable by this tree.
- bool ReachableFromRoots(uint32_t a) const {
- return GetTreeNode(a) != nullptr;
- }
- // Returns true if this tree is a post dominator tree.
- bool IsPostDominator() const { return postdominator_; }
- // Clean up the tree.
- void ClearTree() {
- nodes_.clear();
- roots_.clear();
- }
- // Applies the std::function |func| to all nodes in the dominator tree.
- // Tree nodes are visited in a depth first pre-order.
- bool Visit(std::function<bool(DominatorTreeNode*)> func) {
- for (auto n : *this) {
- if (!func(&n)) return false;
- }
- return true;
- }
- // Applies the std::function |func| to all nodes in the dominator tree.
- // Tree nodes are visited in a depth first pre-order.
- bool Visit(std::function<bool(const DominatorTreeNode*)> func) const {
- for (auto n : *this) {
- if (!func(&n)) return false;
- }
- return true;
- }
- // Applies the std::function |func| to all nodes in the dominator tree from
- // |node| downwards. The boolean return from |func| is used to determine
- // whether or not the children should also be traversed. Tree nodes are
- // visited in a depth first pre-order.
- void VisitChildrenIf(std::function<bool(DominatorTreeNode*)> func,
- iterator node) {
- if (func(&*node)) {
- for (auto n : *node) {
- VisitChildrenIf(func, n->df_begin());
- }
- }
- }
- // Returns the DominatorTreeNode associated with the basic block |bb|.
- // If the |bb| is unknown to the dominator tree, it returns null.
- inline DominatorTreeNode* GetTreeNode(BasicBlock* bb) {
- return GetTreeNode(bb->id());
- }
- // Returns the DominatorTreeNode associated with the basic block |bb|.
- // If the |bb| is unknown to the dominator tree, it returns null.
- inline const DominatorTreeNode* GetTreeNode(BasicBlock* bb) const {
- return GetTreeNode(bb->id());
- }
- // Returns the DominatorTreeNode associated with the basic block id |id|.
- // If the id |id| is unknown to the dominator tree, it returns null.
- inline DominatorTreeNode* GetTreeNode(uint32_t id) {
- DominatorTreeNodeMap::iterator node_iter = nodes_.find(id);
- if (node_iter == nodes_.end()) {
- return nullptr;
- }
- return &node_iter->second;
- }
- // Returns the DominatorTreeNode associated with the basic block id |id|.
- // If the id |id| is unknown to the dominator tree, it returns null.
- inline const DominatorTreeNode* GetTreeNode(uint32_t id) const {
- DominatorTreeNodeMap::const_iterator node_iter = nodes_.find(id);
- if (node_iter == nodes_.end()) {
- return nullptr;
- }
- return &node_iter->second;
- }
- // Adds the basic block |bb| to the tree structure if it doesn't already
- // exist.
- DominatorTreeNode* GetOrInsertNode(BasicBlock* bb);
- // Recomputes the DF numbering of the tree.
- void ResetDFNumbering();
- private:
- // Wrapper function which gets the list of pairs of each BasicBlocks to its
- // immediately dominating BasicBlock and stores the result in the edges
- // parameter.
- //
- // The |edges| vector will contain the dominator tree as pairs of nodes.
- // The first node in the pair is a node in the graph. The second node in the
- // pair is its immediate dominator.
- // The root of the tree has themself as immediate dominator.
- void GetDominatorEdges(
- const Function* f, const BasicBlock* dummy_start_node,
- std::vector<std::pair<BasicBlock*, BasicBlock*>>* edges);
- // The roots of the tree.
- std::vector<DominatorTreeNode*> roots_;
- // Pairs each basic block id to the tree node containing that basic block.
- DominatorTreeNodeMap nodes_;
- // True if this is a post dominator tree.
- bool postdominator_;
- };
- } // namespace opt
- } // namespace spvtools
- #endif // SOURCE_OPT_DOMINATOR_TREE_H_
|