| 
7 | 7 | //!  | 
8 | 8 | //! The `impls` module contains several examples of dataflow analyses.  | 
9 | 9 | //!  | 
10 |  | -//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait,  | 
11 |  | -//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the  | 
12 |  | -//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use  | 
13 |  | -//! `visit_results`. The following example uses the `ResultsCursor` approach.  | 
 | 10 | +//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From  | 
 | 11 | +//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem,  | 
 | 12 | +//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses  | 
 | 13 | +//! the `ResultsCursor` approach.  | 
14 | 14 | //!  | 
15 | 15 | //! ```ignore (cross-crate-imports)  | 
16 |  | -//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available.  | 
 | 16 | +//! use rustc_const_eval::dataflow::Analysis; // Makes `iterate_to_fixpoint` available.  | 
17 | 17 | //!  | 
18 | 18 | //! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {  | 
19 | 19 | //!     let analysis = MyAnalysis::new()  | 
20 |  | -//!         .into_engine(tcx, body)  | 
21 |  | -//!         .iterate_to_fixpoint()  | 
 | 20 | +//!         .iterate_to_fixpoint(tcx, body, None)  | 
22 | 21 | //!         .into_results_cursor(body);  | 
23 | 22 | //!  | 
24 | 23 | //!     // Print the dataflow state *after* each statement in the start block.  | 
 | 
34 | 33 | 
  | 
35 | 34 | use std::cmp::Ordering;  | 
36 | 35 | 
 
  | 
37 |  | -use rustc_index::Idx;  | 
 | 36 | +use rustc_data_structures::work_queue::WorkQueue;  | 
38 | 37 | use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};  | 
39 |  | -use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};  | 
 | 38 | +use rustc_index::{Idx, IndexVec};  | 
 | 39 | +use rustc_middle::bug;  | 
 | 40 | +use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};  | 
40 | 41 | use rustc_middle::ty::TyCtxt;  | 
 | 42 | +use tracing::error;  | 
 | 43 | + | 
 | 44 | +use self::results::write_graphviz_results;  | 
 | 45 | +use super::fmt::DebugWithContext;  | 
41 | 46 | 
 
  | 
42 | 47 | mod cursor;  | 
43 | 48 | mod direction;  | 
44 |  | -mod engine;  | 
45 | 49 | pub mod fmt;  | 
46 | 50 | pub mod graphviz;  | 
47 | 51 | pub mod lattice;  | 
 | 52 | +mod results;  | 
48 | 53 | mod visitor;  | 
49 | 54 | 
 
  | 
50 | 55 | pub use self::cursor::ResultsCursor;  | 
51 | 56 | pub use self::direction::{Backward, Direction, Forward};  | 
52 |  | -pub use self::engine::{Engine, Results};  | 
53 | 57 | pub use self::lattice::{JoinSemiLattice, MaybeReachable};  | 
 | 58 | +pub use self::results::Results;  | 
54 | 59 | pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};  | 
55 | 60 | 
 
  | 
56 | 61 | /// Analysis domains are all bitsets of various kinds. This trait holds  | 
@@ -223,26 +228,92 @@ pub trait Analysis<'tcx> {  | 
223 | 228 | 
 
  | 
224 | 229 |     /* Extension methods */  | 
225 | 230 | 
 
  | 
226 |  | -    /// Creates an `Engine` to find the fixpoint for this dataflow problem.  | 
 | 231 | +    /// Finds the fixpoint for this dataflow problem.  | 
227 | 232 |     ///  | 
228 | 233 |     /// You shouldn't need to override this. Its purpose is to enable method chaining like so:  | 
229 | 234 |     ///  | 
230 | 235 |     /// ```ignore (cross-crate-imports)  | 
231 | 236 |     /// let results = MyAnalysis::new(tcx, body)  | 
232 |  | -    ///     .into_engine(tcx, body, def_id)  | 
233 |  | -    ///     .iterate_to_fixpoint()  | 
 | 237 | +    ///     .iterate_to_fixpoint(tcx, body, None)  | 
