summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_dataflow/src/framework/engine.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_dataflow/src/framework/engine.rs')
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs114
1 files changed, 89 insertions, 25 deletions
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 3e8f792e6..c755d7588 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -5,7 +5,9 @@ use crate::errors::{
};
use crate::framework::BitSetExt;
+use std::borrow::Borrow;
use std::ffi::OsString;
+use std::marker::PhantomData;
use std::path::PathBuf;
use rustc_ast as ast;
@@ -22,54 +24,108 @@ use rustc_span::symbol::{sym, Symbol};
use super::fmt::DebugWithContext;
use super::graphviz;
use super::{
- visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
- ResultsCursor, ResultsVisitor,
+ visit_results, Analysis, AnalysisDomain, CloneAnalysis, Direction, GenKill, GenKillAnalysis,
+ GenKillSet, JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
+ ResultsVisitor,
};
+pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
+
/// A dataflow analysis that has converged to fixpoint.
-pub struct Results<'tcx, A>
+pub struct Results<'tcx, A, E = EntrySets<'tcx, A>>
where
A: Analysis<'tcx>,
{
pub analysis: A,
- pub(super) entry_sets: IndexVec<BasicBlock, A::Domain>,
+ pub(super) entry_sets: E,
+ pub(super) _marker: PhantomData<&'tcx ()>,
}
-impl<'tcx, A> Results<'tcx, A>
+/// `Results` type with a cloned `Analysis` and borrowed entry sets.
+pub type ResultsCloned<'res, 'tcx, A> = Results<'tcx, A, &'res EntrySets<'tcx, A>>;
+
+impl<'tcx, A, E> Results<'tcx, A, E>
where
A: Analysis<'tcx>,
+ E: Borrow<EntrySets<'tcx, A>>,
{
/// Creates a `ResultsCursor` that can inspect these `Results`.
pub fn into_results_cursor<'mir>(
self,
body: &'mir mir::Body<'tcx>,
- ) -> ResultsCursor<'mir, 'tcx, A> {
+ ) -> ResultsCursor<'mir, 'tcx, A, Self> {
ResultsCursor::new(body, self)
}
/// Gets the dataflow state for the given block.
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
- &self.entry_sets[block]
+ &self.entry_sets.borrow()[block]
}
pub fn visit_with<'mir>(
- &self,
+ &mut self,
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
) {
visit_results(body, blocks, self, vis)
}
pub fn visit_reachable_with<'mir>(
- &self,
+ &mut self,
body: &'mir mir::Body<'tcx>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
) {
let blocks = mir::traversal::reachable(body);
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
}
}
+impl<'tcx, A> Results<'tcx, A>
+where
+ A: Analysis<'tcx>,
+{
+ /// Creates a `ResultsCursor` that can inspect these `Results`.
+ pub fn as_results_cursor<'a, 'mir>(
+ &'a mut self,
+ body: &'mir mir::Body<'tcx>,
+ ) -> ResultsRefCursor<'a, 'mir, 'tcx, A> {
+ ResultsCursor::new(body, self)
+ }
+}
+impl<'tcx, A> Results<'tcx, A>
+where
+ A: Analysis<'tcx> + CloneAnalysis,
+{
+ /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
+ pub fn clone_analysis(&self) -> ResultsCloned<'_, 'tcx, A> {
+ Results {
+ analysis: self.analysis.clone_analysis(),
+ entry_sets: &self.entry_sets,
+ _marker: PhantomData,
+ }
+ }
+
+ /// Creates a `ResultsCursor` that can inspect these `Results`.
+ pub fn cloned_results_cursor<'mir>(
+ &self,
+ body: &'mir mir::Body<'tcx>,
+ ) -> ResultsClonedCursor<'_, 'mir, 'tcx, A> {
+ self.clone_analysis().into_results_cursor(body)
+ }
+}
+impl<'res, 'tcx, A> Results<'tcx, A, &'res EntrySets<'tcx, A>>
+where
+ A: Analysis<'tcx> + CloneAnalysis,
+{
+ /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
+ pub fn reclone_analysis(&self) -> Self {
+ Results {
+ analysis: self.analysis.clone_analysis(),
+ entry_sets: self.entry_sets,
+ _marker: PhantomData,
+ }
+ }
+}
/// A solver for dataflow problems.
pub struct Engine<'a, 'tcx, A>
@@ -98,7 +154,7 @@ where
T: Idx,
{
/// Creates a new `Engine` to solve a gen-kill dataflow problem.
- pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
+ pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, mut analysis: A) -> Self {
// If there are no back-edges in the control-flow graph, we only ever need to apply the
// transfer function for each block exactly once (assuming that we process blocks in RPO).
//
@@ -114,7 +170,7 @@ where
for (block, block_data) in body.basic_blocks.iter_enumerated() {
let trans = &mut trans_for_block[block];
- A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data);
+ A::Direction::gen_kill_effects_in_block(&mut analysis, trans, block, block_data);
}
let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
@@ -171,7 +227,13 @@ where
A::Domain: DebugWithContext<A>,
{
let Engine {
- analysis, body, mut entry_sets, tcx, apply_trans_for_block, pass_name, ..
+ mut analysis,
+ body,
+ mut entry_sets,
+ tcx,
+ apply_trans_for_block,
+ pass_name,
+ ..
} = self;
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
@@ -203,11 +265,13 @@ where
// Apply the block transfer function, using the cached one if it exists.
match &apply_trans_for_block {
Some(apply) => apply(bb, &mut state),
- None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data),
+ None => {
+ A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data)
+ }
}
A::Direction::join_state_into_successors_of(
- &analysis,
+ &mut analysis,
tcx,
body,
&mut state,
@@ -221,11 +285,13 @@ where
);
}
- let results = Results { analysis, entry_sets };
+ let mut results = Results { analysis, entry_sets, _marker: PhantomData };
- let res = write_graphviz_results(tcx, &body, &results, pass_name);
- if let Err(e) = res {
- error!("Failed to write graphviz dataflow results: {}", e);
+ if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
+ let res = write_graphviz_results(tcx, &body, &mut results, pass_name);
+ if let Err(e) = res {
+ error!("Failed to write graphviz dataflow results: {}", e);
+ }
}
results
@@ -235,11 +301,11 @@ where
// Graphviz
/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
-/// `rustc_mir` attributes.
+/// `rustc_mir` attributes and `-Z dump-mir-dataflow`.
fn write_graphviz_results<'tcx, A>(
tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
- results: &Results<'tcx, A>,
+ results: &mut Results<'tcx, A>,
pass_name: Option<&'static str>,
) -> std::io::Result<()>
where
@@ -264,9 +330,7 @@ where
io::BufWriter::new(fs::File::create(&path)?)
}
- None if tcx.sess.opts.unstable_opts.dump_mir_dataflow
- && dump_enabled(tcx, A::NAME, def_id) =>
- {
+ None if dump_enabled(tcx, A::NAME, def_id) => {
create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
}