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,37 @@ 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 .
84+ // Reverse postorder visits dominating nodes before the nodes they dominate .
7585 let reverse_post_order = graph:: iterate:: reverse_post_order ( & this, this. start_node ( ) ) ;
7686 // The coverage graph is created by traversal, so all nodes are reachable.
7787 assert_eq ! ( reverse_post_order. len( ) , this. num_nodes( ) ) ;
7888 for ( rank, bcb) in ( 0u32 ..) . zip ( reverse_post_order) {
89+ // The dominator rank of each node is just its index in a reverse-postorder traversal.
7990 this. dominator_order_rank [ bcb] = rank;
91+
92+ // A node is a loop header if it dominates any of its predecessors.
93+ if this. reloop_predecessors ( bcb) . next ( ) . is_some ( ) {
94+ this. is_loop_header . insert ( bcb) ;
95+ }
96+
97+ // If the immediate dominator is a loop header, that's our enclosing loop.
98+ // Otherwise, inherit the immediate dominator's enclosing loop.
99+ // (Reverse postorder ensures that we already processed the dominator.)
100+ if let Some ( dom) = this. dominators ( ) . immediate_dominator ( bcb) {
101+ this. enclosing_loop_header [ bcb] = this
102+ . is_loop_header
103+ . contains ( dom)
104+ . then_some ( dom)
105+ . or_else ( || this. enclosing_loop_header [ dom] ) ;
106+ }
80107 }
81108
82109 // The coverage graph's entry-point node (bcb0) always starts with bb0,
@@ -172,9 +199,14 @@ impl CoverageGraph {
172199 if bb. index ( ) < self . bb_to_bcb . len ( ) { self . bb_to_bcb [ bb] } else { None }
173200 }
174201
202+ #[ inline( always) ]
203+ fn dominators ( & self ) -> & Dominators < BasicCoverageBlock > {
204+ self . dominators . as_ref ( ) . unwrap ( )
205+ }
206+
175207 #[ inline( always) ]
176208 pub ( crate ) fn dominates ( & self , dom : BasicCoverageBlock , node : BasicCoverageBlock ) -> bool {
177- self . dominators . as_ref ( ) . unwrap ( ) . dominates ( dom, node)
209+ self . dominators ( ) . dominates ( dom, node)
178210 }
179211
180212 #[ inline( always) ]
@@ -214,6 +246,36 @@ impl CoverageGraph {
214246 None
215247 }
216248 }
249+
250+ /// For each loop that contains the given node, yields the "loop header"
251+ /// node representing that loop, from innermost to outermost. If the given
252+ /// node is itself a loop header, it is yielded first.
253+ pub ( crate ) fn loop_headers_containing (
254+ & self ,
255+ bcb : BasicCoverageBlock ,
256+ ) -> impl Iterator < Item = BasicCoverageBlock > + Captures < ' _ > {
257+ let self_if_loop_header = self . is_loop_header . contains ( bcb) . then_some ( bcb) . into_iter ( ) ;
258+
259+ let mut curr = Some ( bcb) ;
260+ let strictly_enclosing = iter:: from_fn ( move || {
261+ let enclosing = self . enclosing_loop_header [ curr?] ;
262+ curr = enclosing;
263+ enclosing
264+ } ) ;
265+
266+ self_if_loop_header. chain ( strictly_enclosing)
267+ }
268+
269+ /// For the given node, yields the subset of its predecessor nodes that
270+ /// it dominates. If that subset is non-empty, the node is a "loop header",
271+ /// and each of those predecessors represents an in-edge that jumps back to
272+ /// the top of its loop.
273+ pub ( crate ) fn reloop_predecessors (
274+ & self ,
275+ to_bcb : BasicCoverageBlock ,
276+ ) -> impl Iterator < Item = BasicCoverageBlock > + Captures < ' _ > {
277+ self . predecessors [ to_bcb] . iter ( ) . copied ( ) . filter ( move |& pred| self . dominates ( to_bcb, pred) )
278+ }
217279}
218280
219281impl Index < BasicCoverageBlock > for CoverageGraph {
@@ -439,15 +501,12 @@ struct TraversalContext {
439501pub ( crate ) struct TraverseCoverageGraphWithLoops < ' a > {
440502 basic_coverage_blocks : & ' a CoverageGraph ,
441503
442- backedges : IndexVec < BasicCoverageBlock , Vec < BasicCoverageBlock > > ,
443504 context_stack : Vec < TraversalContext > ,
444505 visited : BitSet < BasicCoverageBlock > ,
445506}
446507
447508impl < ' a > TraverseCoverageGraphWithLoops < ' a > {
448509 pub ( crate ) fn new ( basic_coverage_blocks : & ' a CoverageGraph ) -> Self {
449- let backedges = find_loop_backedges ( basic_coverage_blocks) ;
450-
451510 let worklist = VecDeque :: from ( [ basic_coverage_blocks. start_node ( ) ] ) ;
452511 let context_stack = vec ! [ TraversalContext { loop_header: None , worklist } ] ;
453512
@@ -456,17 +515,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
456515 // of the stack as loops are entered, and popped off of the stack when a loop's worklist is
457516 // exhausted.
458517 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 ( ) )
518+ Self { basic_coverage_blocks, context_stack, visited }
470519 }
471520
472521 pub ( crate ) fn next ( & mut self ) -> Option < BasicCoverageBlock > {
@@ -488,7 +537,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
488537 }
489538 debug ! ( "Visiting {bcb:?}" ) ;
490539
491- if self . backedges [ bcb ] . len ( ) > 0 {
540+ if self . basic_coverage_blocks . is_loop_header . contains ( bcb ) {
492541 debug ! ( "{bcb:?} is a loop header! Start a new TraversalContext..." ) ;
493542 self . context_stack
494543 . push ( TraversalContext { loop_header : Some ( bcb) , worklist : VecDeque :: new ( ) } ) ;
@@ -566,29 +615,6 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
566615 }
567616}
568617
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-
592618fn short_circuit_preorder < ' a , ' tcx , F , Iter > (
593619 body : & ' a mir:: Body < ' tcx > ,
594620 filtered_successors : F ,
0 commit comments