Skip to content

Commit 2055237

Browse files
authored
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``
2 parents 2480e3b + d78e7bb commit 2055237

File tree

15 files changed

+139
-205
lines changed

15 files changed

+139
-205
lines changed

compiler/rustc_borrowck/src/lib.rs

+16-15
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,7 @@ fn do_mir_borrowck<'tcx>(
193193
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
194194

195195
let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
196-
.into_engine(tcx, body)
197-
.pass_name("borrowck")
198-
.iterate_to_fixpoint()
196+
.iterate_to_fixpoint(tcx, body, Some("borrowck"))
199197
.into_results_cursor(body);
200198

201199
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>(
243241
// usage significantly on some benchmarks.
244242
drop(flow_inits);
245243

246-
let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set)
247-
.into_engine(tcx, body)
248-
.pass_name("borrowck")
249-
.iterate_to_fixpoint();
250-
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
251-
.into_engine(tcx, body)
252-
.pass_name("borrowck")
253-
.iterate_to_fixpoint();
254-
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data)
255-
.into_engine(tcx, body)
256-
.pass_name("borrowck")
257-
.iterate_to_fixpoint();
244+
let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set).iterate_to_fixpoint(
245+
tcx,
246+
body,
247+
Some("borrowck"),
248+
);
249+
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
250+
tcx,
251+
body,
252+
Some("borrowck"),
253+
);
254+
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
255+
tcx,
256+
body,
257+
Some("borrowck"),
258+
);
258259

259260
let movable_coroutine =
260261
// The first argument is the coroutine type passed by value

compiler/rustc_const_eval/src/check_consts/check.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
6464
let ConstCx { tcx, body, .. } = *ccx;
6565

6666
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
67-
.into_engine(tcx, body)
68-
.iterate_to_fixpoint()
67+
.iterate_to_fixpoint(tcx, body, None)
6968
.into_results_cursor(body)
7069
});
7170

@@ -94,8 +93,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
9493
let ConstCx { tcx, body, .. } = *ccx;
9594

9695
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
97-
.into_engine(tcx, body)
98-
.iterate_to_fixpoint()
96+
.iterate_to_fixpoint(tcx, body, None)
9997
.into_results_cursor(body)
10098
});
10199

@@ -124,8 +122,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
124122
let ConstCx { tcx, body, .. } = *ccx;
125123

126124
FlowSensitiveAnalysis::new(HasMutInterior, ccx)
127-
.into_engine(tcx, body)
128-
.iterate_to_fixpoint()
125+
.iterate_to_fixpoint(tcx, body, None)
129126
.into_results_cursor(body)
130127
});
131128

@@ -240,8 +237,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
240237
let always_live_locals = &always_storage_live_locals(&ccx.body);
241238
let mut maybe_storage_live =
242239
MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
243-
.into_engine(ccx.tcx, &ccx.body)
244-
.iterate_to_fixpoint()
240+
.iterate_to_fixpoint(ccx.tcx, &ccx.body, None)
245241
.into_results_cursor(&ccx.body);
246242

247243
// And then check all `Return` in the MIR, and if a local is "maybe live" at a

compiler/rustc_mir_dataflow/src/framework/mod.rs

+90-19
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,17 @@
77
//!
88
//! The `impls` module contains several examples of dataflow analyses.
99
//!
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.
1414
//!
1515
//! ```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.
1717
//!
1818
//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
1919
//! let analysis = MyAnalysis::new()
20-
//! .into_engine(tcx, body)
21-
//! .iterate_to_fixpoint()
20+
//! .iterate_to_fixpoint(tcx, body, None)
2221
//! .into_results_cursor(body);
2322
//!
2423
//! // Print the dataflow state *after* each statement in the start block.
@@ -34,23 +33,29 @@
3433
3534
use std::cmp::Ordering;
3635

37-
use rustc_index::Idx;
36+
use rustc_data_structures::work_queue::WorkQueue;
3837
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};
4041
use rustc_middle::ty::TyCtxt;
42+
use tracing::error;
43+
44+
use self::results::write_graphviz_results;
45+
use super::fmt::DebugWithContext;
4146

4247
mod cursor;
4348
mod direction;
44-
mod engine;
4549
pub mod fmt;
4650
pub mod graphviz;
4751
pub mod lattice;
52+
mod results;
4853
mod visitor;
4954

5055
pub use self::cursor::ResultsCursor;
5156
pub use self::direction::{Backward, Direction, Forward};
52-
pub use self::engine::{Engine, Results};
5357
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
58+
pub use self::results::Results;
5459
pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
5560

5661
/// Analysis domains are all bitsets of various kinds. This trait holds
@@ -223,26 +228,92 @@ pub trait Analysis<'tcx> {
223228

224229
/* Extension methods */
225230

226-
/// Creates an `Engine` to find the fixpoint for this dataflow problem.
231+
/// Finds the fixpoint for this dataflow problem.
227232
///
228233
/// You shouldn't need to override this. Its purpose is to enable method chaining like so:
229234
///
230235
/// ```ignore (cross-crate-imports)
231236
/// let results = MyAnalysis::new(tcx, body)
232-
/// .into_engine(tcx, body, def_id)
233-
/// .iterate_to_fixpoint()
237+
/// .iterate_to_fixpoint(tcx, body, None)
234238
/// .into_results_cursor(body);
235239
/// ```
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,
239246
tcx: TyCtxt<'tcx>,
240247
body: &'mir mir::Body<'tcx>,
241-
) -> Engine<'mir, 'tcx, Self>
248+
pass_name: Option<&'static str>,
249+
) -> Results<'tcx, Self>
242250
where
243251
Self: Sized,
252+
Self::Domain: DebugWithContext<Self>,
244253
{
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+
}
246317
}
247318
}
248319

