11use std:: cmp:: Ordering ;
22use std:: collections:: VecDeque ;
3+ use std:: iter;
34use std:: ops:: { Index , IndexMut } ;
45
56use rustc_data_structures:: captures:: Captures ;
67use rustc_data_structures:: fx:: FxHashSet ;
7- use rustc_data_structures:: graph:: dominators:: { self , Dominators } ;
8+ use rustc_data_structures:: graph:: dominators:: Dominators ;
89use rustc_data_structures:: graph:: { self , DirectedGraph , StartNode } ;
910use rustc_index:: IndexVec ;
1011use rustc_index:: bit_set:: BitSet ;
@@ -20,11 +21,17 @@ pub(crate) struct CoverageGraph {
2021 bb_to_bcb : IndexVec < BasicBlock , Option < BasicCoverageBlock > > ,
2122 pub ( crate ) successors : IndexVec < BasicCoverageBlock , Vec < BasicCoverageBlock > > ,
2223 pub ( crate ) predecessors : IndexVec < BasicCoverageBlock , Vec < BasicCoverageBlock > > ,
24+
2325 dominators : Option < Dominators < BasicCoverageBlock > > ,
2426 /// Allows nodes to be compared in some total order such that _if_
2527 /// `a` dominates `b`, then `a < b`. If neither node dominates the other,
2628 /// their relative order is consistent but arbitrary.
2729 dominator_order_rank : IndexVec < BasicCoverageBlock , u32 > ,
30+ /// A loop header is a node that dominates one or more of its predecessors.
31+ is_loop_header : BitSet < BasicCoverageBlock > ,
32+ /// For each node, the loop header node of its nearest enclosing loop.
33+ /// This forms a linked list that can be traversed to find all enclosing loops.
34+ enclosing_loop_header : IndexVec < BasicCoverageBlock , Option < BasicCoverageBlock > > ,
2835}
2936
3037impl CoverageGraph {
@@ -66,17 +73,38 @@ impl CoverageGraph {
6673 predecessors,
6774 dominators : None ,
6875 dominator_order_rank : IndexVec :: from_elem_n ( 0 , num_nodes) ,
76+ is_loop_header : BitSet :: new_empty ( num_nodes) ,
77+ enclosing_loop_header : IndexVec :: from_elem_n ( None , num_nodes) ,
6978 } ;
7079 assert_eq ! ( num_nodes, this. num_nodes( ) ) ;
7180
72- this. dominators = Some ( dominators:: dominators ( & this) ) ;
81+ // Set the dominators first, because later init steps rely on them.
82+ this. dominators = Some ( graph:: dominators:: dominators ( & this) ) ;
7383
74- // The dominator rank of each node is just its index in a reverse-postorder traversal.
75- let reverse_post_order = graph:: iterate:: reverse_post_order ( & this, this. start_node ( ) ) ;
84+ // Iterate over all nodes, such that dominating nodes are visited before
85+ // the nodes they dominate. Either preorder or reverse postorder is fine.
86+ let dominator_order = graph:: iterate:: reverse_post_order ( & this, this. start_node ( ) ) ;
7687 // The coverage graph is created by traversal, so all nodes are reachable.
77- assert_eq ! ( reverse_post_order. len( ) , this. num_nodes( ) ) ;
78- for ( rank, bcb) in ( 0u32 ..) . zip ( reverse_post_order) {
88+ assert_eq ! ( dominator_order. len( ) , this. num_nodes( ) ) ;
89+ for ( rank, bcb) in ( 0u32 ..) . zip ( dominator_order) {
90+ // The dominator rank of each node is its index in a dominator-order traversal.
7991 this. dominator_order_rank [ bcb] = rank;
92+
93+ // A node is a loop header if it dominates any of its predecessors.
94+ if this. reloop_predecessors ( bcb) . next ( ) . is_some ( ) {
95+ this. is_loop_header . insert ( bcb) ;
96+ }
97+
98+ // If the immediate dominator is a loop header, that's our enclosing loop.
99+ // Otherwise, inherit the immediate dominator's enclosing loop.
100+ // (Dominator order ensures that we already processed the dominator.)
101+ if let Some ( dom) = this. dominators ( ) . immediate_dominator ( bcb) {
102+ this. enclosing_loop_header [ bcb] = this
103+ . is_loop_header
104+ . contains ( dom)
105+ . then_some ( dom)
106+ . or_else ( || this. enclosing_loop_header [ dom] ) ;
107+ }
80108 }
81109
82110 // The coverage graph's entry-point node (bcb0) always starts with bb0,
@@ -172,9 +200,14 @@ impl CoverageGraph {
172200 if bb. index ( ) < self . bb_to_bcb . len ( ) { self . bb_to_bcb [ bb] } else { None }
173201 }
174202
203+ #[ inline( always) ]
204+ fn dominators ( & self ) -> & Dominators < BasicCoverageBlock > {
205+ self . dominators . as_ref ( ) . unwrap ( )
206+ }
207+
175208 #[ inline( always) ]
176209 pub ( crate ) fn dominates ( & self , dom : BasicCoverageBlock , node : BasicCoverageBlock ) -> bool {
177- self . dominators . as_ref ( ) . unwrap ( ) . dominates ( dom, node)
210+ self . dominators ( ) . dominates ( dom, node)
178211 }
179212
180213 #[ inline( always) ]
@@ -214,6 +247,36 @@ impl CoverageGraph {
214247 None
215248 }
216249 }
250+
251+ /// For each loop that contains the given node, yields the "loop header"
252+ /// node representing that loop, from innermost to outermost. If the given
253+ /// node is itself a loop header, it is yielded first.
254+ pub ( crate ) fn loop_headers_containing (
255+ & self ,
256+ bcb : BasicCoverageBlock ,
257+ ) -> impl Iterator < Item = BasicCoverageBlock > + Captures < ' _ > {
258+ let self_if_loop_header = self . is_loop_header . contains ( bcb) . then_some ( bcb) . into_iter ( ) ;
259+
260+ let mut curr = Some ( bcb) ;
261+ let strictly_enclosing = iter:: from_fn ( move || {
262+ let enclosing = self . enclosing_loop_header [ curr?] ;
263+ curr = enclosing;
264+ enclosing
265+ } ) ;
266+
267+ self_if_loop_header. chain ( strictly_enclosing)
268+ }
269+
270+ /// For the given node, yields the subset of its predecessor nodes that
271+ /// it dominates. If that subset is non-empty, the node is a "loop header",
272+ /// and each of those predecessors represents an in-edge that jumps back to
273+ /// the top of its loop.
274+ pub ( crate ) fn reloop_predecessors (
275+ & self ,
276+ to_bcb : BasicCoverageBlock ,
277+ ) -> impl Iterator < Item = BasicCoverageBlock > + Captures < ' _ > {
278+ self . predecessors [ to_bcb] . iter ( ) . copied ( ) . filter ( move |& pred| self . dominates ( to_bcb, pred) )
279+ }
217280}
218281
219282impl Index < BasicCoverageBlock > for CoverageGraph {
@@ -439,15 +502,12 @@ struct TraversalContext {
439502pub ( crate ) struct TraverseCoverageGraphWithLoops < ' a > {
440503 basic_coverage_blocks : & ' a CoverageGraph ,
441504
442- backedges : IndexVec < BasicCoverageBlock , Vec < BasicCoverageBlock > > ,
443505 context_stack : Vec < TraversalContext > ,
444506 visited : BitSet < BasicCoverageBlock > ,
445507}
446508
447509impl < ' a > TraverseCoverageGraphWithLoops < ' a > {
448510 pub ( crate ) fn new ( basic_coverage_blocks : & ' a CoverageGraph ) -> Self {
449- let backedges = find_loop_backedges ( basic_coverage_blocks) ;
450-
451511 let worklist = VecDeque :: from ( [ basic_coverage_blocks. start_node ( ) ] ) ;
452512 let context_stack = vec ! [ TraversalContext { loop_header: None , worklist } ] ;
453513
@@ -456,17 +516,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
456516 // of the stack as loops are entered, and popped off of the stack when a loop's worklist is
457517 // exhausted.
458518 let visited = BitSet :: new_empty ( basic_coverage_blocks. num_nodes ( ) ) ;
459- Self { basic_coverage_blocks, backedges, context_stack, visited }
460- }
461-
462- /// For each loop on the loop context stack (top-down), yields a list of BCBs
463- /// within that loop that have an outgoing edge back to the loop header.
464- pub ( crate ) fn reloop_bcbs_per_loop ( & self ) -> impl Iterator < Item = & [ BasicCoverageBlock ] > {
465- self . context_stack
466- . iter ( )
467- . rev ( )
468- . filter_map ( |context| context. loop_header )
469- . map ( |header_bcb| self . backedges [ header_bcb] . as_slice ( ) )
519+ Self { basic_coverage_blocks, context_stack, visited }
470520 }
471521
472522 pub ( crate ) fn next ( & mut self ) -> Option < BasicCoverageBlock > {
@@ -488,7 +538,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
488538 }
489539 debug ! ( "Visiting {bcb:?}" ) ;
490540
491- if self . backedges [ bcb ] . len ( ) > 0 {
541+ if self . basic_coverage_blocks . is_loop_header . contains ( bcb ) {
492542 debug ! ( "{bcb:?} is a loop header! Start a new TraversalContext..." ) ;
493543 self . context_stack
494544 . push ( TraversalContext { loop_header : Some ( bcb) , worklist : VecDeque :: new ( ) } ) ;
@@ -566,29 +616,6 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
566616 }
567617}
568618
569- fn find_loop_backedges (
570- basic_coverage_blocks : & CoverageGraph ,
571- ) -> IndexVec < BasicCoverageBlock , Vec < BasicCoverageBlock > > {
572- let num_bcbs = basic_coverage_blocks. num_nodes ( ) ;
573- let mut backedges = IndexVec :: from_elem_n ( Vec :: < BasicCoverageBlock > :: new ( ) , num_bcbs) ;
574-
575- // Identify loops by their backedges.
576- for ( bcb, _) in basic_coverage_blocks. iter_enumerated ( ) {
577- for & successor in & basic_coverage_blocks. successors [ bcb] {
578- if basic_coverage_blocks. dominates ( successor, bcb) {
579- let loop_header = successor;
580- let backedge_from_bcb = bcb;
581- debug ! (
582- "Found BCB backedge: {:?} -> loop_header: {:?}" ,
583- backedge_from_bcb, loop_header
584- ) ;
585- backedges[ loop_header] . push ( backedge_from_bcb) ;
586- }
587- }
588- }
589- backedges
590- }
591-
592619fn short_circuit_preorder < ' a , ' tcx , F , Iter > (
593620 body : & ' a mir:: Body < ' tcx > ,
594621 filtered_successors : F ,
0 commit comments