@@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
84
84
body,
85
85
arena,
86
86
map : Map :: new ( tcx, body, Some ( MAX_PLACES ) ) ,
87
- loop_headers : loop_headers ( body) ,
87
+ maybe_loop_headers : maybe_loop_headers ( body) ,
88
88
opportunities : Vec :: new ( ) ,
89
89
} ;
90
90
@@ -100,7 +100,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
100
100
101
101
// Verify that we do not thread through a loop header.
102
102
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) ) ) ;
104
104
}
105
105
OpportunitySet :: new ( body, opportunities) . apply ( body) ;
106
106
}
@@ -124,7 +124,7 @@ struct TOFinder<'a, 'tcx> {
124
124
ecx : InterpCx < ' tcx , DummyMachine > ,
125
125
body : & ' a Body < ' tcx > ,
126
126
map : Map < ' tcx > ,
127
- loop_headers : DenseBitSet < BasicBlock > ,
127
+ maybe_loop_headers : DenseBitSet < BasicBlock > ,
128
128
/// We use an arena to avoid cloning the slices when cloning `state`.
129
129
arena : & ' a DroplessArena ,
130
130
opportunities : Vec < ThreadingOpportunity > ,
@@ -190,7 +190,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
190
190
#[ instrument( level = "trace" , skip( self ) ) ]
191
191
fn start_from_switch ( & mut self , bb : BasicBlock ) {
192
192
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) {
194
194
return ;
195
195
}
196
196
let Some ( ( discr, targets) ) = bbdata. terminator ( ) . kind . as_switch ( ) else { return } ;
@@ -235,7 +235,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
235
235
depth : usize ,
236
236
) {
237
237
// Do not thread through loop headers.
238
- if self . loop_headers . contains ( bb) {
238
+ if self . maybe_loop_headers . contains ( bb) {
239
239
return ;
240
240
}
241
241
@@ -833,20 +833,28 @@ enum Update {
833
833
Decr ,
834
834
}
835
835
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.
845
847
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) ;
848
850
}
849
851
}
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) ;
850
857
}
851
- loop_headers
858
+
859
+ maybe_loop_headers
852
860
}
0 commit comments