From 17b364262b725399849df55e79eb924754453561 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 14 Jul 2026 19:10:25 +1000 Subject: [PATCH 1/5] Remove `ResultsVisitor::visit_block_end` `ResultsVisitor` has `visit_block_start` which is called on entry to a a block in a forwards analysis and on exit from a block in a backwards analysis. And vice versa for `visit_block_end`. The only visitor that impls these methods is `StateDiffCollector`, which does something in `visit_block_start` for a forwards analysis and the same thing in `visit_block_end` for a backwards analysis. In other words, `StateDiffCollector` wants to always do the same thing on entry to a block and never do anything on exit from a block. This commit replaces `visit_block_{start,end}` with `visit_block_entry`, which is always called on entry to a block. This is simpler overall. --- .../rustc_mir_dataflow/src/framework/direction.rs | 8 ++------ .../rustc_mir_dataflow/src/framework/graphviz.rs | 12 ++---------- compiler/rustc_mir_dataflow/src/framework/visitor.rs | 6 +++--- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 39df33187d3a9..ad1d9766546a6 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -214,7 +214,7 @@ impl Direction for Backward { ) where A: Analysis<'tcx>, { - vis.visit_block_end(state); + vis.visit_block_entry(state); let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); @@ -230,8 +230,6 @@ impl Direction for Backward { analysis.apply_primary_statement_effect(state, stmt, loc); vis.visit_after_primary_statement_effect(analysis, state, stmt, loc); } - - vis.visit_block_start(state); } } @@ -393,7 +391,7 @@ impl Direction for Forward { ) where A: Analysis<'tcx>, { - vis.visit_block_start(state); + vis.visit_block_entry(state); for (statement_index, stmt) in block_data.statements.iter().enumerate() { let loc = Location { block, statement_index }; @@ -409,7 +407,5 @@ impl Direction for Forward { vis.visit_after_early_terminator_effect(analysis, state, term, loc); analysis.apply_primary_terminator_effect(state, term, loc); vis.visit_after_primary_terminator_effect(analysis, state, term, loc); - - vis.visit_block_end(state); } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 6c0f2e8d73058..ed34a1f151eb9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -660,16 +660,8 @@ where A: Analysis<'tcx>, A::Domain: DebugWithContext, { - fn visit_block_start(&mut self, state: &A::Domain) { - if A::Direction::IS_FORWARD { - self.prev_state.clone_from(state); - } - } - - fn visit_block_end(&mut self, state: &A::Domain) { - if A::Direction::IS_BACKWARD { - self.prev_state.clone_from(state); - } + fn visit_block_entry(&mut self, state: &A::Domain) { + self.prev_state.clone_from(state); } fn visit_after_early_statement_effect( diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 46940c6ab62fc..befe3c0a738d1 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -46,7 +46,9 @@ pub trait ResultsVisitor<'tcx, A> where A: Analysis<'tcx>, { - fn visit_block_start(&mut self, _state: &A::Domain) {} + /// Called on entry to a block. In a forwards analysis, `_state` is from the block's start. In + /// a backwards analysis, `_state` is from the block's end. + fn visit_block_entry(&mut self, _state: &A::Domain) {} /// Called after the "early" effect of the given statement is applied to `state`. fn visit_after_early_statement_effect( @@ -89,6 +91,4 @@ where _location: Location, ) { } - - fn visit_block_end(&mut self, _state: &A::Domain) {} } From f2063f90994e6fe1755d487c5fe627412389d76e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 14 Jul 2026 19:46:39 +1000 Subject: [PATCH 2/5] Avoid some `IS_FORWARD` tests By adding more methods to `Direction`. This makes things more concise, and these new methods will be used more in subsequent commits. --- .../src/framework/cursor.rs | 16 ++---- .../src/framework/direction.rs | 54 ++++++++++++++++++- .../rustc_mir_dataflow/src/framework/mod.rs | 38 ------------- .../rustc_mir_dataflow/src/framework/tests.rs | 12 +---- 4 files changed, 58 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 3c56999fcbdc9..c01cee3e86b6b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -195,18 +195,10 @@ where debug_assert_eq!(target.block, self.pos.block); let block_data = &self.body[target.block]; - #[rustfmt::skip] - let next_effect = if A::Direction::IS_FORWARD { - self.pos.curr_effect_index.map_or_else( - || Effect::Early.at_index(0), - EffectIndex::next_in_forward_order, - ) - } else { - self.pos.curr_effect_index.map_or_else( - || Effect::Early.at_index(block_data.statements.len()), - EffectIndex::next_in_backward_order, - ) - }; + let next_effect = self.pos.curr_effect_index.map_or_else( + || A::Direction::first_index(block_data), + |idx| A::Direction::next_index(idx), + ); let target_effect_index = effect.at_index(target.statement_index); diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index ad1d9766546a6..5b41effed6068 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::ops::RangeInclusive; use rustc_middle::bug; @@ -10,6 +11,16 @@ pub trait Direction { const IS_FORWARD: bool; const IS_BACKWARD: bool = !Self::IS_FORWARD; + /// Returns the first statement index for this direction. (0 when going forward and + /// `statements.len()` when going backward.) + fn first_index(block_data: &mir::BasicBlockData<'_>) -> EffectIndex; + + /// Returns `true` if `a` comes before `b` for this direction. + fn index_precedes(a: EffectIndex, b: EffectIndex) -> bool; + + /// Returns the next index for this direction. + fn next_index(idx: EffectIndex) -> EffectIndex; + /// Called by `iterate_to_fixpoint` during initial analysis computation. fn apply_effects_in_block<'mir, 'tcx, A>( analysis: &A, @@ -53,6 +64,26 @@ pub struct Backward; impl Direction for Backward { const IS_FORWARD: bool = false; + fn first_index(block_data: &mir::BasicBlockData<'_>) -> EffectIndex { + Effect::Early.at_index(block_data.statements.len()) + } + + fn index_precedes(a: EffectIndex, b: EffectIndex) -> bool { + // Higher statement indices precede lower statement indices, and then `Early` effects + // precede `Primary` effects. (That's why the two comparisons use different orders for `a` + // and `b`.) + let ord = b.statement_index.cmp(&a.statement_index).then_with(|| a.effect.cmp(&b.effect)); + ord == Ordering::Less + } + + /// Returns the next index for this direction. + fn next_index(idx: EffectIndex) -> EffectIndex { + match idx.effect { + Effect::Early => Effect::Primary.at_index(idx.statement_index), + Effect::Primary => Effect::Early.at_index(idx.statement_index - 1), + } + } + fn apply_effects_in_block<'mir, 'tcx, A>( analysis: &A, body: &mir::Body<'tcx>, @@ -141,7 +172,7 @@ impl Direction for Backward { let terminator_index = block_data.statements.len(); assert!(from.statement_index <= terminator_index); - assert!(!to.precedes_in_backward_order(from)); + assert!(!Self::index_precedes(to, from)); // Handle the statement (or terminator) at `from`. @@ -239,6 +270,25 @@ pub struct Forward; impl Direction for Forward { const IS_FORWARD: bool = true; + fn first_index(_block_data: &mir::BasicBlockData<'_>) -> EffectIndex { + Effect::Early.at_index(0) + } + + fn index_precedes(a: EffectIndex, b: EffectIndex) -> bool { + // Lower statement indices precede higher statement indices, and then `Early` effects + // precede `Primary` effects. + let ord = a.statement_index.cmp(&b.statement_index).then_with(|| a.effect.cmp(&b.effect)); + ord == Ordering::Less + } + + /// Returns the next index for this direction. + fn next_index(idx: EffectIndex) -> EffectIndex { + match idx.effect { + Effect::Early => Effect::Primary.at_index(idx.statement_index), + Effect::Primary => Effect::Early.at_index(idx.statement_index + 1), + } + } + fn apply_effects_in_block<'mir, 'tcx, A>( analysis: &A, body: &mir::Body<'tcx>, @@ -321,7 +371,7 @@ impl Direction for Forward { let terminator_index = block_data.statements.len(); assert!(to.statement_index <= terminator_index); - assert!(!to.precedes_in_forward_order(from)); + assert!(!Self::index_precedes(to, from)); // If we have applied the before affect of the statement or terminator at `from` but not its // after effect, do so now and start the loop below from the next statement. diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 6445ba7ad27b6..5156749f2e6d8 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -32,8 +32,6 @@ //! //! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems -use std::cmp::Ordering; - use rustc_data_structures::work_queue::WorkQueue; use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; use rustc_index::{Idx, IndexVec}; @@ -402,41 +400,5 @@ pub struct EffectIndex { effect: Effect, } -impl EffectIndex { - fn next_in_forward_order(self) -> Self { - match self.effect { - Effect::Early => Effect::Primary.at_index(self.statement_index), - Effect::Primary => Effect::Early.at_index(self.statement_index + 1), - } - } - - fn next_in_backward_order(self) -> Self { - match self.effect { - Effect::Early => Effect::Primary.at_index(self.statement_index), - Effect::Primary => Effect::Early.at_index(self.statement_index - 1), - } - } - - /// Returns `true` if the effect at `self` should be applied earlier than the effect at `other` - /// in forward order. - fn precedes_in_forward_order(self, other: Self) -> bool { - let ord = self - .statement_index - .cmp(&other.statement_index) - .then_with(|| self.effect.cmp(&other.effect)); - ord == Ordering::Less - } - - /// Returns `true` if the effect at `self` should be applied earlier than the effect at `other` - /// in backward order. - fn precedes_in_backward_order(self, other: Self) -> bool { - let ord = other - .statement_index - .cmp(&self.statement_index) - .then_with(|| self.effect.cmp(&other.effect)); - ord == Ordering::Less - } -} - #[cfg(test)] mod tests; diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index dec273d39dd1a..86ea3a34ae0ea 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -139,11 +139,7 @@ impl MockAnalysis<'_, D> { SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index), }; - let mut pos = if D::IS_FORWARD { - Effect::Early.at_index(0) - } else { - Effect::Early.at_index(self.body[block].statements.len()) - }; + let mut pos = D::first_index(&self.body[block]); loop { ret.insert(self.effect(pos)); @@ -152,11 +148,7 @@ impl MockAnalysis<'_, D> { return ret; } - if D::IS_FORWARD { - pos = pos.next_in_forward_order(); - } else { - pos = pos.next_in_backward_order(); - } + pos = D::next_index(pos); } } } From 642e9d2b47dc44f36c4e2384b32a5c1f54fea516 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 14 Jul 2026 15:11:32 +1000 Subject: [PATCH 3/5] Simplify `apply_effects_in_range` This commit adds `Analysis::apply_effect`, which takes an `EffectIndex` and calls the appropriate `Analysis::apply_*` method. Once that is in place, it is possible to use it with `next_index` to write a simple `apply_effects_in_range` method that can be shared between `Forward` and `Backward`. The end result is much easier to understand. --- .../src/framework/direction.rs | 170 ++---------------- .../rustc_mir_dataflow/src/framework/mod.rs | 38 +++- 2 files changed, 55 insertions(+), 153 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 5b41effed6068..c5157dc728614 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -43,7 +43,24 @@ pub trait Direction { block_data: &mir::BasicBlockData<'tcx>, effects: RangeInclusive, ) where - A: Analysis<'tcx>; + A: Analysis<'tcx>, + { + let (from, to) = (*effects.start(), *effects.end()); + let terminator_index = block_data.statements.len(); + + assert!(to.statement_index <= terminator_index); + assert!(from.statement_index <= terminator_index); + assert!(!Self::index_precedes(to, from)); + + let mut idx = from; + loop { + analysis.apply_effect(state, block, block_data, idx); + if idx == to { + break; + } + idx = Self::next_index(idx); + } + } /// Called by `ResultsVisitor` to recompute the analysis domain values for /// all locations in a basic block (starting from `entry_state` and to @@ -159,83 +176,6 @@ impl Direction for Backward { } } - fn apply_effects_in_range<'tcx, A>( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - effects: RangeInclusive, - ) where - A: Analysis<'tcx>, - { - let (from, to) = (*effects.start(), *effects.end()); - let terminator_index = block_data.statements.len(); - - assert!(from.statement_index <= terminator_index); - assert!(!Self::index_precedes(to, from)); - - // Handle the statement (or terminator) at `from`. - - let next_effect = match from.effect { - // If we need to apply the terminator effect in all or in part, do so now. - _ if from.statement_index == terminator_index => { - let location = Location { block, statement_index: from.statement_index }; - let terminator = block_data.terminator(); - - if from.effect == Effect::Early { - analysis.apply_early_terminator_effect(state, terminator, location); - if to == Effect::Early.at_index(terminator_index) { - return; - } - } - - analysis.apply_primary_terminator_effect(state, terminator, location); - if to == Effect::Primary.at_index(terminator_index) { - return; - } - - // If `from.statement_index` is `0`, we will have hit one of the earlier comparisons - // with `to`. - from.statement_index - 1 - } - - Effect::Primary => { - let location = Location { block, statement_index: from.statement_index }; - let statement = &block_data.statements[from.statement_index]; - - analysis.apply_primary_statement_effect(state, statement, location); - if to == Effect::Primary.at_index(from.statement_index) { - return; - } - - from.statement_index - 1 - } - - Effect::Early => from.statement_index, - }; - - // Handle all statements between `first_unapplied_idx` and `to.statement_index`. - - for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) { - let location = Location { block, statement_index }; - let statement = &block_data.statements[statement_index]; - analysis.apply_early_statement_effect(state, statement, location); - analysis.apply_primary_statement_effect(state, statement, location); - } - - // Handle the statement at `to`. - - let location = Location { block, statement_index: to.statement_index }; - let statement = &block_data.statements[to.statement_index]; - analysis.apply_early_statement_effect(state, statement, location); - - if to.effect == Effect::Early { - return; - } - - analysis.apply_primary_statement_effect(state, statement, location); - } - fn visit_results_in_block<'mir, 'tcx, A>( analysis: &A, state: &mut A::Domain, @@ -358,80 +298,6 @@ impl Direction for Forward { } } - fn apply_effects_in_range<'tcx, A>( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - effects: RangeInclusive, - ) where - A: Analysis<'tcx>, - { - let (from, to) = (*effects.start(), *effects.end()); - let terminator_index = block_data.statements.len(); - - assert!(to.statement_index <= terminator_index); - assert!(!Self::index_precedes(to, from)); - - // If we have applied the before affect of the statement or terminator at `from` but not its - // after effect, do so now and start the loop below from the next statement. - - let first_unapplied_index = match from.effect { - Effect::Early => from.statement_index, - - Effect::Primary if from.statement_index == terminator_index => { - debug_assert_eq!(from, to); - - let location = Location { block, statement_index: terminator_index }; - let terminator = block_data.terminator(); - analysis.apply_primary_terminator_effect(state, terminator, location); - return; - } - - Effect::Primary => { - let location = Location { block, statement_index: from.statement_index }; - let statement = &block_data.statements[from.statement_index]; - analysis.apply_primary_statement_effect(state, statement, location); - - // If we only needed to apply the after effect of the statement at `idx`, we are - // done. - if from == to { - return; - } - - from.statement_index + 1 - } - }; - - // Handle all statements between `from` and `to` whose effects must be applied in full. - - for statement_index in first_unapplied_index..to.statement_index { - let location = Location { block, statement_index }; - let statement = &block_data.statements[statement_index]; - analysis.apply_early_statement_effect(state, statement, location); - analysis.apply_primary_statement_effect(state, statement, location); - } - - // Handle the statement or terminator at `to`. - - let location = Location { block, statement_index: to.statement_index }; - if to.statement_index == terminator_index { - let terminator = block_data.terminator(); - analysis.apply_early_terminator_effect(state, terminator, location); - - if to.effect == Effect::Primary { - analysis.apply_primary_terminator_effect(state, terminator, location); - } - } else { - let statement = &block_data.statements[to.statement_index]; - analysis.apply_early_statement_effect(state, statement, location); - - if to.effect == Effect::Primary { - analysis.apply_primary_statement_effect(state, statement, location); - } - } - } - fn visit_results_in_block<'mir, 'tcx, A>( analysis: &A, state: &mut A::Domain, diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 5156749f2e6d8..211a1b8d05b71 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -36,7 +36,9 @@ use rustc_data_structures::work_queue::WorkQueue; use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; use rustc_index::{Idx, IndexVec}; use rustc_middle::bug; -use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal}; +use rustc_middle::mir::{ + self, BasicBlock, BasicBlockData, CallReturnPlaces, Location, TerminatorEdges, traversal, +}; use rustc_middle::ty::TyCtxt; use tracing::error; @@ -123,6 +125,40 @@ pub trait Analysis<'tcx> { // `resume`). It's not obvious how to handle `yield` points in coroutines, however. fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain); + /// Given an `EffectIndex`, calls the appropriate `apply_*` method in the + /// {early,primary} x {statement,terminator} space. + /// + /// Do not override this; instead override one or more of the `apply_*` methods. + #[inline] + fn apply_effect<'mir>( + &self, + state: &mut Self::Domain, + block: BasicBlock, + block_data: &'mir BasicBlockData<'tcx>, + idx: EffectIndex, + ) { + let statement_index = idx.statement_index; + let terminator_index = block_data.statements.len(); + let loc = Location { block, statement_index }; + let is_terminator = statement_index == terminator_index; + + if !is_terminator { + let statement = &block_data.statements[statement_index]; + match idx.effect { + Effect::Early => self.apply_early_statement_effect(state, statement, loc), + Effect::Primary => self.apply_primary_statement_effect(state, statement, loc), + } + } else { + let terminator = block_data.terminator(); + match idx.effect { + Effect::Early => self.apply_early_terminator_effect(state, terminator, loc), + Effect::Primary => { + self.apply_primary_terminator_effect(state, terminator, loc); + } + } + } + } + /// Updates the current dataflow state with an "early" effect, i.e. one /// that occurs immediately before the given statement. /// From 61b5db69f7aba90eeb831545a1c25922616c0c1f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 20 Jul 2026 13:19:20 +1000 Subject: [PATCH 4/5] Eliminate `ResultsVisitor::visit_block_entry` It's only used by `StateDiffCollector`, and it's just a complicated way to get the entry state, which can instead be done directly (avoiding the creation of a `bottom_value` which was immediately overwritten). --- compiler/rustc_mir_dataflow/src/framework/direction.rs | 4 ---- compiler/rustc_mir_dataflow/src/framework/graphviz.rs | 8 ++------ compiler/rustc_mir_dataflow/src/framework/visitor.rs | 4 ---- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index c5157dc728614..8519eb92c8e02 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -185,8 +185,6 @@ impl Direction for Backward { ) where A: Analysis<'tcx>, { - vis.visit_block_entry(state); - let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); analysis.apply_early_terminator_effect(state, term, loc); @@ -307,8 +305,6 @@ impl Direction for Forward { ) where A: Analysis<'tcx>, { - vis.visit_block_entry(state); - for (statement_index, stmt) in block_data.statements.iter().enumerate() { let loc = Location { block, statement_index }; analysis.apply_early_statement_effect(state, stmt, loc); diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index ed34a1f151eb9..a95ab44c951d6 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -633,7 +633,7 @@ struct StateDiffCollector { after: Vec, } -impl StateDiffCollector { +impl StateDiffCollector { fn run<'tcx, A>( body: &Body<'tcx>, block: BasicBlock, @@ -645,7 +645,7 @@ impl StateDiffCollector { D: DebugWithContext, { let mut collector = StateDiffCollector { - prev_state: results.analysis.bottom_value(body), + prev_state: results.entry_states[block].clone(), after: vec![], before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), }; @@ -660,10 +660,6 @@ where A: Analysis<'tcx>, A::Domain: DebugWithContext, { - fn visit_block_entry(&mut self, state: &A::Domain) { - self.prev_state.clone_from(state); - } - fn visit_after_early_statement_effect( &mut self, analysis: &A, diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index befe3c0a738d1..b6827be3d8beb 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -46,10 +46,6 @@ pub trait ResultsVisitor<'tcx, A> where A: Analysis<'tcx>, { - /// Called on entry to a block. In a forwards analysis, `_state` is from the block's start. In - /// a backwards analysis, `_state` is from the block's end. - fn visit_block_entry(&mut self, _state: &A::Domain) {} - /// Called after the "early" effect of the given statement is applied to `state`. fn visit_after_early_statement_effect( &mut self, From e736635dd39d3d346e6d818e2bd30c7feb83b94a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 20 Jul 2026 13:32:54 +1000 Subject: [PATCH 5/5] Inline and remove `Direction::apply_effects_in_range` It has a single call site. The commit removes the assertions because they necessary any more due to the assertions and checks at the call site. This then removes the need for `index_precedes`. --- .../src/framework/cursor.rs | 16 +++--- .../src/framework/direction.rs | 51 ------------------- 2 files changed, 8 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index c01cee3e86b6b..63b2adceb524c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -199,16 +199,16 @@ where || A::Direction::first_index(block_data), |idx| A::Direction::next_index(idx), ); - let target_effect_index = effect.at_index(target.statement_index); - A::Direction::apply_effects_in_range( - &self.results.analysis, - &mut self.state, - target.block, - block_data, - next_effect..=target_effect_index, - ); + let mut idx = next_effect; + loop { + self.results.analysis.apply_effect(&mut self.state, target.block, block_data, idx); + if idx == target_effect_index { + break; + } + idx = A::Direction::next_index(idx); + } self.pos = CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) }; diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 8519eb92c8e02..68c8e03de8022 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -1,6 +1,3 @@ -use std::cmp::Ordering; -use std::ops::RangeInclusive; - use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; @@ -15,9 +12,6 @@ pub trait Direction { /// `statements.len()` when going backward.) fn first_index(block_data: &mir::BasicBlockData<'_>) -> EffectIndex; - /// Returns `true` if `a` comes before `b` for this direction. - fn index_precedes(a: EffectIndex, b: EffectIndex) -> bool; - /// Returns the next index for this direction. fn next_index(idx: EffectIndex) -> EffectIndex; @@ -32,36 +26,6 @@ pub trait Direction { ) where A: Analysis<'tcx>; - /// Called by `ResultsCursor` to recompute the domain value for a location - /// in a basic block. Applies all effects between the given `EffectIndex`s. - /// - /// `effects.start()` must precede or equal `effects.end()` in this direction. - fn apply_effects_in_range<'tcx, A>( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - effects: RangeInclusive, - ) where - A: Analysis<'tcx>, - { - let (from, to) = (*effects.start(), *effects.end()); - let terminator_index = block_data.statements.len(); - - assert!(to.statement_index <= terminator_index); - assert!(from.statement_index <= terminator_index); - assert!(!Self::index_precedes(to, from)); - - let mut idx = from; - loop { - analysis.apply_effect(state, block, block_data, idx); - if idx == to { - break; - } - idx = Self::next_index(idx); - } - } - /// Called by `ResultsVisitor` to recompute the analysis domain values for /// all locations in a basic block (starting from `entry_state` and to /// visit them with `vis`. @@ -85,14 +49,6 @@ impl Direction for Backward { Effect::Early.at_index(block_data.statements.len()) } - fn index_precedes(a: EffectIndex, b: EffectIndex) -> bool { - // Higher statement indices precede lower statement indices, and then `Early` effects - // precede `Primary` effects. (That's why the two comparisons use different orders for `a` - // and `b`.) - let ord = b.statement_index.cmp(&a.statement_index).then_with(|| a.effect.cmp(&b.effect)); - ord == Ordering::Less - } - /// Returns the next index for this direction. fn next_index(idx: EffectIndex) -> EffectIndex { match idx.effect { @@ -212,13 +168,6 @@ impl Direction for Forward { Effect::Early.at_index(0) } - fn index_precedes(a: EffectIndex, b: EffectIndex) -> bool { - // Lower statement indices precede higher statement indices, and then `Early` effects - // precede `Primary` effects. - let ord = a.statement_index.cmp(&b.statement_index).then_with(|| a.effect.cmp(&b.effect)); - ord == Ordering::Less - } - /// Returns the next index for this direction. fn next_index(idx: EffectIndex) -> EffectIndex { match idx.effect {