@@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
8484 body,
8585 arena,
8686 map : Map :: new ( tcx, body, Some ( MAX_PLACES ) ) ,
87- loop_headers : loop_headers ( body) ,
87+ maybe_loop_headers : maybe_loop_headers ( body) ,
8888 opportunities : Vec :: new ( ) ,
8989 } ;
9090
@@ -100,7 +100,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
100100
101101 // Verify that we do not thread through a loop header.
102102 for to in opportunities. iter ( ) {
103- assert ! ( to. chain. iter( ) . all( |& block| !finder. loop_headers . contains( block) ) ) ;
103+ assert ! ( to. chain. iter( ) . all( |& block| !finder. maybe_loop_headers . contains( block) ) ) ;
104104 }
105105 OpportunitySet :: new ( body, opportunities) . apply ( body) ;
106106 }
@@ -124,7 +124,7 @@ struct TOFinder<'a, 'tcx> {
124124 ecx : InterpCx < ' tcx , DummyMachine > ,
125125 body : & ' a Body < ' tcx > ,
126126 map : Map < ' tcx > ,
127- loop_headers : DenseBitSet < BasicBlock > ,
127+ maybe_loop_headers : DenseBitSet < BasicBlock > ,
128128 /// We use an arena to avoid cloning the slices when cloning `state`.
129129 arena : & ' a DroplessArena ,
130130 opportunities : Vec < ThreadingOpportunity > ,
@@ -190,7 +190,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
190190 #[ instrument( level = "trace" , skip( self ) ) ]
191191 fn start_from_switch ( & mut self , bb : BasicBlock ) {
192192 let bbdata = & self . body [ bb] ;
193- if bbdata. is_cleanup || self . loop_headers . contains ( bb) {
193+ if bbdata. is_cleanup || self . maybe_loop_headers . contains ( bb) {
194194 return ;
195195 }
196196 let Some ( ( discr, targets) ) = bbdata. terminator ( ) . kind . as_switch ( ) else { return } ;
@@ -235,7 +235,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
235235 depth : usize ,
236236 ) {
237237 // Do not thread through loop headers.
238- if self . loop_headers . contains ( bb) {
238+ if self . maybe_loop_headers . contains ( bb) {
239239 return ;
240240 }
241241
@@ -833,20 +833,28 @@ enum Update {
833833 Decr ,
834834}
835835
836- /// Compute the set of loop headers in the given body. We define a loop header as a block which has
837- /// at least a predecessor which it dominates. This definition is only correct for reducible CFGs.
838- /// But if the CFG is already irreducible, there is no point in trying much harder.
839- /// is already irreducible.
840- fn loop_headers ( body : & Body < ' _ > ) -> DenseBitSet < BasicBlock > {
841- let mut loop_headers = DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
842- let dominators = body. basic_blocks . dominators ( ) ;
843- // Only visit reachable blocks.
844- for ( bb, bbdata) in traversal:: preorder ( body) {
836+ /// Compute the set of loop headers in the given body. A loop header is usually defined as a block
837+ /// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
838+ /// However, computing dominators is expensive, so we approximate according to the post-order
839+ /// traversal order. A loop header for us is a block which is visited after its predecessor in
840+ /// post-order. This is ok as we mostly need a heuristic.
841+ fn maybe_loop_headers ( body : & Body < ' _ > ) -> DenseBitSet < BasicBlock > {
842+ let mut maybe_loop_headers = DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
843+ let mut visited = DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
844+ for ( bb, bbdata) in traversal:: postorder ( body) {
845+ // Post-order means we visit successors before the block for acyclic CFGs.
846+ // If the successor is not visited yet, consider it a loop header.
845847 for succ in bbdata. terminator ( ) . successors ( ) {
846- if dominators . dominates ( succ, bb ) {
847- loop_headers . insert ( succ) ;
848+ if !visited . contains ( succ) {
849+ maybe_loop_headers . insert ( succ) ;
848850 }
849851 }
852+
853+ // Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
854+ // bb1: goto -> bb1;
855+ let _new = visited. insert ( bb) ;
856+ debug_assert ! ( _new) ;
850857 }
851- loop_headers
858+
859+ maybe_loop_headers
852860}
0 commit comments