From 6352e8298ffe51c712c0ac682ef0370bba78734a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 09:25:52 +1100 Subject: [PATCH] Move `maybe_loop_headers` out of `rustc_middle`. `rustc_middle` is enormous and it's always good to move things out of it where possible. `maybe_loop_headers` is easy to move because it has a single use in `jump_threading.rs`. --- compiler/rustc_middle/src/mir/loops.rs | 29 ------------------- compiler/rustc_middle/src/mir/mod.rs | 2 -- .../rustc_mir_transform/src/jump_threading.rs | 28 +++++++++++++++++- 3 files changed, 27 insertions(+), 32 deletions(-) delete mode 100644 compiler/rustc_middle/src/mir/loops.rs diff --git a/compiler/rustc_middle/src/mir/loops.rs b/compiler/rustc_middle/src/mir/loops.rs deleted file mode 100644 index ae332913c6421..0000000000000 --- a/compiler/rustc_middle/src/mir/loops.rs +++ /dev/null @@ -1,29 +0,0 @@ -use rustc_index::bit_set::DenseBitSet; - -use super::*; - -/// Compute the set of loop headers in the given body. A loop header is usually defined as a block -/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. -/// However, computing dominators is expensive, so we approximate according to the post-order -/// traversal order. A loop header for us is a block which is visited after its predecessor in -/// post-order. This is ok as we mostly need a heuristic. -pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { - let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); - let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); - for (bb, bbdata) in traversal::postorder(body) { - // Post-order means we visit successors before the block for acyclic CFGs. - // If the successor is not visited yet, consider it a loop header. - for succ in bbdata.terminator().successors() { - if !visited.contains(succ) { - maybe_loop_headers.insert(succ); - } - } - - // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. - // bb1: goto -> bb1; - let _new = visited.insert(bb); - debug_assert!(_new); - } - - maybe_loop_headers -} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 892d3bfea653e..1c14b94b8d7d3 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -48,8 +48,6 @@ mod query; mod statement; mod syntax; mod terminator; - -pub mod loops; pub mod traversal; pub mod visit; diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index a1e5d810afc02..c17e18ac664ed 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -97,7 +97,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), body, map: Map::new(tcx, body, PlaceCollectionMode::OnDemand), - maybe_loop_headers: loops::maybe_loop_headers(body), + maybe_loop_headers: maybe_loop_headers(body), entry_states: IndexVec::from_elem(ConditionSet::default(), &body.basic_blocks), }; @@ -1100,3 +1100,29 @@ impl<'a, 'tcx> OpportunitySet<'a, 'tcx> { Some(new_target) } } + +/// Compute the set of loop headers in the given body. A loop header is usually defined as a block +/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. +/// However, computing dominators is expensive, so we approximate according to the post-order +/// traversal order. A loop header for us is a block which is visited after its predecessor in +/// post-order. This is ok as we mostly need a heuristic. +fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { + let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); + let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); + for (bb, bbdata) in traversal::postorder(body) { + // Post-order means we visit successors before the block for acyclic CFGs. + // If the successor is not visited yet, consider it a loop header. + for succ in bbdata.terminator().successors() { + if !visited.contains(succ) { + maybe_loop_headers.insert(succ); + } + } + + // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. + // bb1: goto -> bb1; + let _new = visited.insert(bb); + debug_assert!(_new); + } + + maybe_loop_headers +}