@@ -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 dominators < G : ControlFlowGraph > ( graph : & G ) -> Dominators < 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,10 @@ 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
+
248
+ let time = compute_access_time ( start_node, & immediate_dominators) ;
249
+
250
+ Dominators { start_node, post_order_rank, immediate_dominators, time }
248
251
}
249
252
250
253
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -316,6 +319,7 @@ pub struct Dominators<N: Idx> {
316
319
// possible to get its full list of dominators by looking up the dominator
317
320
// of each dominator. (See the `impl Iterator for Iter` definition).
318
321
immediate_dominators : IndexVec < N , Option < N > > ,
322
+ time : IndexVec < N , Time > ,
319
323
}
320
324
321
325
impl < Node : Idx > Dominators < Node > {
@@ -333,12 +337,7 @@ impl<Node: Idx> Dominators<Node> {
333
337
/// See the `impl Iterator for Iter` definition to understand how this works.
334
338
pub fn dominators ( & self , node : Node ) -> Iter < ' _ , Node > {
335
339
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)
340
+ Iter { dom_tree : self , node : Some ( node) }
342
341
}
343
342
344
343
/// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
@@ -348,10 +347,22 @@ impl<Node: Idx> Dominators<Node> {
348
347
pub fn rank_partial_cmp ( & self , lhs : Node , rhs : Node ) -> Option < Ordering > {
349
348
self . post_order_rank [ rhs] . partial_cmp ( & self . post_order_rank [ lhs] )
350
349
}
350
+
351
+ /// Returns true if `a` dominates `b`.
352
+ ///
353
+ /// # Panics
354
+ ///
355
+ /// Panics if `b` is unreachable.
356
+ pub fn dominates ( & self , a : Node , b : Node ) -> bool {
357
+ let a = self . time [ a] ;
358
+ let b = self . time [ b] ;
359
+ assert ! ( b. start != 0 , "node {b:?} is not reachable" ) ;
360
+ a. start <= b. start && b. finish <= a. finish
361
+ }
351
362
}
352
363
353
364
pub struct Iter < ' dom , Node : Idx > {
354
- dominators : & ' dom Dominators < Node > ,
365
+ dom_tree : & ' dom Dominators < Node > ,
355
366
node : Option < Node > ,
356
367
}
357
368
@@ -360,10 +371,74 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
360
371
361
372
fn next ( & mut self ) -> Option < Self :: Item > {
362
373
if let Some ( node) = self . node {
363
- self . node = self . dominators . immediate_dominator ( node) ;
374
+ self . node = self . dom_tree . immediate_dominator ( node) ;
364
375
Some ( node)
365
376
} else {
366
377
None
367
378
}
368
379
}
369
380
}
381
+
382
+ /// Describes the number of vertices discovered at the time when processing of a particular vertex
383
+ /// started and when it finished. Both values are zero for unreachable vertices.
384
+ #[ derive( Copy , Clone , Default , Debug ) ]
385
+ struct Time {
386
+ start : u32 ,
387
+ finish : u32 ,
388
+ }
389
+
390
+ fn compute_access_time < N : Idx > (
391
+ start_node : N ,
392
+ immediate_dominators : & IndexSlice < N , Option < N > > ,
393
+ ) -> IndexVec < N , Time > {
394
+ // Transpose the dominator tree edges, so that child nodes of vertex v are stored in
395
+ // node[edges[v].start..edges[v].end].
396
+ let mut edges: IndexVec < N , std:: ops:: Range < u32 > > =
397
+ IndexVec :: from_elem ( 0 ..0 , immediate_dominators) ;
398
+ for & idom in immediate_dominators. iter ( ) {
399
+ if let Some ( idom) = idom {
400
+ edges[ idom] . end += 1 ;
401
+ }
402
+ }
403
+ let mut m = 0 ;
404
+ for e in edges. iter_mut ( ) {
405
+ m += e. end ;
406
+ e. start = m;
407
+ e. end = m;
408
+ }
409
+ let mut node = IndexVec :: from_elem_n ( Idx :: new ( 0 ) , m. try_into ( ) . unwrap ( ) ) ;
410
+ for ( i, & idom) in immediate_dominators. iter_enumerated ( ) {
411
+ if let Some ( idom) = idom {
412
+ edges[ idom] . start -= 1 ;
413
+ node[ edges[ idom] . start ] = i;
414
+ }
415
+ }
416
+
417
+ // Perform a depth-first search of the dominator tree. Record the number of vertices discovered
418
+ // when vertex v is discovered first as time[v].start, and when its processing is finished as
419
+ // time[v].finish.
420
+ let mut time: IndexVec < N , Time > = IndexVec :: from_elem ( Time :: default ( ) , immediate_dominators) ;
421
+ let mut stack = Vec :: new ( ) ;
422
+
423
+ let mut discovered = 1 ;
424
+ stack. push ( start_node) ;
425
+ time[ start_node] . start = discovered;
426
+
427
+ while let Some ( & i) = stack. last ( ) {
428
+ let e = & mut edges[ i] ;
429
+ if e. start == e. end {
430
+ // Finish processing vertex i.
431
+ time[ i] . finish = discovered;
432
+ stack. pop ( ) ;
433
+ } else {
434
+ let j = node[ e. start ] ;
435
+ e. start += 1 ;
436
+ // Start processing vertex j.
437
+ discovered += 1 ;
438
+ time[ j] . start = discovered;
439
+ stack. push ( j) ;
440
+ }
441
+ }
442
+
443
+ time
444
+ }
0 commit comments