Remove Analysis::into_engine
.
This is a standard pattern: ``` MyAnalysis.into_engine(tcx, body).iterate_to_fixpoint() ``` `into_engine` and `iterate_to_fixpoint` are always called in pairs, but sometimes with a builder-style `pass_name` call between them. But a builder-style interface is overkill here. This has been bugging me a for a while. This commit: - Merges `Engine::new` and `Engine::iterate_to_fixpoint`. This removes the need for `Engine` to have fields, leaving it as a trivial type that the next commit will remove. - Renames `Analysis::into_engine` as `Analysis::iterate_to_fixpoint`, gives it an extra argument for the optional pass name, and makes it call `Engine::iterate_to_fixpoint` instead of `Engine::new`. This turns the pattern from above into this: ``` MyAnalysis.iterate_to_fixpoint(tcx, body, None) ``` which is shorter at every call site, and there's less plumbing required to support it.
This commit is contained in:
parent
31e102c509
commit
e54c177118
14 changed files with 72 additions and 116 deletions
|
@ -71,25 +71,21 @@ where
|
|||
}
|
||||
|
||||
/// A solver for dataflow problems.
|
||||
pub struct Engine<'mir, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
entry_sets: IndexVec<BasicBlock, A::Domain>,
|
||||
pass_name: Option<&'static str>,
|
||||
analysis: A,
|
||||
}
|
||||
pub struct Engine;
|
||||
|
||||
impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx, Domain = D>,
|
||||
D: Clone + JoinSemiLattice,
|
||||
{
|
||||
impl Engine {
|
||||
/// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
|
||||
/// function.
|
||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self {
|
||||
pub(crate) fn iterate_to_fixpoint<'mir, 'tcx, A>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
mut analysis: A,
|
||||
pass_name: Option<&'static str>,
|
||||
) -> Results<'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
A::Domain: DebugWithContext<A> + Clone + JoinSemiLattice,
|
||||
{
|
||||
let mut entry_sets =
|
||||
IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len());
|
||||
analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
|
||||
|
@ -99,25 +95,6 @@ where
|
|||
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
|
||||
}
|
||||
|
||||
Engine { analysis, tcx, body, pass_name: None, entry_sets }
|
||||
}
|
||||
|
||||
/// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
|
||||
///
|
||||
/// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name`
|
||||
/// to differentiate them. Otherwise, only the results for the latest run will be saved.
|
||||
pub fn pass_name(mut self, name: &'static str) -> Self {
|
||||
self.pass_name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
/// Computes the fixpoint for this dataflow problem and returns it.
|
||||
pub fn iterate_to_fixpoint(self) -> Results<'tcx, A>
|
||||
where
|
||||
A::Domain: DebugWithContext<A>,
|
||||
{
|
||||
let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self;
|
||||
|
||||
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
|
||||
|
||||
if A::Direction::IS_FORWARD {
|
||||
|
|
|
@ -7,18 +7,17 @@
|
|||
//!
|
||||
//! The `impls` module contains several examples of dataflow analyses.
|
||||
//!
|
||||
//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait,
|
||||
//! then call `iterate_to_fixpoint`. 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 the `ResultsCursor` approach.
|
||||
//! 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
|
||||
//! the `ResultsCursor` approach.
|
||||
//!
|
||||
//! ```ignore (cross-crate-imports)
|
||||
//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available.
|
||||
//! use rustc_const_eval::dataflow::Analysis; // Makes `iterate_to_fixpoint` available.
|
||||
//!
|
||||
//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
|
||||
//! let analysis = MyAnalysis::new()
|
||||
//! .into_engine(tcx, body)
|
||||
//! .iterate_to_fixpoint()
|
||||
//! .iterate_to_fixpoint(tcx, body, None)
|
||||
//! .into_results_cursor(body);
|
||||
//!
|
||||
//! // Print the dataflow state *after* each statement in the start block.
|
||||
|
@ -39,6 +38,8 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
|
|||
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use super::fmt::DebugWithContext;
|
||||
|
||||
mod cursor;
|
||||
mod direction;
|
||||
mod engine;
|
||||
|
@ -223,26 +224,30 @@ pub trait Analysis<'tcx> {
|
|||
|
||||
/* Extension methods */
|
||||
|
||||
/// Creates an `Engine` to find the fixpoint for this dataflow problem.
|
||||
/// Finds the fixpoint for this dataflow problem.
|
||||
///
|
||||
/// You shouldn't need to override this. Its purpose is to enable method chaining like so:
|
||||
///
|
||||
/// ```ignore (cross-crate-imports)
|
||||
/// let results = MyAnalysis::new(tcx, body)
|
||||
/// .into_engine(tcx, body, def_id)
|
||||
/// .iterate_to_fixpoint()
|
||||
/// .iterate_to_fixpoint(tcx, body, None)
|
||||
/// .into_results_cursor(body);
|
||||
/// ```
|
||||
#[inline]
|
||||
fn into_engine<'mir>(
|
||||
/// You can optionally add a `pass_name` to the graphviz output for this particular run of a
|
||||
/// dataflow analysis. Some analyses are run multiple times in the compilation pipeline.
|
||||
/// Without a `pass_name` to differentiates them, only the results for the latest run will be
|
||||
/// saved.
|
||||
fn iterate_to_fixpoint<'mir>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
) -> Engine<'mir, 'tcx, Self>
|
||||
pass_name: Option<&'static str>,
|
||||
) -> Results<'tcx, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
Self::Domain: DebugWithContext<Self>,
|
||||
{
|
||||
Engine::new(tcx, body, self)
|
||||
Engine::iterate_to_fixpoint(tcx, body, self, pass_name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue