1 // Copyright (c) 2017 Google Inc.
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 #include <iostream>
16 #include <memory>
17 #include <set>
18
19 #include "source/cfa.h"
20 #include "source/opt/dominator_tree.h"
21 #include "source/opt/ir_context.h"
22
23 // Calculates the dominator or postdominator tree for a given function.
24 // 1 - Compute the successors and predecessors for each BasicBlock. We add a
25 // placeholder node for the start node or for postdominators the exit. This node
26 // will point to all entry or all exit nodes.
27 // 2 - Using the CFA::DepthFirstTraversal get a depth first postordered list of
28 // all BasicBlocks. Using the successors (or for postdominator, predecessors)
29 // calculated in step 1 to traverse the tree.
30 // 3 - Pass the list calculated in step 2 to the CFA::CalculateDominators using
31 // the predecessors list (or for postdominator, successors). This will give us a
32 // vector of BB pairs. Each BB and its immediate dominator.
33 // 4 - Using the list from 3 use those edges to build a tree of
34 // DominatorTreeNodes. Each node containing a link to the parent dominator and
35 // children which are dominated.
36 // 5 - Using the tree from 4, perform a depth first traversal to calculate the
37 // preorder and postorder index of each node. We use these indexes to compare
38 // nodes against each other for domination checks.
39
40 namespace spvtools {
41 namespace opt {
42 namespace {
43
44 // Wrapper around CFA::DepthFirstTraversal to provide an interface to perform
45 // depth first search on generic BasicBlock types. Will call post and pre order
46 // user defined functions during traversal
47 //
48 // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
49 // SuccessorLambda - Lamdba matching the signature of 'const
50 // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
51 // succeeding BasicBlock A.
52 // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
53 // called on each node traversed AFTER their children.
54 // PreLambda - Lamdba matching the signature of 'void (const BBType*)' will be
55 // called on each node traversed BEFORE their children.
56 template <typename BBType, typename SuccessorLambda, typename PreLambda,
57 typename PostLambda>
DepthFirstSearch(const BBType * bb,SuccessorLambda successors,PreLambda pre,PostLambda post)58 void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
59 PreLambda pre, PostLambda post) {
60 auto no_terminal_blocks = [](const BBType*) { return false; };
61 CFA<BBType>::DepthFirstTraversal(bb, successors, pre, post,
62 no_terminal_blocks);
63 }
64
65 // Wrapper around CFA::DepthFirstTraversal to provide an interface to perform
66 // depth first search on generic BasicBlock types. This overload is for only
67 // performing user defined post order.
68 //
69 // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
70 // SuccessorLambda - Lamdba matching the signature of 'const
71 // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
72 // succeeding BasicBlock A.
73 // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
74 // called on each node traversed after their children.
75 template <typename BBType, typename SuccessorLambda, typename PostLambda>
DepthFirstSearchPostOrder(const BBType * bb,SuccessorLambda successors,PostLambda post)76 void DepthFirstSearchPostOrder(const BBType* bb, SuccessorLambda successors,
77 PostLambda post) {
78 // Ignore preorder operation.
79 auto nop_preorder = [](const BBType*) {};
80 DepthFirstSearch(bb, successors, nop_preorder, post);
81 }
82
83 // Small type trait to get the function class type.
84 template <typename BBType>
85 struct GetFunctionClass {
86 using FunctionType = Function;
87 };
88
89 // Helper class to compute predecessors and successors for each Basic Block in a
90 // function. Through GetPredFunctor and GetSuccessorFunctor it provides an
91 // interface to get the successor and predecessor lists for each basic
92 // block. This is required by the DepthFirstTraversal and ComputeDominator
93 // functions which take as parameter an std::function returning the successors
94 // and predecessors respectively.
95 //
96 // When computing the post-dominator tree, all edges are inverted. So successors
97 // returned by this class will be predecessors in the original CFG.
98 template <typename BBType>
99 class BasicBlockSuccessorHelper {
100 // This should eventually become const BasicBlock.
101 using BasicBlock = BBType;
102 using Function = typename GetFunctionClass<BBType>::FunctionType;
103
104 using BasicBlockListTy = std::vector<BasicBlock*>;
105 using BasicBlockMapTy =
106 std::unordered_map<const BasicBlock*, BasicBlockListTy>;
107
108 public:
109 // For compliance with the dominance tree computation, entry nodes are
110 // connected to a single placeholder node.
111 BasicBlockSuccessorHelper(Function& func,
112 const BasicBlock* placeholder_start_node,
113 bool post);
114
115 // CFA::CalculateDominators requires std::vector<BasicBlock*>.
116 using GetBlocksFunction =
117 std::function<const std::vector<BasicBlock*>*(const BasicBlock*)>;
118
119 // Returns the list of predecessor functions.
GetPredFunctor()120 GetBlocksFunction GetPredFunctor() {
121 return [this](const BasicBlock* bb) {
122 BasicBlockListTy* v = &this->predecessors_[bb];
123 return v;
124 };
125 }
126
127 // Returns a vector of the list of successor nodes from a given node.
GetSuccessorFunctor()128 GetBlocksFunction GetSuccessorFunctor() {
129 return [this](const BasicBlock* bb) {
130 BasicBlockListTy* v = &this->successors_[bb];
131 return v;
132 };
133 }
134
135 private:
136 bool invert_graph_;
137 BasicBlockMapTy successors_;
138 BasicBlockMapTy predecessors_;
139
140 // Build the successors and predecessors map for each basic blocks |f|.
141 // If |invert_graph_| is true, all edges are reversed (successors becomes
142 // predecessors and vice versa).
143 // For convenience, the start of the graph is |placeholder_start_node|.
144 // The dominator tree construction requires a unique entry node, which cannot
145 // be guaranteed for the postdominator graph. The |placeholder_start_node| BB
146 // is here to gather all entry nodes.
147 void CreateSuccessorMap(Function& f,
148 const BasicBlock* placeholder_start_node);
149 };
150
151 template <typename BBType>
BasicBlockSuccessorHelper(Function & func,const BasicBlock * placeholder_start_node,bool invert)152 BasicBlockSuccessorHelper<BBType>::BasicBlockSuccessorHelper(
153 Function& func, const BasicBlock* placeholder_start_node, bool invert)
154 : invert_graph_(invert) {
155 CreateSuccessorMap(func, placeholder_start_node);
156 }
157
158 template <typename BBType>
CreateSuccessorMap(Function & f,const BasicBlock * placeholder_start_node)159 void BasicBlockSuccessorHelper<BBType>::CreateSuccessorMap(
160 Function& f, const BasicBlock* placeholder_start_node) {
161 IRContext* context = f.DefInst().context();
162
163 if (invert_graph_) {
164 // For the post dominator tree, we see the inverted graph.
165 // successors_ in the inverted graph are the predecessors in the CFG.
166 // The tree construction requires 1 entry point, so we add a placeholder
167 // node that is connected to all function exiting basic blocks. An exiting
168 // basic block is a block with an OpKill, OpUnreachable, OpReturn,
169 // OpReturnValue, or OpTerminateInvocation as terminator instruction.
170 for (BasicBlock& bb : f) {
171 if (bb.hasSuccessor()) {
172 BasicBlockListTy& pred_list = predecessors_[&bb];
173 const auto& const_bb = bb;
174 const_bb.ForEachSuccessorLabel(
175 [this, &pred_list, &bb, context](const uint32_t successor_id) {
176 BasicBlock* succ = context->get_instr_block(successor_id);
177 // Inverted graph: our successors in the CFG
178 // are our predecessors in the inverted graph.
179 this->successors_[succ].push_back(&bb);
180 pred_list.push_back(succ);
181 });
182 } else {
183 successors_[placeholder_start_node].push_back(&bb);
184 predecessors_[&bb].push_back(
185 const_cast<BasicBlock*>(placeholder_start_node));
186 }
187 }
188 } else {
189 successors_[placeholder_start_node].push_back(f.entry().get());
190 predecessors_[f.entry().get()].push_back(
191 const_cast<BasicBlock*>(placeholder_start_node));
192 for (BasicBlock& bb : f) {
193 BasicBlockListTy& succ_list = successors_[&bb];
194
195 const auto& const_bb = bb;
196 const_bb.ForEachSuccessorLabel([&](const uint32_t successor_id) {
197 BasicBlock* succ = context->get_instr_block(successor_id);
198 succ_list.push_back(succ);
199 predecessors_[succ].push_back(&bb);
200 });
201 }
202 }
203 }
204
205 } // namespace
206
StrictlyDominates(uint32_t a,uint32_t b) const207 bool DominatorTree::StrictlyDominates(uint32_t a, uint32_t b) const {
208 if (a == b) return false;
209 return Dominates(a, b);
210 }
211
StrictlyDominates(const BasicBlock * a,const BasicBlock * b) const212 bool DominatorTree::StrictlyDominates(const BasicBlock* a,
213 const BasicBlock* b) const {
214 return DominatorTree::StrictlyDominates(a->id(), b->id());
215 }
216
StrictlyDominates(const DominatorTreeNode * a,const DominatorTreeNode * b) const217 bool DominatorTree::StrictlyDominates(const DominatorTreeNode* a,
218 const DominatorTreeNode* b) const {
219 if (a == b) return false;
220 return Dominates(a, b);
221 }
222
Dominates(uint32_t a,uint32_t b) const223 bool DominatorTree::Dominates(uint32_t a, uint32_t b) const {
224 // Check that both of the inputs are actual nodes.
225 const DominatorTreeNode* a_node = GetTreeNode(a);
226 const DominatorTreeNode* b_node = GetTreeNode(b);
227 if (!a_node || !b_node) return false;
228
229 return Dominates(a_node, b_node);
230 }
231
Dominates(const DominatorTreeNode * a,const DominatorTreeNode * b) const232 bool DominatorTree::Dominates(const DominatorTreeNode* a,
233 const DominatorTreeNode* b) const {
234 if (!a || !b) return false;
235 // Node A dominates node B if they are the same.
236 if (a == b) return true;
237
238 return a->dfs_num_pre_ < b->dfs_num_pre_ &&
239 a->dfs_num_post_ > b->dfs_num_post_;
240 }
241
Dominates(const BasicBlock * A,const BasicBlock * B) const242 bool DominatorTree::Dominates(const BasicBlock* A, const BasicBlock* B) const {
243 return Dominates(A->id(), B->id());
244 }
245
ImmediateDominator(const BasicBlock * A) const246 BasicBlock* DominatorTree::ImmediateDominator(const BasicBlock* A) const {
247 return ImmediateDominator(A->id());
248 }
249
ImmediateDominator(uint32_t a) const250 BasicBlock* DominatorTree::ImmediateDominator(uint32_t a) const {
251 // Check that A is a valid node in the tree.
252 auto a_itr = nodes_.find(a);
253 if (a_itr == nodes_.end()) return nullptr;
254
255 const DominatorTreeNode* node = &a_itr->second;
256
257 if (node->parent_ == nullptr) {
258 return nullptr;
259 }
260
261 return node->parent_->bb_;
262 }
263
GetOrInsertNode(BasicBlock * bb)264 DominatorTreeNode* DominatorTree::GetOrInsertNode(BasicBlock* bb) {
265 DominatorTreeNode* dtn = nullptr;
266
267 std::map<uint32_t, DominatorTreeNode>::iterator node_iter =
268 nodes_.find(bb->id());
269 if (node_iter == nodes_.end()) {
270 dtn = &nodes_.emplace(std::make_pair(bb->id(), DominatorTreeNode{bb}))
271 .first->second;
272 } else {
273 dtn = &node_iter->second;
274 }
275
276 return dtn;
277 }
278
GetDominatorEdges(const Function * f,const BasicBlock * placeholder_start_node,std::vector<std::pair<BasicBlock *,BasicBlock * >> * edges)279 void DominatorTree::GetDominatorEdges(
280 const Function* f, const BasicBlock* placeholder_start_node,
281 std::vector<std::pair<BasicBlock*, BasicBlock*>>* edges) {
282 // Each time the depth first traversal calls the postorder callback
283 // std::function we push that node into the postorder vector to create our
284 // postorder list.
285 std::vector<const BasicBlock*> postorder;
286 auto postorder_function = [&](const BasicBlock* b) {
287 postorder.push_back(b);
288 };
289
290 // CFA::CalculateDominators requires std::vector<BasicBlock*>
291 // BB are derived from F, so we need to const cast it at some point
292 // no modification is made on F.
293 BasicBlockSuccessorHelper<BasicBlock> helper{
294 *const_cast<Function*>(f), placeholder_start_node, postdominator_};
295
296 // The successor function tells DepthFirstTraversal how to move to successive
297 // nodes by providing an interface to get a list of successor nodes from any
298 // given node.
299 auto successor_functor = helper.GetSuccessorFunctor();
300
301 // The predecessor functor does the same as the successor functor
302 // but for all nodes preceding a given node.
303 auto predecessor_functor = helper.GetPredFunctor();
304
305 // If we're building a post dominator tree we traverse the tree in reverse
306 // using the predecessor function in place of the successor function and vice
307 // versa.
308 DepthFirstSearchPostOrder(placeholder_start_node, successor_functor,
309 postorder_function);
310 *edges = CFA<BasicBlock>::CalculateDominators(postorder, predecessor_functor);
311 }
312
InitializeTree(const CFG & cfg,const Function * f)313 void DominatorTree::InitializeTree(const CFG& cfg, const Function* f) {
314 ClearTree();
315
316 // Skip over empty functions.
317 if (f->cbegin() == f->cend()) {
318 return;
319 }
320
321 const BasicBlock* placeholder_start_node =
322 postdominator_ ? cfg.pseudo_exit_block() : cfg.pseudo_entry_block();
323
324 // Get the immediate dominator for each node.
325 std::vector<std::pair<BasicBlock*, BasicBlock*>> edges;
326 GetDominatorEdges(f, placeholder_start_node, &edges);
327
328 // Transform the vector<pair> into the tree structure which we can use to
329 // efficiently query dominance.
330 for (auto edge : edges) {
331 DominatorTreeNode* first = GetOrInsertNode(edge.first);
332
333 if (edge.first == edge.second) {
334 if (std::find(roots_.begin(), roots_.end(), first) == roots_.end())
335 roots_.push_back(first);
336 continue;
337 }
338
339 DominatorTreeNode* second = GetOrInsertNode(edge.second);
340
341 first->parent_ = second;
342 second->children_.push_back(first);
343 }
344 ResetDFNumbering();
345 }
346
ResetDFNumbering()347 void DominatorTree::ResetDFNumbering() {
348 int index = 0;
349 auto preFunc = [&index](const DominatorTreeNode* node) {
350 const_cast<DominatorTreeNode*>(node)->dfs_num_pre_ = ++index;
351 };
352
353 auto postFunc = [&index](const DominatorTreeNode* node) {
354 const_cast<DominatorTreeNode*>(node)->dfs_num_post_ = ++index;
355 };
356
357 auto getSucc = [](const DominatorTreeNode* node) { return &node->children_; };
358
359 for (auto root : roots_) DepthFirstSearch(root, getSucc, preFunc, postFunc);
360 }
361
DumpTreeAsDot(std::ostream & out_stream) const362 void DominatorTree::DumpTreeAsDot(std::ostream& out_stream) const {
363 out_stream << "digraph {\n";
364 Visit([&out_stream](const DominatorTreeNode* node) {
365 // Print the node.
366 if (node->bb_) {
367 out_stream << node->bb_->id() << "[label=\"" << node->bb_->id()
368 << "\"];\n";
369 }
370
371 // Print the arrow from the parent to this node. Entry nodes will not have
372 // parents so draw them as children from the placeholder node.
373 if (node->parent_) {
374 out_stream << node->parent_->bb_->id() << " -> " << node->bb_->id()
375 << ";\n";
376 }
377
378 // Return true to continue the traversal.
379 return true;
380 });
381 out_stream << "}\n";
382 }
383
384 } // namespace opt
385 } // namespace spvtools
386