Rollup merge of #132338 - nnethercote:rm-Engine, r=nnethercote
Remove `Engine` It's just unnecessary plumbing. Removing it results in less code, and simpler code. r? ``@cjgillot``
This commit is contained in:
commit
2055237e8f
15 changed files with 139 additions and 205 deletions
|
@ -193,9 +193,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
|
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
|
||||||
|
|
||||||
let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, Some("borrowck"))
|
||||||
.pass_name("borrowck")
|
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
|
let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
|
||||||
|
@ -243,18 +241,21 @@ fn do_mir_borrowck<'tcx>(
|
||||||
// usage significantly on some benchmarks.
|
// usage significantly on some benchmarks.
|
||||||
drop(flow_inits);
|
drop(flow_inits);
|
||||||
|
|
||||||
let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set)
|
let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint(
|
||||||
.into_engine(tcx, body)
|
tcx,
|
||||||
.pass_name("borrowck")
|
body,
|
||||||
.iterate_to_fixpoint();
|
Some("borrowck"),
|
||||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
|
);
|
||||||
.into_engine(tcx, body)
|
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
|
||||||
.pass_name("borrowck")
|
tcx,
|
||||||
.iterate_to_fixpoint();
|
body,
|
||||||
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data)
|
Some("borrowck"),
|
||||||
.into_engine(tcx, body)
|
);
|
||||||
.pass_name("borrowck")
|
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
|
||||||
.iterate_to_fixpoint();
|
tcx,
|
||||||
|
body,
|
||||||
|
Some("borrowck"),
|
||||||
|
);
|
||||||
|
|
||||||
let movable_coroutine =
|
let movable_coroutine =
|
||||||
// The first argument is the coroutine type passed by value
|
// The first argument is the coroutine type passed by value
|
||||||
|
|
|
@ -64,8 +64,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
||||||
let ConstCx { tcx, body, .. } = *ccx;
|
let ConstCx { tcx, body, .. } = *ccx;
|
||||||
|
|
||||||
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
|
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body)
|
.into_results_cursor(body)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -94,8 +93,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
||||||
let ConstCx { tcx, body, .. } = *ccx;
|
let ConstCx { tcx, body, .. } = *ccx;
|
||||||
|
|
||||||
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
|
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body)
|
.into_results_cursor(body)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,8 +122,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
||||||
let ConstCx { tcx, body, .. } = *ccx;
|
let ConstCx { tcx, body, .. } = *ccx;
|
||||||
|
|
||||||
FlowSensitiveAnalysis::new(HasMutInterior, ccx)
|
FlowSensitiveAnalysis::new(HasMutInterior, ccx)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body)
|
.into_results_cursor(body)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -240,8 +237,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
||||||
let always_live_locals = &always_storage_live_locals(&ccx.body);
|
let always_live_locals = &always_storage_live_locals(&ccx.body);
|
||||||
let mut maybe_storage_live =
|
let mut maybe_storage_live =
|
||||||
MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
|
MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
|
||||||
.into_engine(ccx.tcx, &ccx.body)
|
.iterate_to_fixpoint(ccx.tcx, &ccx.body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(&ccx.body);
|
.into_results_cursor(&ccx.body);
|
||||||
|
|
||||||
// And then check all `Return` in the MIR, and if a local is "maybe live" at a
|
// And then check all `Return` in the MIR, and if a local is "maybe live" at a
|
||||||
|
|
|
@ -7,18 +7,17 @@
|
||||||
//!
|
//!
|
||||||
//! The `impls` module contains several examples of dataflow analyses.
|
//! 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` on your type that impls `Analysis` to get a `Results`. From
|
||||||
//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the
|
//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem,
|
||||||
//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use
|
//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses
|
||||||
//! `visit_results`. The following example uses the `ResultsCursor` approach.
|
//! the `ResultsCursor` approach.
|
||||||
//!
|
//!
|
||||||
//! ```ignore (cross-crate-imports)
|
//! ```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>) {
|
//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
|
||||||
//! let analysis = MyAnalysis::new()
|
//! let analysis = MyAnalysis::new()
|
||||||
//! .into_engine(tcx, body)
|
//! .iterate_to_fixpoint(tcx, body, None)
|
||||||
//! .iterate_to_fixpoint()
|
|
||||||
//! .into_results_cursor(body);
|
//! .into_results_cursor(body);
|
||||||
//!
|
//!
|
||||||
//! // Print the dataflow state *after* each statement in the start block.
|
//! // Print the dataflow state *after* each statement in the start block.
|
||||||
|
@ -34,23 +33,29 @@
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use rustc_index::Idx;
|
use rustc_data_structures::work_queue::WorkQueue;
|
||||||
use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
|
use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
|
||||||
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
|
use rustc_index::{Idx, IndexVec};
|
||||||
|
use rustc_middle::bug;
|
||||||
|
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use self::results::write_graphviz_results;
|
||||||
|
use super::fmt::DebugWithContext;
|
||||||
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod direction;
|
mod direction;
|
||||||
mod engine;
|
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
pub mod graphviz;
|
pub mod graphviz;
|
||||||
pub mod lattice;
|
pub mod lattice;
|
||||||
|
mod results;
|
||||||
mod visitor;
|
mod visitor;
|
||||||
|
|
||||||
pub use self::cursor::ResultsCursor;
|
pub use self::cursor::ResultsCursor;
|
||||||
pub use self::direction::{Backward, Direction, Forward};
|
pub use self::direction::{Backward, Direction, Forward};
|
||||||
pub use self::engine::{Engine, Results};
|
|
||||||
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
|
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
|
||||||
|
pub use self::results::Results;
|
||||||
pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
|
pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
|
||||||
|
|
||||||
/// Analysis domains are all bitsets of various kinds. This trait holds
|
/// Analysis domains are all bitsets of various kinds. This trait holds
|
||||||
|
@ -223,26 +228,92 @@ pub trait Analysis<'tcx> {
|
||||||
|
|
||||||
/* Extension methods */
|
/* 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:
|
/// You shouldn't need to override this. Its purpose is to enable method chaining like so:
|
||||||
///
|
///
|
||||||
/// ```ignore (cross-crate-imports)
|
/// ```ignore (cross-crate-imports)
|
||||||
/// let results = MyAnalysis::new(tcx, body)
|
/// let results = MyAnalysis::new(tcx, body)
|
||||||
/// .into_engine(tcx, body, def_id)
|
/// .iterate_to_fixpoint(tcx, body, None)
|
||||||
/// .iterate_to_fixpoint()
|
|
||||||
/// .into_results_cursor(body);
|
/// .into_results_cursor(body);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
/// You can optionally add a `pass_name` to the graphviz output for this particular run of a
|
||||||
fn into_engine<'mir>(
|
/// dataflow analysis. Some analyses are run multiple times in the compilation pipeline.
|
||||||
self,
|
/// Without a `pass_name` to differentiates them, only the results for the latest run will be
|
||||||
|
/// saved.
|
||||||
|
fn iterate_to_fixpoint<'mir>(
|
||||||
|
mut self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
) -> Engine<'mir, 'tcx, Self>
|
pass_name: Option<&'static str>,
|
||||||
|
) -> Results<'tcx, Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
Self::Domain: DebugWithContext<Self>,
|
||||||
{
|
{
|
||||||
Engine::new(tcx, body, self)
|
let mut entry_sets =
|
||||||
|
IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
|
||||||
|
self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
|
||||||
|
|
||||||
|
if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) {
|
||||||
|
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
|
||||||
|
|
||||||
|
if Self::Direction::IS_FORWARD {
|
||||||
|
for (bb, _) in traversal::reverse_postorder(body) {
|
||||||
|
dirty_queue.insert(bb);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reverse post-order on the reverse CFG may generate a better iteration order for
|
||||||
|
// backward dataflow analyses, but probably not enough to matter.
|
||||||
|
for (bb, _) in traversal::postorder(body) {
|
||||||
|
dirty_queue.insert(bb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `state` is not actually used between iterations;
|
||||||
|
// this is just an optimization to avoid reallocating
|
||||||
|
// every iteration.
|
||||||
|
let mut state = self.bottom_value(body);
|
||||||
|
while let Some(bb) = dirty_queue.pop() {
|
||||||
|
let bb_data = &body[bb];
|
||||||
|
|
||||||
|
// Set the state to the entry state of the block.
|
||||||
|
// This is equivalent to `state = entry_sets[bb].clone()`,
|
||||||
|
// but it saves an allocation, thus improving compile times.
|
||||||
|
state.clone_from(&entry_sets[bb]);
|
||||||
|
|
||||||
|
// Apply the block transfer function, using the cached one if it exists.
|
||||||
|
let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);
|
||||||
|
|
||||||
|
Self::Direction::join_state_into_successors_of(
|
||||||
|
&mut self,
|
||||||
|
body,
|
||||||
|
&mut state,
|
||||||
|
bb,
|
||||||
|
edges,
|
||||||
|
|target: BasicBlock, state: &Self::Domain| {
|
||||||
|
let set_changed = entry_sets[target].join(state);
|
||||||
|
if set_changed {
|
||||||
|
dirty_queue.insert(target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let results = Results { analysis: self, entry_sets };
|
||||||
|
|
||||||
|
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
|
||||||
|
let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
|
||||||
|
if let Err(e) = res {
|
||||||
|
error!("Failed to write graphviz dataflow results: {}", e);
|
||||||
|
}
|
||||||
|
results
|
||||||
|
} else {
|
||||||
|
results
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
//! A solver for dataflow problems.
|
//! Dataflow analysis results.
|
||||||
|
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use rustc_data_structures::work_queue::WorkQueue;
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::bug;
|
|
||||||
use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
|
use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_span::symbol::{Symbol, sym};
|
use rustc_span::symbol::{Symbol, sym};
|
||||||
use tracing::{debug, error};
|
use tracing::debug;
|
||||||
use {rustc_ast as ast, rustc_graphviz as dot};
|
use {rustc_ast as ast, rustc_graphviz as dot};
|
||||||
|
|
||||||
use super::fmt::DebugWithContext;
|
use super::fmt::DebugWithContext;
|
||||||
use super::{
|
use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
|
||||||
Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results,
|
|
||||||
};
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
|
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
|
||||||
};
|
};
|
||||||
|
@ -65,124 +61,17 @@ where
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
|
||||||
) {
|
) {
|
||||||
let blocks = mir::traversal::reachable(body);
|
let blocks = traversal::reachable(body);
|
||||||
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
|
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A>
|
|
||||||
where
|
|
||||||
A: Analysis<'tcx, Domain = D>,
|
|
||||||
D: Clone + JoinSemiLattice,
|
|
||||||
{
|
|
||||||
/// 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 {
|
|
||||||
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]);
|
|
||||||
|
|
||||||
if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body)
|
|
||||||
{
|
|
||||||
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 {
|
|
||||||
for (bb, _) in traversal::reverse_postorder(body) {
|
|
||||||
dirty_queue.insert(bb);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Reverse post-order on the reverse CFG may generate a better iteration order for
|
|
||||||
// backward dataflow analyses, but probably not enough to matter.
|
|
||||||
for (bb, _) in traversal::postorder(body) {
|
|
||||||
dirty_queue.insert(bb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// `state` is not actually used between iterations;
|
|
||||||
// this is just an optimization to avoid reallocating
|
|
||||||
// every iteration.
|
|
||||||
let mut state = analysis.bottom_value(body);
|
|
||||||
while let Some(bb) = dirty_queue.pop() {
|
|
||||||
let bb_data = &body[bb];
|
|
||||||
|
|
||||||
// Set the state to the entry state of the block.
|
|
||||||
// This is equivalent to `state = entry_sets[bb].clone()`,
|
|
||||||
// but it saves an allocation, thus improving compile times.
|
|
||||||
state.clone_from(&entry_sets[bb]);
|
|
||||||
|
|
||||||
// Apply the block transfer function, using the cached one if it exists.
|
|
||||||
let edges =
|
|
||||||
A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data);
|
|
||||||
|
|
||||||
A::Direction::join_state_into_successors_of(
|
|
||||||
&mut analysis,
|
|
||||||
body,
|
|
||||||
&mut state,
|
|
||||||
bb,
|
|
||||||
edges,
|
|
||||||
|target: BasicBlock, state: &A::Domain| {
|
|
||||||
let set_changed = entry_sets[target].join(state);
|
|
||||||
if set_changed {
|
|
||||||
dirty_queue.insert(target);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let results = Results { analysis, entry_sets };
|
|
||||||
|
|
||||||
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
|
|
||||||
let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
|
|
||||||
if let Err(e) = res {
|
|
||||||
error!("Failed to write graphviz dataflow results: {}", e);
|
|
||||||
}
|
|
||||||
results
|
|
||||||
} else {
|
|
||||||
results
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Graphviz
|
// Graphviz
|
||||||
|
|
||||||
/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
|
/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
|
||||||
/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
|
/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
|
||||||
/// the same.
|
/// the same.
|
||||||
fn write_graphviz_results<'tcx, A>(
|
pub(super) fn write_graphviz_results<'tcx, A>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &mir::Body<'tcx>,
|
body: &mir::Body<'tcx>,
|
||||||
results: Results<'tcx, A>,
|
results: Results<'tcx, A>,
|
|
@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{
|
||||||
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
|
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
|
||||||
};
|
};
|
||||||
pub use self::framework::{
|
pub use self::framework::{
|
||||||
Analysis, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, MaybeReachable,
|
Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
|
||||||
Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz,
|
ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
|
||||||
lattice, visit_results,
|
visit_results,
|
||||||
};
|
};
|
||||||
use self::move_paths::MoveData;
|
use self::move_paths::MoveData;
|
||||||
|
|
||||||
|
|
|
@ -43,31 +43,28 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||||
let move_data = MoveData::gather_moves(body, tcx, |_| true);
|
let move_data = MoveData::gather_moves(body, tcx, |_| true);
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
|
||||||
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
let flow_inits =
|
||||||
.into_engine(tcx, body)
|
MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None);
|
||||||
.iterate_to_fixpoint();
|
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
|
sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
||||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
|
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None);
|
||||||
.iterate_to_fixpoint();
|
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
||||||
let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
|
let flow_def_inits =
|
||||||
.into_engine(tcx, body)
|
DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None);
|
||||||
.iterate_to_fixpoint();
|
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
||||||
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
|
let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
|
sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
|
@ -666,14 +666,13 @@ fn locals_live_across_suspend_points<'tcx>(
|
||||||
// Calculate when MIR locals have live storage. This gives us an upper bound of their
|
// Calculate when MIR locals have live storage. This gives us an upper bound of their
|
||||||
// lifetimes.
|
// lifetimes.
|
||||||
let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
|
let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
// Calculate the MIR locals which have been previously
|
// Calculate the MIR locals which have been previously
|
||||||
// borrowed (even if they are still active).
|
// borrowed (even if they are still active).
|
||||||
let borrowed_locals_results =
|
let borrowed_locals_results =
|
||||||
MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint();
|
MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine"));
|
||||||
|
|
||||||
let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
|
let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
|
||||||
|
|
||||||
|
@ -681,16 +680,12 @@ fn locals_live_across_suspend_points<'tcx>(
|
||||||
// for.
|
// for.
|
||||||
let mut requires_storage_cursor =
|
let mut requires_storage_cursor =
|
||||||
MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
|
MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
// Calculate the liveness of MIR locals ignoring borrows.
|
// Calculate the liveness of MIR locals ignoring borrows.
|
||||||
let mut liveness = MaybeLiveLocals
|
let mut liveness =
|
||||||
.into_engine(tcx, body)
|
MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body);
|
||||||
.pass_name("coroutine")
|
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
|
||||||
|
|
||||||
let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks);
|
let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks);
|
||||||
let mut live_locals_at_suspension_points = Vec::new();
|
let mut live_locals_at_suspension_points = Vec::new();
|
||||||
|
|
|
@ -59,7 +59,7 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
|
||||||
// Perform the actual dataflow analysis.
|
// Perform the actual dataflow analysis.
|
||||||
let analysis = ConstAnalysis::new(tcx, body, map);
|
let analysis = ConstAnalysis::new(tcx, body, map);
|
||||||
let mut results = debug_span!("analyze")
|
let mut results = debug_span!("analyze")
|
||||||
.in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
|
.in_scope(|| analysis.wrap().iterate_to_fixpoint(tcx, body, None));
|
||||||
|
|
||||||
// Collect results and patch the body afterwards.
|
// Collect results and patch the body afterwards.
|
||||||
let mut visitor = Collector::new(tcx, &body.local_decls);
|
let mut visitor = Collector::new(tcx, &body.local_decls);
|
||||||
|
|
|
@ -37,8 +37,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
always_live.union(&borrowed_locals);
|
always_live.union(&borrowed_locals);
|
||||||
|
|
||||||
let mut live = MaybeTransitiveLiveLocals::new(&always_live)
|
let mut live = MaybeTransitiveLiveLocals::new(&always_live)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
// For blocks with a call terminator, if an argument copy can be turned into a move,
|
// For blocks with a call terminator, if an argument copy can be turned into a move,
|
||||||
|
|
|
@ -169,10 +169,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
|
||||||
|
|
||||||
let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
|
let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
|
||||||
|
|
||||||
let live = MaybeLiveLocals
|
let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp"));
|
||||||
.into_engine(tcx, body)
|
|
||||||
.pass_name("MaybeLiveLocals-DestinationPropagation")
|
|
||||||
.iterate_to_fixpoint();
|
|
||||||
let points = DenseLocationMap::new(body);
|
let points = DenseLocationMap::new(body);
|
||||||
let mut live = save_as_intervals(&points, body, live);
|
let mut live = save_as_intervals(&points, body, live);
|
||||||
|
|
||||||
|
|
|
@ -64,18 +64,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
|
||||||
|
|
||||||
let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data)
|
let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data)
|
||||||
.skipping_unreachable_unwind()
|
.skipping_unreachable_unwind()
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, Some("elaborate_drops"))
|
||||||
.pass_name("elaborate_drops")
|
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
let dead_unwinds = compute_dead_unwinds(body, &mut inits);
|
let dead_unwinds = compute_dead_unwinds(body, &mut inits);
|
||||||
|
|
||||||
let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data)
|
let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data)
|
||||||
.mark_inactive_variants_as_uninit()
|
.mark_inactive_variants_as_uninit()
|
||||||
.skipping_unreachable_unwind(dead_unwinds)
|
.skipping_unreachable_unwind(dead_unwinds)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, Some("elaborate_drops"))
|
||||||
.pass_name("elaborate_drops")
|
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths);
|
let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths);
|
||||||
|
|
|
@ -17,13 +17,11 @@ pub(super) fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String
|
||||||
let always_live_locals = &always_storage_live_locals(body);
|
let always_live_locals = &always_storage_live_locals(body);
|
||||||
|
|
||||||
let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
|
let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals))
|
let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals))
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
let mut lint = Lint {
|
let mut lint = Lint {
|
||||||
|
|
|
@ -126,8 +126,7 @@ fn compute_replacement<'tcx>(
|
||||||
// Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is
|
// Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is
|
||||||
// definitely live.
|
// definitely live.
|
||||||
let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals))
|
let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals))
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, None)
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
// Map for each local to the pointee.
|
// Map for each local to the pointee.
|
||||||
|
|
|
@ -22,9 +22,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
|
||||||
let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env));
|
let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env));
|
||||||
|
|
||||||
let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||||
.into_engine(tcx, body)
|
.iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops"))
|
||||||
.pass_name("remove_uninit_drops")
|
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
let mut to_remove = vec![];
|
let mut to_remove = vec![];
|
||||||
|
|
|
@ -185,9 +185,7 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
|
||||||
vis.into_map(cx)
|
vis.into_map(cx)
|
||||||
};
|
};
|
||||||
let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
|
let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
|
||||||
.into_engine(cx.tcx, mir)
|
.iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone"))
|
||||||
.pass_name("redundant_clone")
|
|
||||||
.iterate_to_fixpoint()
|
|
||||||
.into_results_cursor(mir);
|
.into_results_cursor(mir);
|
||||||
let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
|
let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
|
||||||
vis.visit_body(mir);
|
vis.visit_body(mir);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue