llvm.org GIT mirror llvm / 3f91c64
[Dominators] Use a custom DFS implementation Summary: Custom DFS implementation allows us to skip over certain nodes without adding them to the visited map, which is not easily doable with llvm's dfs iterators. What's more, caching predecessors becomes easy. This patch implements a single DFS function (template) for both forward and reverse DFS, which should be easier to maintain then separate two ones. Skipping over nodes based on a predicate will be necessary later to implement incremental updates. There also seems to be a very slight performance improved when bootstrapping clang with this patch on my machine (3:28s -> 3:26s) . Reviewers: dberlin, sanjoy, davide, grosser Reviewed By: dberlin Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34651 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307727 91177308-0d34-0410-b5e6-96231b3b80d8 Jakub Kuderski 3 years ago
1 changed file(s) with 91 addition(s) and 94 deletion(s). Raw diff Collapse all Expand all
3131 namespace llvm {
3232 namespace DomTreeBuilder {
3333
34 template
35 struct ChildrenGetter {
36 static auto Get(NodePtr N) -> decltype(reverse(children(N))) {
37 return reverse(children(N));
38 }
39 };
40
41 template
42 struct ChildrenGetter {
43 static auto Get(NodePtr N) -> decltype(inverse_children(N)) {
44 return inverse_children(N);
45 }
46 };
47
3448 // Information record used by Semi-NCA during tree construction.
3549 template
3650 struct SemiNCAInfo {
4458 unsigned Semi = 0;
4559 NodePtr Label = nullptr;
4660 NodePtr IDom = nullptr;
61 SmallVector ReverseChildren;
4762 };
4863
4964 std::vector NumToNode;
7893 .get();
7994 }
8095
81 // External storage for depth first iterator that reuses the info lookup map
82 // SemiNCAInfo already has. We don't have a set, but a map instead, so we are
83 // converting the one argument insert calls.
84 struct df_iterator_dom_storage {
85 public:
86 using BaseSet = decltype(NodeToInfo);
87 df_iterator_dom_storage(BaseSet &Storage) : Storage(Storage) {}
88
89 using iterator = typename BaseSet::iterator;
90 std::pair insert(NodePtr N) {
91 return Storage.insert({N, InfoRec()});
92 }
93 void completed(NodePtr) {}
94
95 private:
96 BaseSet &Storage;
96 static bool AlwaysDescend(NodePtr, NodePtr) { return true; }
97
98 // Custom DFS implementation which can skip nodes based on a provided
99 // predicate. It also collects ReverseChildren so that we don't have to spend
100 // time getting predecessors in SemiNCA.
101 template
102 unsigned runDFS(NodePtr V, unsigned LastNum, DescendCondition Condition,
103 unsigned AttachToNum) {
104 assert(V);
105 SmallVector WorkList = {V};
106 if (NodeToInfo.count(V) != 0) NodeToInfo[V].Parent = AttachToNum;
107
108 while (!WorkList.empty()) {
109 const NodePtr BB = WorkList.pop_back_val();
110 auto &BBInfo = NodeToInfo[BB];
111
112 // Visited nodes always have positive DFS numbers.
113 if (BBInfo.DFSNum != 0) continue;
114 BBInfo.DFSNum = BBInfo.Semi = ++LastNum;
115 BBInfo.Label = BB;
116 NumToNode.push_back(BB);
117
118 for (const NodePtr Succ : ChildrenGetter::Get(BB)) {
119 const auto SIT = NodeToInfo.find(Succ);
120 // Don't visit nodes more than once but remember to collect
121 // RerverseChildren.
122 if (SIT != NodeToInfo.end() && SIT->second.DFSNum != 0) {
123 if (Succ != BB) SIT->second.ReverseChildren.push_back(BB);
124 continue;
125 }
126
127 if (!Condition(BB, Succ)) continue;
128
129 // It's fine to add Succ to the map, because we know that it will be
130 // visited later.
131 auto &SuccInfo = NodeToInfo[Succ];
132 WorkList.push_back(Succ);
133 SuccInfo.Parent = LastNum;
134 SuccInfo.ReverseChildren.push_back(BB);
135 }
136 }
137
138 return LastNum;
97139 };
98
99 df_iterator_dom_storage getStorage() { return {NodeToInfo}; }
100
101 unsigned runReverseDFS(NodePtr V, unsigned N) {
102 auto DFStorage = getStorage();
103
104 bool IsChildOfArtificialExit = (N != 0);
105 for (auto I = idf_ext_begin(V, DFStorage), E = idf_ext_end(V, DFStorage);
106 I != E; ++I) {
107 NodePtr BB = *I;
108 auto &BBInfo = NodeToInfo[BB];
109 BBInfo.DFSNum = BBInfo.Semi = ++N;
110 BBInfo.Label = BB;
111 // Set the parent to the top of the visited stack. The stack includes us,
112 // and is 1 based, so we subtract to account for both of these.
113 if (I.getPathLength() > 1)
114 BBInfo.Parent = NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum;
115 NumToNode.push_back(BB); // NumToNode[n] = V;
116
117 if (IsChildOfArtificialExit)
118 BBInfo.Parent = 1;
119
120 IsChildOfArtificialExit = false;
121 }
122 return N;
123 }
124
125 unsigned runForwardDFS(NodePtr V, unsigned N) {
126 auto DFStorage = getStorage();
127
128 for (auto I = df_ext_begin(V, DFStorage), E = df_ext_end(V, DFStorage);
129 I != E; ++I) {
130 NodePtr BB = *I;
131 auto &BBInfo = NodeToInfo[BB];
132 BBInfo.DFSNum = BBInfo.Semi = ++N;
133 BBInfo.Label = BB;
134 // Set the parent to the top of the visited stack. The stack includes us,
135 // and is 1 based, so we subtract to account for both of these.
136 if (I.getPathLength() > 1)
137 BBInfo.Parent = NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum;
138 NumToNode.push_back(BB); // NumToNode[n] = V;
139 }
140 return N;
141 }
142140
143141 NodePtr eval(NodePtr VIn, unsigned LastLinked) {
144142 auto &VInInfo = NodeToInfo[VIn];
180178
181179 template
182180 void runSemiNCA(DomTreeT &DT, unsigned NumBlocks) {
183 unsigned N = 0;
184 NumToNode.push_back(nullptr);
185
186 bool MultipleRoots = (DT.Roots.size() > 1);
187 if (MultipleRoots) {
188 auto &BBInfo = NodeToInfo[nullptr];
189 BBInfo.DFSNum = BBInfo.Semi = ++N;
190 BBInfo.Label = nullptr;
191
192 NumToNode.push_back(nullptr); // NumToNode[n] = V;
193 }
194
195181 // Step #1: Number blocks in depth-first order and initialize variables used
196182 // in later stages of the algorithm.
197 if (DT.isPostDominator()){
198 for (unsigned i = 0, e = static_cast(DT.Roots.size());
199 i != e; ++i)
200 N = runReverseDFS(DT.Roots[i], N);
201 } else {
202 N = runForwardDFS(DT.Roots[0], N);
203 }
183 const unsigned N = doFullDFSWalk(DT, AlwaysDescend);
204184
205185 // It might be that some blocks did not get a DFS number (e.g., blocks of
206186 // infinite loops). In these cases an artificial exit node is required.
207 MultipleRoots |= (DT.isPostDominator() && N != NumBlocks);
187 const bool MultipleRoots =
188 DT.Roots.size() > 1 || (DT.isPostDominator() && N != NumBlocks);
208189
209190 // Initialize IDoms to spanning tree parents.
210191 for (unsigned i = 1; i <= N; ++i) {
220201
221202 // Initialize the semi dominator to point to the parent node.
222203 WInfo.Semi = WInfo.Parent;
223 for (const auto &N : inverse_children(W))
204 for (const auto &N : WInfo.ReverseChildren)
224205 if (NodeToInfo.count(N)) { // Only if this predecessor is reachable!
225206 unsigned SemiU = NodeToInfo[eval(N, i + 1)].Semi;
226207 if (SemiU < WInfo.Semi)
278259 }
279260 }
280261
281 void doFullDFSWalk(const DomTreeT &DT) {
262 template
263 unsigned doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
264 unsigned Num = 0;
282265 NumToNode.push_back(nullptr);
283 unsigned Num = 0;
284 for (auto *Root : DT.Roots)
285 if (!DT.isPostDominator())
286 Num = runForwardDFS(Root, Num);
287 else
288 Num = runReverseDFS(Root, Num);
266
267 if (DT.Roots.size() > 1) {
268 auto &BBInfo = NodeToInfo[nullptr];
269 BBInfo.DFSNum = BBInfo.Semi = ++Num;
270 BBInfo.Label = nullptr;
271
272 NumToNode.push_back(nullptr); // NumToNode[n] = V;
273 }
274
275 if (DT.isPostDominator()) {
276 for (auto *Root : DT.Roots) Num = runDFS(Root, Num, DC, 1);
277 } else {
278 assert(DT.Roots.size() == 1);
279 Num = runDFS(DT.Roots[0], Num, DC, Num);
280 }
281
282 return Num;
289283 }
290284
291285 static void PrintBlockOrNullptr(raw_ostream &O, NodePtr Obj) {
298292 // Checks if the tree contains all reachable nodes in the input graph.
299293 bool verifyReachability(const DomTreeT &DT) {
300294 clear();
301 doFullDFSWalk(DT);
295 doFullDFSWalk(DT, AlwaysDescend);
302296
303297 for (auto &NodeToTN : DT.DomTreeNodes) {
304298 const TreeNodePtr TN = NodeToTN.second.get();
355349 // NCD(From, To) == IDom(To) or To.
356350 bool verifyNCD(const DomTreeT &DT) {
357351 clear();
358 doFullDFSWalk(DT);
352 doFullDFSWalk(DT, AlwaysDescend);
359353
360354 for (auto &BlockToInfo : NodeToInfo) {
361355 auto &Info = BlockToInfo.second;
439433 if (!BB || TN->getChildren().empty()) continue;
440434
441435 clear();
442 NodeToInfo.insert({BB, {}});
443 doFullDFSWalk(DT);
436 doFullDFSWalk(DT, [BB](NodePtr From, NodePtr To) {
437 return From != BB && To != BB;
438 });
444439
445440 for (TreeNodePtr Child : TN->getChildren())
446441 if (NodeToInfo.count(Child->getBlock()) != 0) {
472467 const auto &Siblings = TN->getChildren();
473468 for (const TreeNodePtr N : Siblings) {
474469 clear();
475 NodeToInfo.insert({N->getBlock(), {}});
476 doFullDFSWalk(DT);
470 NodePtr BBN = N->getBlock();
471 doFullDFSWalk(DT, [BBN](NodePtr From, NodePtr To) {
472 return From != BBN && To != BBN;
473 });
477474
478475 for (const TreeNodePtr S : Siblings) {
479476 if (S == N) continue;