@@ -26,7 +26,7 @@ rustc_index::newtype_index! {
26
26
struct PreorderIndex { }
27
27
}
28
28
29
- pub fn dominators < G : ControlFlowGraph > ( graph : G ) -> Dominators < G :: Node > {
29
+ pub fn dominator_tree < G : ControlFlowGraph > ( graph : G ) -> DominatorTree < G :: Node > {
30
30
// compute the post order index (rank) for each node
31
31
let mut post_order_rank = IndexVec :: from_elem_n ( 0 , graph. num_nodes ( ) ) ;
32
32
@@ -244,7 +244,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
244
244
245
245
let start_node = graph. start_node ( ) ;
246
246
immediate_dominators[ start_node] = None ;
247
- Dominators { start_node, post_order_rank, immediate_dominators }
247
+ DominatorTree { start_node, post_order_rank, immediate_dominators }
248
248
}
249
249
250
250
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -309,16 +309,18 @@ fn compress(
309
309
310
310
/// Tracks the list of dominators for each node.
311
311
#[ derive( Clone , Debug ) ]
312
- pub struct Dominators < N : Idx > {
312
+ pub struct DominatorTree < N : Idx > {
313
313
start_node : N ,
314
314
post_order_rank : IndexVec < N , usize > ,
315
315
// Even though we track only the immediate dominator of each node, it's
316
316
// possible to get its full list of dominators by looking up the dominator
317
317
// of each dominator. (See the `impl Iterator for Iter` definition).
318
+ //
319
+ // Note: immediate_dominators[root] is Some(root)!
318
320
immediate_dominators : IndexVec < N , Option < N > > ,
319
321
}
320
322
321
- impl < Node : Idx > Dominators < Node > {
323
+ impl < Node : Idx > DominatorTree < Node > {
322
324
/// Returns true if node is reachable from the start node.
323
325
pub fn is_reachable ( & self , node : Node ) -> bool {
324
326
node == self . start_node || self . immediate_dominators [ node] . is_some ( )
@@ -333,12 +335,7 @@ impl<Node: Idx> Dominators<Node> {
333
335
/// See the `impl Iterator for Iter` definition to understand how this works.
334
336
pub fn dominators ( & self , node : Node ) -> Iter < ' _ , Node > {
335
337
assert ! ( self . is_reachable( node) , "node {node:?} is not reachable" ) ;
336
- Iter { dominators : self , node : Some ( node) }
337
- }
338
-
339
- pub fn dominates ( & self , dom : Node , node : Node ) -> bool {
340
- // FIXME -- could be optimized by using post-order-rank
341
- self . dominators ( node) . any ( |n| n == dom)
338
+ Iter { dom_tree : self , node : Some ( node) }
342
339
}
343
340
344
341
/// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
@@ -351,7 +348,7 @@ impl<Node: Idx> Dominators<Node> {
351
348
}
352
349
353
350
pub struct Iter < ' dom , Node : Idx > {
354
- dominators : & ' dom Dominators < Node > ,
351
+ dom_tree : & ' dom DominatorTree < Node > ,
355
352
node : Option < Node > ,
356
353
}
357
354
@@ -360,10 +357,96 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
360
357
361
358
fn next ( & mut self ) -> Option < Self :: Item > {
362
359
if let Some ( node) = self . node {
363
- self . node = self . dominators . immediate_dominator ( node) ;
360
+ self . node = self . dom_tree . immediate_dominator ( node) ;
364
361
Some ( node)
365
362
} else {
366
363
None
367
364
}
368
365
}
369
366
}
367
+
368
+ #[ derive( Clone , Debug ) ]
369
+ pub struct Dominators < Node : Idx > {
370
+ time : IndexVec < Node , Time > ,
371
+ }
372
+
373
+ /// Describes the number of vertices discovered at the time when processing of a particular vertex
374
+ /// started and when it finished. Both values are zero for unreachable vertices.
375
+ #[ derive( Copy , Clone , Default , Debug ) ]
376
+ struct Time {
377
+ start : u32 ,
378
+ finish : u32 ,
379
+ }
380
+
381
+ impl < Node : Idx > Dominators < Node > {
382
+ pub fn dummy ( ) -> Self {
383
+ Self { time : Default :: default ( ) }
384
+ }
385
+
386
+ /// Returns true if `a` dominates `b`.
387
+ ///
388
+ /// # Panics
389
+ ///
390
+ /// Panics if `b` is unreachable.
391
+ pub fn dominates ( & self , a : Node , b : Node ) -> bool {
392
+ let a = self . time [ a] ;
393
+ let b = self . time [ b] ;
394
+ assert ! ( b. start != 0 , "node {b:?} is not reachable" ) ;
395
+ a. start <= b. start && b. finish <= a. finish
396
+ }
397
+ }
398
+
399
+ pub fn dominators < N : Idx > ( tree : & DominatorTree < N > ) -> Dominators < N > {
400
+ let DominatorTree { start_node, ref immediate_dominators, post_order_rank : _ } = * tree;
401
+
402
+ // Transpose the dominator tree edges, so that child nodes of vertex v are stored in
403
+ // node[edges[v].start..edges[y].end].
404
+ let mut edges: IndexVec < N , std:: ops:: Range < u32 > > =
405
+ IndexVec :: from_elem ( 0 ..0 , immediate_dominators) ;
406
+ for & idom in immediate_dominators. iter ( ) {
407
+ if let Some ( idom) = idom {
408
+ edges[ idom] . end += 1 ;
409
+ }
410
+ }
411
+ let mut m = 0 ;
412
+ for e in edges. iter_mut ( ) {
413
+ m += e. end ;
414
+ e. start = m;
415
+ e. end = m;
416
+ }
417
+ let mut node = IndexVec :: from_elem_n ( Idx :: new ( 0 ) , m. try_into ( ) . unwrap ( ) ) ;
418
+ for ( i, & idom) in immediate_dominators. iter_enumerated ( ) {
419
+ if let Some ( idom) = idom {
420
+ edges[ idom] . start -= 1 ;
421
+ node[ edges[ idom] . start ] = i;
422
+ }
423
+ }
424
+
425
+ // Perform a depth-first search of the dominator tree. Record the number of vertices discovered
426
+ // when vertex v is discovered first as time[v].start, and when its processing is finished as
427
+ // time[v].finish.
428
+ let mut time: IndexVec < N , Time > = IndexVec :: from_elem ( Time :: default ( ) , immediate_dominators) ;
429
+ let mut stack = Vec :: new ( ) ;
430
+
431
+ let mut discovered = 1 ;
432
+ stack. push ( start_node) ;
433
+ time[ start_node] . start = discovered;
434
+
435
+ while let Some ( & i) = stack. last ( ) {
436
+ let e = & mut edges[ i] ;
437
+ if e. start == e. end {
438
+ // Finish processing vertex i.
439
+ time[ i] . finish = discovered;
440
+ stack. pop ( ) ;
441
+ } else {
442
+ let j = node[ e. start ] ;
443
+ e. start += 1 ;
444
+ // Start processing vertex j.
445
+ discovered += 1 ;
446
+ time[ j] . start = discovered;
447
+ stack. push ( j) ;
448
+ }
449
+ }
450
+
451
+ Dominators { time }
452
+ }
0 commit comments