about summary refs log tree commit diff
path: root/compiler/rustc_mir_dataflow/src/framework/engine.rs
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2023-02-20 17:28:03 -0500
committerJason Newcomb <jsnewcomb@pm.me>2023-05-18 17:46:39 -0400
commiteaddc3707520988f8bc2d267cb192d2f0c63ee80 (patch)
tree0ed197fa7a525c6543e08b8bae3fad983241dc47 /compiler/rustc_mir_dataflow/src/framework/engine.rs
parentfdd030127cc68afec44a8d3f6341525dd34e50ae (diff)
downloadrust-eaddc3707520988f8bc2d267cb192d2f0c63ee80.tar.gz
rust-eaddc3707520988f8bc2d267cb192d2f0c63ee80.zip
Take MIR dataflow analyses by mutable reference.
Diffstat (limited to 'compiler/rustc_mir_dataflow/src/framework/engine.rs')
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs102
1 files changed, 83 insertions, 19 deletions
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 3e8f792e634..4bdfa35fc70 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,9 +285,9 @@ 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);
+        let res = write_graphviz_results(tcx, body, &mut results, pass_name);
         if let Err(e) = res {
             error!("Failed to write graphviz dataflow results: {}", e);
         }
@@ -239,7 +303,7 @@ where
 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