| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- // 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.
- #include <iostream>
- #include <memory>
- #include <set>
- #include "source/cfa.h"
- #include "source/opt/dominator_tree.h"
- #include "source/opt/ir_context.h"
- // Calculates the dominator or postdominator tree for a given function.
- // 1 - Compute the successors and predecessors for each BasicBlock. We add a
- // placeholder node for the start node or for postdominators the exit. This node
- // will point to all entry or all exit nodes.
- // 2 - Using the CFA::DepthFirstTraversal get a depth first postordered list of
- // all BasicBlocks. Using the successors (or for postdominator, predecessors)
- // calculated in step 1 to traverse the tree.
- // 3 - Pass the list calculated in step 2 to the CFA::CalculateDominators using
- // the predecessors list (or for postdominator, successors). This will give us a
- // vector of BB pairs. Each BB and its immediate dominator.
- // 4 - Using the list from 3 use those edges to build a tree of
- // DominatorTreeNodes. Each node containing a link to the parent dominator and
- // children which are dominated.
- // 5 - Using the tree from 4, perform a depth first traversal to calculate the
- // preorder and postorder index of each node. We use these indexes to compare
- // nodes against each other for domination checks.
- namespace spvtools {
- namespace opt {
- namespace {
- // Wrapper around CFA::DepthFirstTraversal to provide an interface to perform
- // depth first search on generic BasicBlock types. Will call post and pre order
- // user defined functions during traversal
- //
- // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
- // SuccessorLambda - Lamdba matching the signature of 'const
- // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
- // succeeding BasicBlock A.
- // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
- // called on each node traversed AFTER their children.
- // PreLambda - Lamdba matching the signature of 'void (const BBType*)' will be
- // called on each node traversed BEFORE their children.
- template <typename BBType, typename SuccessorLambda, typename PreLambda,
- typename PostLambda>
- void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
- PreLambda pre, PostLambda post) {
- auto no_terminal_blocks = [](const BBType*) { return false; };
- CFA<BBType>::DepthFirstTraversal(bb, successors, pre, post,
- no_terminal_blocks);
- }
- // Wrapper around CFA::DepthFirstTraversal to provide an interface to perform
- // depth first search on generic BasicBlock types. This overload is for only
- // performing user defined post order.
- //
- // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
- // SuccessorLambda - Lamdba matching the signature of 'const
- // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
- // succeeding BasicBlock A.
- // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
- // called on each node traversed after their children.
- template <typename BBType, typename SuccessorLambda, typename PostLambda>
- void DepthFirstSearchPostOrder(const BBType* bb, SuccessorLambda successors,
- PostLambda post) {
- // Ignore preorder operation.
- auto nop_preorder = [](const BBType*) {};
- DepthFirstSearch(bb, successors, nop_preorder, post);
- }
- // Small type trait to get the function class type.
- template <typename BBType>
- struct GetFunctionClass {
- using FunctionType = Function;
- };
- // Helper class to compute predecessors and successors for each Basic Block in a
- // function. Through GetPredFunctor and GetSuccessorFunctor it provides an
- // interface to get the successor and predecessor lists for each basic
- // block. This is required by the DepthFirstTraversal and ComputeDominator
- // functions which take as parameter an std::function returning the successors
- // and predecessors respectively.
- //
- // When computing the post-dominator tree, all edges are inverted. So successors
- // returned by this class will be predecessors in the original CFG.
- template <typename BBType>
- class BasicBlockSuccessorHelper {
- // This should eventually become const BasicBlock.
- using BasicBlock = BBType;
- using Function = typename GetFunctionClass<BBType>::FunctionType;
- using BasicBlockListTy = std::vector<BasicBlock*>;
- using BasicBlockMapTy =
- std::unordered_map<const BasicBlock*, BasicBlockListTy>;
- public:
- // For compliance with the dominance tree computation, entry nodes are
- // connected to a single placeholder node.
- BasicBlockSuccessorHelper(Function& func,
- const BasicBlock* placeholder_start_node,
- bool post);
- // CFA::CalculateDominators requires std::vector<BasicBlock*>.
- using GetBlocksFunction =
- std::function<const std::vector<BasicBlock*>*(const BasicBlock*)>;
- // Returns the list of predecessor functions.
- GetBlocksFunction GetPredFunctor() {
- return [this](const BasicBlock* bb) {
- BasicBlockListTy* v = &this->predecessors_[bb];
- return v;
- };
- }
- // Returns a vector of the list of successor nodes from a given node.
- GetBlocksFunction GetSuccessorFunctor() {
- return [this](const BasicBlock* bb) {
- BasicBlockListTy* v = &this->successors_[bb];
- return v;
- };
- }
- private:
- bool invert_graph_;
- BasicBlockMapTy successors_;
- BasicBlockMapTy predecessors_;
- // Build the successors and predecessors map for each basic blocks |f|.
- // If |invert_graph_| is true, all edges are reversed (successors becomes
- // predecessors and vice versa).
- // For convenience, the start of the graph is |placeholder_start_node|.
- // The dominator tree construction requires a unique entry node, which cannot
- // be guaranteed for the postdominator graph. The |placeholder_start_node| BB
- // is here to gather all entry nodes.
- void CreateSuccessorMap(Function& f,
- const BasicBlock* placeholder_start_node);
- };
- template <typename BBType>
- BasicBlockSuccessorHelper<BBType>::BasicBlockSuccessorHelper(
- Function& func, const BasicBlock* placeholder_start_node, bool invert)
- : invert_graph_(invert) {
- CreateSuccessorMap(func, placeholder_start_node);
- }
- template <typename BBType>
- void BasicBlockSuccessorHelper<BBType>::CreateSuccessorMap(
- Function& f, const BasicBlock* placeholder_start_node) {
- IRContext* context = f.DefInst().context();
- if (invert_graph_) {
- // For the post dominator tree, we see the inverted graph.
- // successors_ in the inverted graph are the predecessors in the CFG.
- // The tree construction requires 1 entry point, so we add a placeholder
- // node that is connected to all function exiting basic blocks. An exiting
- // basic block is a block with an OpKill, OpUnreachable, OpReturn,
- // OpReturnValue, or OpTerminateInvocation as terminator instruction.
- for (BasicBlock& bb : f) {
- if (bb.hasSuccessor()) {
- BasicBlockListTy& pred_list = predecessors_[&bb];
- const auto& const_bb = bb;
- const_bb.ForEachSuccessorLabel(
- [this, &pred_list, &bb, context](const uint32_t successor_id) {
- BasicBlock* succ = context->get_instr_block(successor_id);
- // Inverted graph: our successors in the CFG
- // are our predecessors in the inverted graph.
- this->successors_[succ].push_back(&bb);
- pred_list.push_back(succ);
- });
- } else {
- successors_[placeholder_start_node].push_back(&bb);
- predecessors_[&bb].push_back(
- const_cast<BasicBlock*>(placeholder_start_node));
- }
- }
- } else {
- successors_[placeholder_start_node].push_back(f.entry().get());
- predecessors_[f.entry().get()].push_back(
- const_cast<BasicBlock*>(placeholder_start_node));
- for (BasicBlock& bb : f) {
- BasicBlockListTy& succ_list = successors_[&bb];
- const auto& const_bb = bb;
- const_bb.ForEachSuccessorLabel([&](const uint32_t successor_id) {
- BasicBlock* succ = context->get_instr_block(successor_id);
- succ_list.push_back(succ);
- predecessors_[succ].push_back(&bb);
- });
- }
- }
- }
- } // namespace
- bool DominatorTree::StrictlyDominates(uint32_t a, uint32_t b) const {
- if (a == b) return false;
- return Dominates(a, b);
- }
- bool DominatorTree::StrictlyDominates(const BasicBlock* a,
- const BasicBlock* b) const {
- return DominatorTree::StrictlyDominates(a->id(), b->id());
- }
- bool DominatorTree::StrictlyDominates(const DominatorTreeNode* a,
- const DominatorTreeNode* b) const {
- if (a == b) return false;
- return Dominates(a, b);
- }
- bool DominatorTree::Dominates(uint32_t a, uint32_t b) const {
- // Check that both of the inputs are actual nodes.
- const DominatorTreeNode* a_node = GetTreeNode(a);
- const DominatorTreeNode* b_node = GetTreeNode(b);
- if (!a_node || !b_node) return false;
- return Dominates(a_node, b_node);
- }
- bool DominatorTree::Dominates(const DominatorTreeNode* a,
- const DominatorTreeNode* b) const {
- if (!a || !b) return false;
- // Node A dominates node B if they are the same.
- if (a == b) return true;
- return a->dfs_num_pre_ < b->dfs_num_pre_ &&
- a->dfs_num_post_ > b->dfs_num_post_;
- }
- bool DominatorTree::Dominates(const BasicBlock* A, const BasicBlock* B) const {
- return Dominates(A->id(), B->id());
- }
- BasicBlock* DominatorTree::ImmediateDominator(const BasicBlock* A) const {
- return ImmediateDominator(A->id());
- }
- BasicBlock* DominatorTree::ImmediateDominator(uint32_t a) const {
- // Check that A is a valid node in the tree.
- auto a_itr = nodes_.find(a);
- if (a_itr == nodes_.end()) return nullptr;
- const DominatorTreeNode* node = &a_itr->second;
- if (node->parent_ == nullptr) {
- return nullptr;
- }
- return node->parent_->bb_;
- }
- DominatorTreeNode* DominatorTree::GetOrInsertNode(BasicBlock* bb) {
- DominatorTreeNode* dtn = nullptr;
- std::map<uint32_t, DominatorTreeNode>::iterator node_iter =
- nodes_.find(bb->id());
- if (node_iter == nodes_.end()) {
- dtn = &nodes_.emplace(std::make_pair(bb->id(), DominatorTreeNode{bb}))
- .first->second;
- } else {
- dtn = &node_iter->second;
- }
- return dtn;
- }
- void DominatorTree::GetDominatorEdges(
- const Function* f, const BasicBlock* placeholder_start_node,
- std::vector<std::pair<BasicBlock*, BasicBlock*>>* edges) {
- // Each time the depth first traversal calls the postorder callback
- // std::function we push that node into the postorder vector to create our
- // postorder list.
- std::vector<const BasicBlock*> postorder;
- auto postorder_function = [&](const BasicBlock* b) {
- postorder.push_back(b);
- };
- // CFA::CalculateDominators requires std::vector<BasicBlock*>
- // BB are derived from F, so we need to const cast it at some point
- // no modification is made on F.
- BasicBlockSuccessorHelper<BasicBlock> helper{
- *const_cast<Function*>(f), placeholder_start_node, postdominator_};
- // The successor function tells DepthFirstTraversal how to move to successive
- // nodes by providing an interface to get a list of successor nodes from any
- // given node.
- auto successor_functor = helper.GetSuccessorFunctor();
- // The predecessor functor does the same as the successor functor
- // but for all nodes preceding a given node.
- auto predecessor_functor = helper.GetPredFunctor();
- // If we're building a post dominator tree we traverse the tree in reverse
- // using the predecessor function in place of the successor function and vice
- // versa.
- DepthFirstSearchPostOrder(placeholder_start_node, successor_functor,
- postorder_function);
- *edges = CFA<BasicBlock>::CalculateDominators(postorder, predecessor_functor);
- }
- void DominatorTree::InitializeTree(const CFG& cfg, const Function* f) {
- ClearTree();
- // Skip over empty functions.
- if (f->cbegin() == f->cend()) {
- return;
- }
- const BasicBlock* placeholder_start_node =
- postdominator_ ? cfg.pseudo_exit_block() : cfg.pseudo_entry_block();
- // Get the immediate dominator for each node.
- std::vector<std::pair<BasicBlock*, BasicBlock*>> edges;
- GetDominatorEdges(f, placeholder_start_node, &edges);
- // Transform the vector<pair> into the tree structure which we can use to
- // efficiently query dominance.
- for (auto edge : edges) {
- DominatorTreeNode* first = GetOrInsertNode(edge.first);
- if (edge.first == edge.second) {
- if (std::find(roots_.begin(), roots_.end(), first) == roots_.end())
- roots_.push_back(first);
- continue;
- }
- DominatorTreeNode* second = GetOrInsertNode(edge.second);
- first->parent_ = second;
- second->children_.push_back(first);
- }
- ResetDFNumbering();
- }
- void DominatorTree::ResetDFNumbering() {
- int index = 0;
- auto preFunc = [&index](const DominatorTreeNode* node) {
- const_cast<DominatorTreeNode*>(node)->dfs_num_pre_ = ++index;
- };
- auto postFunc = [&index](const DominatorTreeNode* node) {
- const_cast<DominatorTreeNode*>(node)->dfs_num_post_ = ++index;
- };
- auto getSucc = [](const DominatorTreeNode* node) { return &node->children_; };
- for (auto root : roots_) DepthFirstSearch(root, getSucc, preFunc, postFunc);
- }
- void DominatorTree::DumpTreeAsDot(std::ostream& out_stream) const {
- out_stream << "digraph {\n";
- Visit([&out_stream](const DominatorTreeNode* node) {
- // Print the node.
- if (node->bb_) {
- out_stream << node->bb_->id() << "[label=\"" << node->bb_->id()
- << "\"];\n";
- }
- // Print the arrow from the parent to this node. Entry nodes will not have
- // parents so draw them as children from the placeholder node.
- if (node->parent_) {
- out_stream << node->parent_->bb_->id() << " -> " << node->bb_->id()
- << ";\n";
- }
- // Return true to continue the traversal.
- return true;
- });
- out_stream << "}\n";
- }
- } // namespace opt
- } // namespace spvtools
|