compiler/rustc_mir_dataflow/src/framework/engine.rs renamed to compiler/rustc_mir_dataflow/src/framework/results.rs

+5-116
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
1-
//! A solver for dataflow problems.
1+
//! Dataflow analysis results.
22
33
use std::ffi::OsString;
44
use std::path::PathBuf;
55

6-
use rustc_data_structures::work_queue::WorkQueue;
76
use rustc_hir::def_id::DefId;
87
use rustc_index::IndexVec;
9-
use rustc_middle::bug;
108
use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
119
use rustc_middle::ty::TyCtxt;
1210
use rustc_middle::ty::print::with_no_trimmed_paths;
1311
use rustc_span::symbol::{Symbol, sym};
14-
use tracing::{debug, error};
12+
use tracing::debug;
1513
use {rustc_ast as ast, rustc_graphviz as dot};
1614

1715
use super::fmt::DebugWithContext;
18-
use super::{
19-
Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results,
20-
};
16+
use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
2117
use crate::errors::{
2218
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
2319
};
@@ -65,124 +61,17 @@ where
6561
body: &'mir mir::Body<'tcx>,
6662
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
6763
) {
68-
let blocks = mir::traversal::reachable(body);
64+
let blocks = traversal::reachable(body);
6965
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
7066
}
7167
}
7268

73-
/// A solver for dataflow problems.
74-
pub struct Engine<'mir, 'tcx, A>
75-
where
76-
A: Analysis<'tcx>,
77-
{
78-
tcx: TyCtxt<'tcx>,
79-
body: &'mir mir::Body<'tcx>,
80-
entry_sets: IndexVec<BasicBlock, A::Domain>,
81-
pass_name: Option<&'static str>,
82-
analysis: A,
83-
}
84-
85-
impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A>
86-
where
87-
A: Analysis<'tcx, Domain = D>,
88-
D: Clone + JoinSemiLattice,
89-
{
90-
/// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
91-
/// function.
92-
pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self {
93-
let mut entry_sets =
94-
IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len());
95-
analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
96-
97-
if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body)
98-
{
99-
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
100-
}
101-
102-
Engine { analysis, tcx, body, pass_name: None, entry_sets }
103-
}
104-
105-
/// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
106-
///
107-
/// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name`
108-
/// to differentiate them. Otherwise, only the results for the latest run will be saved.
109-
pub fn pass_name(mut self, name: &'static str) -> Self {
110-
self.pass_name = Some(name);
111-
self
112-
}
113-
114-
/// Computes the fixpoint for this dataflow problem and returns it.
115-
pub fn iterate_to_fixpoint(self) -> Results<'tcx, A>
116-
where
117-
A::Domain: DebugWithContext<A>,
118-
{
119-
let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self;
120-
121-
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
122-
123-
if A::Direction::IS_FORWARD {
124-
for (bb, _) in traversal::reverse_postorder(body) {
125-
dirty_queue.insert(bb);
126-
}
127-
} else {
128-
// Reverse post-order on the reverse CFG may generate a better iteration order for
129-
// backward dataflow analyses, but probably not enough to matter.
130-
for (bb, _) in traversal::postorder(body) {
131-
dirty_queue.insert(bb);
132-
}
133-
}
134-
135-
// `state` is not actually used between iterations;
136-
// this is just an optimization to avoid reallocating
137-
// every iteration.
138-
let mut state = analysis.bottom_value(body);
139-
while let Some(bb) = dirty_queue.pop() {
140-
let bb_data = &body[bb];
141-
142-
// Set the state to the entry state of the block.
143-
// This is equivalent to `state = entry_sets[bb].clone()`,
144-
// but it saves an allocation, thus improving compile times.
145-
state.clone_from(&entry_sets[bb]);
146-
147-
// Apply the block transfer function, using the cached one if it exists.
148-
let edges =
149-
A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data);
150-
151-
A::Direction::join_state_into_successors_of(
152-
&mut analysis,
153-
body,
154-
&mut state,
155-
bb,
156-
edges,
157-
|target: BasicBlock, state: &A::Domain| {
158-
let set_changed = entry_sets[target].join(state);
159-
if set_changed {
160-
dirty_queue.insert(target);
161-
}
162-
},
163-
);
164-
}
165-
166-
let results = Results { analysis, entry_sets };
167-
168-
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
169-
let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
170-
if let Err(e) = res {
171-
error!("Failed to write graphviz dataflow results: {}", e);
172-
}
173-
results
174-
} else {
175-
results
176-
}
177-
}
178-
}
179-
18069
// Graphviz
18170

18271
/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
18372
/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
18473
/// the same.
185-
fn write_graphviz_results<'tcx, A>(
74+
pub(super) fn write_graphviz_results<'tcx, A>(
18675
tcx: TyCtxt<'tcx>,
18776
body: &mir::Body<'tcx>,
18877
results: Results<'tcx, A>,

0 commit comments

Comments
 (0)