@@ -26,7 +26,42 @@ rustc_index::newtype_index! {
2626 struct PreorderIndex { }
2727}
2828
29- pub fn dominators < G : ControlFlowGraph > ( graph : & G ) -> Dominators < G :: Node > {
29+ #[ derive( Clone , Debug ) ]
30+ pub struct Dominators < Node : Idx > {
31+ kind : Kind < Node > ,
32+ }
33+
34+ #[ derive( Clone , Debug ) ]
35+ enum Kind < Node : Idx > {
36+ /// A representation optimized for a small path graphs.
37+ Path ( usize ) ,
38+ General ( Inner < Node > ) ,
39+ }
40+
41+ pub fn dominators < G : ControlFlowGraph > ( g : & G ) -> Dominators < G :: Node > {
42+ // We often encounter MIR bodies with 1 or 2 basic blocks. Special case the dominators
43+ // computation and representation for those cases.
44+ if is_small_path_graph ( g) {
45+ Dominators { kind : Kind :: Path ( g. num_nodes ( ) ) }
46+ } else {
47+ Dominators { kind : Kind :: General ( dominators_impl ( g) ) }
48+ }
49+ }
50+
51+ fn is_small_path_graph < G : ControlFlowGraph > ( g : & G ) -> bool {
52+ if g. start_node ( ) . index ( ) != 0 {
53+ return false ;
54+ }
55+ if g. num_nodes ( ) == 1 {
56+ return true ;
57+ }
58+ if g. num_nodes ( ) == 2 {
59+ return g. successors ( g. start_node ( ) ) . any ( |n| n. index ( ) == 1 ) ;
60+ }
61+ false
62+ }
63+
64+ fn dominators_impl < G : ControlFlowGraph > ( graph : & G ) -> Inner < G :: Node > {
3065 // compute the post order index (rank) for each node
3166 let mut post_order_rank = IndexVec :: from_elem_n ( 0 , graph. num_nodes ( ) ) ;
3267
@@ -245,7 +280,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
245280
246281 let time = compute_access_time ( start_node, & immediate_dominators) ;
247282
248- Dominators { post_order_rank, immediate_dominators, time }
283+ Inner { post_order_rank, immediate_dominators, time }
249284}
250285
251286/// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -310,7 +345,7 @@ fn compress(
310345
311346/// Tracks the list of dominators for each node.
312347#[ derive( Clone , Debug ) ]
313- pub struct Dominators < N : Idx > {
348+ struct Inner < N : Idx > {
314349 post_order_rank : IndexVec < N , usize > ,
315350 // Even though we track only the immediate dominator of each node, it's
316351 // possible to get its full list of dominators by looking up the dominator
@@ -322,12 +357,24 @@ pub struct Dominators<N: Idx> {
322357impl < Node : Idx > Dominators < Node > {
323358 /// Returns true if node is reachable from the start node.
324359 pub fn is_reachable ( & self , node : Node ) -> bool {
325- self . time [ node] . start != 0
360+ match & self . kind {
361+ Kind :: Path ( _) => true ,
362+ Kind :: General ( g) => g. time [ node] . start != 0 ,
363+ }
326364 }
327365
328366 /// Returns the immediate dominator of node, if any.
329367 pub fn immediate_dominator ( & self , node : Node ) -> Option < Node > {
330- self . immediate_dominators [ node]
368+ match & self . kind {
369+ Kind :: Path ( n) => {
370+ if 0 < node. index ( ) && node. index ( ) < * n {
371+ Some ( Node :: new ( node. index ( ) - 1 ) )
372+ } else {
373+ None
374+ }
375+ }
376+ Kind :: General ( g) => g. immediate_dominators [ node] ,
377+ }
331378 }
332379
333380 /// Provides an iterator over each dominator up the CFG, for the given Node.
@@ -342,7 +389,10 @@ impl<Node: Idx> Dominators<Node> {
342389 /// of two unrelated nodes will also be consistent, but otherwise the order has no
343390 /// meaning.) This method cannot be used to determine if either Node dominates the other.
344391 pub fn cmp_in_dominator_order ( & self , lhs : Node , rhs : Node ) -> Ordering {
345- self . post_order_rank [ rhs] . cmp ( & self . post_order_rank [ lhs] )
392+ match & self . kind {
393+ Kind :: Path ( _) => lhs. index ( ) . cmp ( & rhs. index ( ) ) ,
394+ Kind :: General ( g) => g. post_order_rank [ rhs] . cmp ( & g. post_order_rank [ lhs] ) ,
395+ }
346396 }
347397
348398 /// Returns true if `a` dominates `b`.
@@ -351,10 +401,15 @@ impl<Node: Idx> Dominators<Node> {
351401 ///
352402 /// Panics if `b` is unreachable.
353403 pub fn dominates ( & self , a : Node , b : Node ) -> bool {
354- let a = self . time [ a] ;
355- let b = self . time [ b] ;
356- assert ! ( b. start != 0 , "node {b:?} is not reachable" ) ;
357- a. start <= b. start && b. finish <= a. finish
404+ match & self . kind {
405+ Kind :: Path ( _) => a. index ( ) <= b. index ( ) ,
406+ Kind :: General ( g) => {
407+ let a = g. time [ a] ;
408+ let b = g. time [ b] ;
409+ assert ! ( b. start != 0 , "node {b:?} is not reachable" ) ;
410+ a. start <= b. start && b. finish <= a. finish
411+ }
412+ }
358413 }
359414}
360415
0 commit comments