@@ -25,7 +25,7 @@ rustc_index::newtype_index! {
25
25
struct PreorderIndex { }
26
26
}
27
27
28
- pub fn dominators < G : ControlFlowGraph > ( graph : G ) -> Dominators < G :: Node > {
28
+ pub fn dominator_tree < G : ControlFlowGraph > ( graph : G ) -> DominatorTree < G :: Node > {
29
29
// compute the post order index (rank) for each node
30
30
let mut post_order_rank = IndexVec :: from_elem_n ( 0 , graph. num_nodes ( ) ) ;
31
31
@@ -201,7 +201,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
201
201
immediate_dominators[ * node] = Some ( pre_order_to_real[ idom[ idx] ] ) ;
202
202
}
203
203
204
- Dominators { post_order_rank, immediate_dominators }
204
+ DominatorTree { post_order_rank, immediate_dominators }
205
205
}
206
206
207
207
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -265,13 +265,14 @@ fn compress(
265
265
}
266
266
267
267
#[ derive( Clone , Debug ) ]
268
- pub struct Dominators < N : Idx > {
268
+ pub struct DominatorTree < N : Idx > {
269
269
post_order_rank : IndexVec < N , usize > ,
270
+ // Note: immediate_dominators[root] is Some(root)!
270
271
immediate_dominators : IndexVec < N , Option < N > > ,
271
272
}
272
273
273
- impl < Node : Idx > Dominators < Node > {
274
- pub fn is_reachable ( & self , node : Node ) -> bool {
274
+ impl < Node : Idx > DominatorTree < Node > {
275
+ fn is_reachable ( & self , node : Node ) -> bool {
275
276
self . immediate_dominators [ node] . is_some ( )
276
277
}
277
278
@@ -282,25 +283,12 @@ impl<Node: Idx> Dominators<Node> {
282
283
283
284
pub fn dominators ( & self , node : Node ) -> Iter < ' _ , Node > {
284
285
assert ! ( self . is_reachable( node) , "node {node:?} is not reachable" ) ;
285
- Iter { dominators : self , node : Some ( node) }
286
- }
287
-
288
- pub fn dominates ( & self , dom : Node , node : Node ) -> bool {
289
- // FIXME -- could be optimized by using post-order-rank
290
- self . dominators ( node) . any ( |n| n == dom)
291
- }
292
-
293
- /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
294
- /// relationship, the dominator will always precede the dominated. (The relative ordering
295
- /// of two unrelated nodes will also be consistent, but otherwise the order has no
296
- /// meaning.) This method cannot be used to determine if either Node dominates the other.
297
- pub fn rank_partial_cmp ( & self , lhs : Node , rhs : Node ) -> Option < Ordering > {
298
- self . post_order_rank [ rhs] . partial_cmp ( & self . post_order_rank [ lhs] )
286
+ Iter { dom_tree : self , node : Some ( node) }
299
287
}
300
288
}
301
289
302
290
pub struct Iter < ' dom , Node : Idx > {
303
- dominators : & ' dom Dominators < Node > ,
291
+ dom_tree : & ' dom DominatorTree < Node > ,
304
292
node : Option < Node > ,
305
293
}
306
294
@@ -309,7 +297,7 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
309
297
310
298
fn next ( & mut self ) -> Option < Self :: Item > {
311
299
if let Some ( node) = self . node {
312
- let dom = self . dominators . immediate_dominator ( node) ;
300
+ let dom = self . dom_tree . immediate_dominator ( node) ;
313
301
if dom == node {
314
302
self . node = None ; // reached the root
315
303
} else {
@@ -321,3 +309,101 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
321
309
}
322
310
}
323
311
}
312
+
313
+ #[ derive( Clone , Debug ) ]
314
+ pub struct Dominators < Node : Idx > {
315
+ time : IndexVec < Node , Time > ,
316
+ post_order_rank : IndexVec < Node , usize > ,
317
+ }
318
+
319
+ /// Describes the number of vertices discovered at the time when processing of a particular vertex
320
+ /// started and when it finished. Both values are zero for unreachable vertices.
321
+ #[ derive( Copy , Clone , Default , Debug ) ]
322
+ struct Time {
323
+ start : u32 ,
324
+ finish : u32 ,
325
+ }
326
+
327
+ impl < Node : Idx > Dominators < Node > {
328
+ pub fn dummy ( ) -> Self {
329
+ Self { time : Default :: default ( ) , post_order_rank : Default :: default ( ) }
330
+ }
331
+
332
+ /// Returns true if `a` dominates `b`.
333
+ ///
334
+ /// # Panics
335
+ ///
336
+ /// Panics if `b` is unreachable.
337
+ pub fn dominates ( & self , a : Node , b : Node ) -> bool {
338
+ let a = self . time [ a] ;
339
+ let b = self . time [ b] ;
340
+ assert ! ( b. start != 0 , "node {b:?} is not reachable" ) ;
341
+ a. start <= b. start && b. finish <= a. finish
342
+ }
343
+
344
+ /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
345
+ /// relationship, the dominator will always precede the dominated. (The relative ordering
346
+ /// of two unrelated nodes will also be consistent, but otherwise the order has no
347
+ /// meaning.) This method cannot be used to determine if either Node dominates the other.
348
+ pub fn rank_partial_cmp ( & self , lhs : Node , rhs : Node ) -> Option < Ordering > {
349
+ self . post_order_rank [ rhs] . partial_cmp ( & self . post_order_rank [ lhs] )
350
+ }
351
+ }
352
+
353
+ pub fn dominators < G : Copy + ControlFlowGraph > ( graph : G ) -> Dominators < G :: Node > {
354
+ let DominatorTree { mut immediate_dominators, post_order_rank } = dominator_tree ( graph) ;
355
+
356
+ immediate_dominators[ graph. start_node ( ) ] = None ;
357
+
358
+ // Transpose the dominator tree edges, so that child nodes of vertex v are stored in
359
+ // node[edges[v].start..edges[y].end].
360
+ let mut edges: IndexVec < G :: Node , std:: ops:: Range < u32 > > =
361
+ IndexVec :: from_elem_n ( 0 ..0 , graph. num_nodes ( ) ) ;
362
+ for & idom in immediate_dominators. iter ( ) {
363
+ if let Some ( idom) = idom {
364
+ edges[ idom] . end += 1 ;
365
+ }
366
+ }
367
+ let mut m = 0 ;
368
+ for e in edges. iter_mut ( ) {
369
+ m += e. end ;
370
+ e. start = m;
371
+ e. end = m;
372
+ }
373
+ let mut node = IndexVec :: from_elem_n ( Idx :: new ( 0 ) , m. try_into ( ) . unwrap ( ) ) ;
374
+ for ( i, & idom) in immediate_dominators. iter_enumerated ( ) {
375
+ if let Some ( idom) = idom {
376
+ edges[ idom] . start -= 1 ;
377
+ node[ edges[ idom] . start ] = i;
378
+ }
379
+ }
380
+
381
+ // Perform a depth-first search of the dominator tree. Record the number of vertices discovered
382
+ // when vertex v is discovered first as time[v].start, and when its processing is finished as
383
+ // time[v].finish.
384
+ let mut time: IndexVec < G :: Node , Time > =
385
+ IndexVec :: from_elem_n ( Time :: default ( ) , graph. num_nodes ( ) ) ;
386
+ let mut stack = Vec :: new ( ) ;
387
+
388
+ let mut discovered = 1 ;
389
+ stack. push ( graph. start_node ( ) ) ;
390
+ time[ graph. start_node ( ) ] . start = discovered;
391
+
392
+ while let Some ( & i) = stack. last ( ) {
393
+ let e = & mut edges[ i] ;
394
+ if e. start == e. end {
395
+ // Finish processing vertex i.
396
+ time[ i] . finish = discovered;
397
+ stack. pop ( ) ;
398
+ } else {
399
+ let j = node[ e. start ] ;
400
+ e. start += 1 ;
401
+ // Start processing vertex j.
402
+ discovered += 1 ;
403
+ time[ j] . start = discovered;
404
+ stack. push ( j) ;
405
+ }
406
+ }
407
+
408
+ Dominators { time, post_order_rank }
409
+ }
0 commit comments