234 | 238 |     ///     .into_results_cursor(body);  | 
235 | 239 |     /// ```  | 
236 |  | -    #[inline]  | 
237 |  | -    fn into_engine<'mir>(  | 
238 |  | -        self,  | 
 | 240 | +    /// You can optionally add a `pass_name` to the graphviz output for this particular run of a  | 
 | 241 | +    /// dataflow analysis. Some analyses are run multiple times in the compilation pipeline.  | 
 | 242 | +    /// Without a `pass_name` to differentiates them, only the results for the latest run will be  | 
 | 243 | +    /// saved.  | 
 | 244 | +    fn iterate_to_fixpoint<'mir>(  | 
 | 245 | +        mut self,  | 
239 | 246 |         tcx: TyCtxt<'tcx>,  | 
240 | 247 |         body: &'mir mir::Body<'tcx>,  | 
241 |  | -    ) -> Engine<'mir, 'tcx, Self>  | 
 | 248 | +        pass_name: Option<&'static str>,  | 
 | 249 | +    ) -> Results<'tcx, Self>  | 
242 | 250 |     where  | 
243 | 251 |         Self: Sized,  | 
 | 252 | +        Self::Domain: DebugWithContext<Self>,  | 
244 | 253 |     {  | 
245 |  | -        Engine::new(tcx, body, self)  | 
 | 254 | +        let mut entry_sets =  | 
 | 255 | +            IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());  | 
 | 256 | +        self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);  | 
 | 257 | + | 
 | 258 | +        if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) {  | 
 | 259 | +            bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");  | 
 | 260 | +        }  | 
 | 261 | + | 
 | 262 | +        let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());  | 
 | 263 | + | 
 | 264 | +        if Self::Direction::IS_FORWARD {  | 
 | 265 | +            for (bb, _) in traversal::reverse_postorder(body) {  | 
 | 266 | +                dirty_queue.insert(bb);  | 
 | 267 | +            }  | 
 | 268 | +        } else {  | 
 | 269 | +            // Reverse post-order on the reverse CFG may generate a better iteration order for  | 
 | 270 | +            // backward dataflow analyses, but probably not enough to matter.  | 
 | 271 | +            for (bb, _) in traversal::postorder(body) {  | 
 | 272 | +                dirty_queue.insert(bb);  | 
 | 273 | +            }  | 
 | 274 | +        }  | 
 | 275 | + | 
 | 276 | +        // `state` is not actually used between iterations;  | 
 | 277 | +        // this is just an optimization to avoid reallocating  | 
 | 278 | +        // every iteration.  | 
 | 279 | +        let mut state = self.bottom_value(body);  | 
 | 280 | +        while let Some(bb) = dirty_queue.pop() {  | 
 | 281 | +            let bb_data = &body[bb];  | 
 | 282 | + | 
 | 283 | +            // Set the state to the entry state of the block.  | 
 | 284 | +            // This is equivalent to `state = entry_sets[bb].clone()`,  | 
 | 285 | +            // but it saves an allocation, thus improving compile times.  | 
 | 286 | +            state.clone_from(&entry_sets[bb]);  | 
 | 287 | + | 
 | 288 | +            // Apply the block transfer function, using the cached one if it exists.  | 
 | 289 | +            let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);  | 
 | 290 | + | 
 | 291 | +            Self::Direction::join_state_into_successors_of(  | 
 | 292 | +                &mut self,  | 
 | 293 | +                body,  | 
 | 294 | +                &mut state,  | 
 | 295 | +                bb,  | 
 | 296 | +                edges,  | 
 | 297 | +                |target: BasicBlock, state: &Self::Domain| {  | 
 | 298 | +                    let set_changed = entry_sets[target].join(state);  | 
 | 299 | +                    if set_changed {  | 
 | 300 | +                        dirty_queue.insert(target);  | 
 | 301 | +                    }  | 
 | 302 | +                },  | 
 | 303 | +            );  | 
 | 304 | +        }  | 
 | 305 | + | 
 | 306 | +        let results = Results { analysis: self, entry_sets };  | 
 | 307 | + | 
 | 308 | +        if tcx.sess.opts.unstable_opts.dump_mir_dataflow {  | 
 | 309 | +            let (res, results) = write_graphviz_results(tcx, body, results, pass_name);  | 
 | 310 | +            if let Err(e) = res {  | 
 | 311 | +                error!("Failed to write graphviz dataflow results: {}", e);  | 
 | 312 | +            }  | 
 | 313 | +            results  | 
 | 314 | +        } else {  | 
 | 315 | +            results  | 
 | 316 | +        }  | 
246 | 317 |     }  | 
247 | 318 | }  | 
248 | 319 | 
 
  | 
 | 
0 commit comments