[Dominators] Use SemiNCA instead of SLT to calculate dominators
Summary:
This patch makes GenericDomTreeConstruction use the SemiNCA algorithm instead of Simple LengauerTarjan.
As described in `RFC: Dynamic dominators`, SemiNCA offers slightly better performance than SLT. What's more important, it can be extended to perform incremental updates on already constructed dominator trees.
The patch passes checkall, llvm test suite and is able to boostrap clang. I also wasn't able to observe any compilation time regressions.
Reviewers: sanjoy, dberlin, chandlerc, grosser
Reviewed By: dberlin
Subscribers: llvmcommits
Differential Revision: https://reviews.llvm.org/D34258
gitsvnid: https://llvm.org/svn/llvmproject/llvm/trunk@306437 911773080d340410b5e696231b3b80d8
Jakub Kuderski
3 years ago
9  9  /// 
10  10  /// Generic dominator tree construction  This file provides routines to 
11  11  /// construct immediate dominator information for a flowgraph based on the 
12  /// algorithm described in this document:  
13  ///  
14  /// A Fast Algorithm for Finding Dominators in a Flowgraph  
15 
/// 

12  /// SemiNCA algorithm described in this dissertation:⏎  
13  ///  
14  /// LinearTime Algorithms for Dominators and Related Problems  
15  /// Loukas Georgiadis, Princeton University, November 2005, pp. 2123:  
16  /// ftp://ftp.cs.princeton.edu/reports/2005/737.pdf  
16  17  /// 
17  18  /// This implements the O(n*log(n)) versions of EVAL and LINK, because it turns 
18  19  /// out that the theoretically slower O(n*log(n)) implementation is actually 
168  169 
N = DFSPass 
169  170  } 
170  171  
171 
// 

172  // It might be that some blocks did not get a DFS number (e.g., blocks of⏎  
172  173  // infinite loops). In these cases an artificial exit node is required. 
173  174 
MultipleRoots = (DT.isPostDominator() && N != GraphTraits 
174  175  
175  // When naively implemented, the LengauerTarjan algorithm requires a separate  
176  // bucket for each vertex. However, this is unnecessary, because each vertex  
177  // is only placed into a single bucket (that of its semidominator), and each  
178  // vertex's bucket is processed before it is added to any bucket itself.  
179  //  
180  // Instead of using a bucket per vertex, we use a single array Buckets that  
181  // has two purposes. Before the vertex V with preorder number i is processed,  
182  // Buckets[i] stores the index of the first element in V's bucket. After V's  
183  // bucket is processed, Buckets[i] stores the index of the next element in the  
184  // bucket containing V, if any.  
185 
SmallVector 

186  Buckets.resize(N + 1);  
187  for (unsigned i = 1; i <= N; ++i)  
188  Buckets[i] = i;  
189  ⏎  
176  // Initialize IDoms to spanning tree parents.⏎  
177  for (unsigned i = 1; i <= N; ++i) {  
178  const NodePtr V = DT.Vertex[i];  
179  DT.IDoms[V] = DT.Vertex[DT.Info[V].Parent];  
180  }  
181  
182  // Step #2: Calculate the semidominators of all vertices.  
190  183  for (unsigned i = N; i >= 2; i) { 
191  184  NodePtr W = DT.Vertex[i]; 
192  185  auto &WInfo = DT.Info[W]; 
193  186  
194  // Step #2: Implicitly define the immediate dominator of vertices  
195  for (unsigned j = i; Buckets[j] != i; j = Buckets[j]) {  
196  NodePtr V = DT.Vertex[Buckets[j]];  
197 
NodePtr U = Eval 

198  DT.IDoms[V] = DT.Info[U].Semi < i ? U : W;  
199  }  
200  
201  // Step #3: Calculate the semidominators of all vertices  
202  
203 
// 

187  // Initialize the semi dominator to point to the parent node.⏎  
204  188  WInfo.Semi = WInfo.Parent; 
205  189 
for (const auto &N : inverse_children 
206  190  if (DT.Info.count(N)) { // Only if this predecessor is reachable! 
208  192  if (SemiU < WInfo.Semi) 
209  193  WInfo.Semi = SemiU; 
210  194  } 
211  
212  // If V is a nonroot vertex and sdom(V) = parent(V), then idom(V) is  
213  // necessarily parent(V). In this case, set idom(V) here and avoid placing  
214  // V into a bucket.  
215  if (WInfo.Semi == WInfo.Parent) {  
216  DT.IDoms[W] = DT.Vertex[WInfo.Parent];  
217  } else {  
218  Buckets[i] = Buckets[WInfo.Semi];  
219  Buckets[WInfo.Semi] = i;  
220  }  
221  }  
222  
223  if (N >= 1) {  
224  NodePtr Root = DT.Vertex[1];  
225  for (unsigned j = 1; Buckets[j] != 1; j = Buckets[j]) {  
226  NodePtr V = DT.Vertex[Buckets[j]];  
227  DT.IDoms[V] = Root;  
228  }  
229  }  
230  
231 


195  }⏎  
196  
197  
198  // Step #3: Explicitly define the immediate dominator of each vertex.  
199  // IDom[i] = NCA(SDom[i], SpanningTreeParent(i)).  
200  // Note that the parents were stored in IDoms and later got invalidated during  
201  // path compression in Eval.  
232  202  for (unsigned i = 2; i <= N; ++i) { 
233  NodePtr W = DT.Vertex[i];  
234  NodePtr &WIDom = DT.IDoms[W];  
235  if (WIDom != DT.Vertex[DT.Info[W].Semi])  
236 


203  const NodePtr W = DT.Vertex[i];⏎  
204  const auto &WInfo = DT.Info[W];  
205  const unsigned SDomNum = DT.Info[DT.Vertex[WInfo.Semi]].DFSNum;  
206  NodePtr WIDomCandidate = DT.IDoms[W];  
207  while (DT.Info[WIDomCandidate].DFSNum > SDomNum)  
208  WIDomCandidate = DT.IDoms[WIDomCandidate];  
209  
210  DT.IDoms[W] = WIDomCandidate;  
237  211  } 
238  212  
239  213  if (DT.Roots.empty()) return; 