From 7e704afc2d48df0f266ac592d0806c6770a3d08c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Nov 2024 15:43:13 +1100 Subject: [PATCH] Add some useful comments. Describing some things that took me a long time to understand. --- .../rustc_mir_dataflow/src/framework/cursor.rs | 14 +++++++++----- .../rustc_mir_dataflow/src/framework/direction.rs | 9 ++++++--- compiler/rustc_mir_dataflow/src/framework/mod.rs | 5 +++-- .../rustc_mir_dataflow/src/framework/results.rs | 4 +++- .../rustc_mir_dataflow/src/framework/visitor.rs | 4 +++- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 5ebb343f4e195..fbd9376917a14 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -8,12 +8,16 @@ use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Effect, EffectIndex, Results}; -/// Allows random access inspection of the results of a dataflow analysis. +/// Allows random access inspection of the results of a dataflow analysis. Use this when you want +/// to inspect domain values only in certain locations; use `ResultsVisitor` if you want to inspect +/// domain values in many or all locations. /// -/// This cursor only has linear performance within a basic block when its statements are visited in -/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are -/// visited in *reverse* order—performance will be quadratic in the number of statements in the -/// block. The order in which basic blocks are inspected has no impact on performance. +/// Because `Results` only has domain values for the entry of each basic block, these inspections +/// involve some amount of domain value recomputations. This cursor only has linear performance +/// within a basic block when its statements are visited in the same order as the `DIRECTION` of +/// the analysis. In the worst case—when statements are visited in *reverse* order—performance will +/// be quadratic in the number of statements in the block. The order in which basic blocks are +/// inspected has no impact on performance. pub struct ResultsCursor<'mir, 'tcx, A> where A: Analysis<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 84b22ed68c6dc..566a6b09b2b15 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -9,9 +9,9 @@ use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget}; pub trait Direction { const IS_FORWARD: bool; - const IS_BACKWARD: bool = !Self::IS_FORWARD; + /// Called by `iterate_to_fixpoint` during initial analysis computation. fn apply_effects_in_block<'mir, 'tcx, A>( analysis: &mut A, body: &mir::Body<'tcx>, @@ -22,7 +22,8 @@ pub trait Direction { ) where A: Analysis<'tcx>; - /// Applies all effects between the given `EffectIndex`s. + /// 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>( @@ -34,6 +35,9 @@ pub trait Direction { ) where A: Analysis<'tcx>; + /// Called by `ResultsVisitor` to recompute the analysis domain values for + /// all locations in a basic block (starting from the entry value stored + /// in `Results`) and to visit them with `vis`. fn visit_results_in_block<'mir, 'tcx, A>( state: &mut A::Domain, block: BasicBlock, @@ -222,7 +226,6 @@ impl Direction for Backward { vis.visit_block_end(state); - // Terminator let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); results.analysis.apply_before_terminator_effect(state, term, loc); diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 7c3bcebcfe252..f9e7ba743fc2f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -8,8 +8,9 @@ //! The `impls` module contains several examples of dataflow analyses. //! //! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From -//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem, -//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses +//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem +//! (good for inspecting a small number of locations), or implement the `ResultsVisitor` interface +//! and use `visit_results` (good for inspecting many or all locations). The following example uses //! the `ResultsCursor` approach. //! //! ```ignore (cross-crate-imports) diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index ff6cafbfbaee6..7c775ae7f4a56 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -20,7 +20,9 @@ use crate::errors::{ pub type EntrySets<'tcx, A> = IndexVec>::Domain>; -/// A dataflow analysis that has converged to fixpoint. +/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the +/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly +/// by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). #[derive(Clone)] pub struct Results<'tcx, A> where diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 5c7539eed4d6a..bde41974d4727 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -26,7 +26,9 @@ pub fn visit_results<'mir, 'tcx, A>( } } -/// A visitor over the results of an `Analysis`. +/// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in +/// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain +/// locations. pub trait ResultsVisitor<'mir, 'tcx, A> where A: Analysis<'tcx>,