Skip to content

Commit e0b83c3

Browse files
committed
Remove Engine::new_gen_kill.
This is an alternative to `Engine::new_generic` for gen/kill analyses. It's supposed to be an optimization, but it has negligible effect. The commit merges `Engine::new_generic` into `Engine::new`. This allows the removal of various other things: `GenKillSet`, `gen_kill_statement_effects_in_block`, `is_cfg_cyclic`.
1 parent 874b03e commit e0b83c3

File tree

4 files changed

+17
-197
lines changed

4 files changed

+17
-197
lines changed

compiler/rustc_middle/src/mir/basic_blocks.rs

-7
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>;
2626
struct Cache {
2727
predecessors: OnceLock<Predecessors>,
2828
switch_sources: OnceLock<SwitchSources>,
29-
is_cyclic: OnceLock<bool>,
3029
reverse_postorder: OnceLock<Vec<BasicBlock>>,
3130
dominators: OnceLock<Dominators<BasicBlock>>,
3231
}
@@ -37,12 +36,6 @@ impl<'tcx> BasicBlocks<'tcx> {
3736
BasicBlocks { basic_blocks, cache: Cache::default() }
3837
}
3938

40-
/// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
41-
#[inline]
42-
pub fn is_cfg_cyclic(&self) -> bool {
43-
*self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self))
44-
}
45-
4639
pub fn dominators(&self) -> &Dominators<BasicBlock> {
4740
self.cache.dominators.get_or_init(|| dominators(self))
4841
}

compiler/rustc_mir_dataflow/src/framework/direction.rs

+8-58
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_middle::mir::{
55
};
66

77
use super::visitor::{ResultsVisitable, ResultsVisitor};
8-
use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget};
8+
use super::{Analysis, Effect, EffectIndex, SwitchIntTarget};
99

1010
pub trait Direction {
1111
const IS_FORWARD: bool;
@@ -29,19 +29,10 @@ pub trait Direction {
2929
state: &mut A::Domain,
3030
block: BasicBlock,
3131
block_data: &'mir mir::BasicBlockData<'tcx>,
32-
statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>,
3332
) -> TerminatorEdges<'mir, 'tcx>
3433
where
3534
A: Analysis<'tcx>;
3635

37-
fn gen_kill_statement_effects_in_block<'tcx, A>(
38-
analysis: &mut A,
39-
trans: &mut GenKillSet<A::Idx>,
40-
block: BasicBlock,
41-
block_data: &mir::BasicBlockData<'tcx>,
42-
) where
43-
A: GenKillAnalysis<'tcx>;
44-
4536
fn visit_results_in_block<'mir, 'tcx, D, R>(
4637
state: &mut D,
4738
block: BasicBlock,
@@ -73,7 +64,6 @@ impl Direction for Backward {
7364
state: &mut A::Domain,
7465
block: BasicBlock,
7566
block_data: &'mir mir::BasicBlockData<'tcx>,
76-
statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>,
7767
) -> TerminatorEdges<'mir, 'tcx>
7868
where
7969
A: Analysis<'tcx>,
@@ -82,31 +72,12 @@ impl Direction for Backward {
8272
let location = Location { block, statement_index: block_data.statements.len() };
8373
analysis.apply_before_terminator_effect(state, terminator, location);
8474
let edges = analysis.apply_terminator_effect(state, terminator, location);
85-
if let Some(statement_effect) = statement_effect {
86-
statement_effect(block, state)
87-
} else {
88-
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
89-
let location = Location { block, statement_index };
90-
analysis.apply_before_statement_effect(state, statement, location);
91-
analysis.apply_statement_effect(state, statement, location);
92-
}
93-
}
94-
edges
95-
}
96-
97-
fn gen_kill_statement_effects_in_block<'tcx, A>(
98-
analysis: &mut A,
99-
trans: &mut GenKillSet<A::Idx>,
100-
block: BasicBlock,
101-
block_data: &mir::BasicBlockData<'tcx>,
102-
) where
103-
A: GenKillAnalysis<'tcx>,
104-
{
10575
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
10676
let location = Location { block, statement_index };
107-
analysis.before_statement_effect(trans, statement, location);
108-
analysis.statement_effect(trans, statement, location);
77+
analysis.apply_before_statement_effect(state, statement, location);
78+
analysis.apply_statement_effect(state, statement, location);
10979
}
80+
edges
11081
}
11182

11283
fn apply_effects_in_range<'tcx, A>(
@@ -330,42 +301,21 @@ impl Direction for Forward {
330301
state: &mut A::Domain,
331302
block: BasicBlock,
332303
block_data: &'mir mir::BasicBlockData<'tcx>,
333-
statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>,
334304
) -> TerminatorEdges<'mir, 'tcx>
335305
where
336306
A: Analysis<'tcx>,
337307
{
338-
if let Some(statement_effect) = statement_effect {
339-
statement_effect(block, state)
340-
} else {
341-
for (statement_index, statement) in block_data.statements.iter().enumerate() {
342-
let location = Location { block, statement_index };
343-
analysis.apply_before_statement_effect(state, statement, location);
344-
analysis.apply_statement_effect(state, statement, location);
345-
}
308+
for (statement_index, statement) in block_data.statements.iter().enumerate() {
309+
let location = Location { block, statement_index };
310+
analysis.apply_before_statement_effect(state, statement, location);
311+
analysis.apply_statement_effect(state, statement, location);
346312
}
347-
348313
let terminator = block_data.terminator();
349314
let location = Location { block, statement_index: block_data.statements.len() };
350315
analysis.apply_before_terminator_effect(state, terminator, location);
351316
analysis.apply_terminator_effect(state, terminator, location)
352317
}
353318

354-
fn gen_kill_statement_effects_in_block<'tcx, A>(
355-
analysis: &mut A,
356-
trans: &mut GenKillSet<A::Idx>,
357-
block: BasicBlock,
358-
block_data: &mir::BasicBlockData<'tcx>,
359-
) where
360-
A: GenKillAnalysis<'tcx>,
361-
{
362-
for (statement_index, statement) in block_data.statements.iter().enumerate() {
363-
let location = Location { block, statement_index };
364-
analysis.before_statement_effect(trans, statement, location);
365-
analysis.statement_effect(trans, statement, location);
366-
}
367-
}
368-
369319
fn apply_effects_in_range<'tcx, A>(
370320
analysis: &mut A,
371321
state: &mut A::Domain,

compiler/rustc_mir_dataflow/src/framework/engine.rs

+8-80
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::path::PathBuf;
55

66
use rustc_data_structures::work_queue::WorkQueue;
77
use rustc_hir::def_id::DefId;
8-
use rustc_index::{Idx, IndexVec};
8+
use rustc_index::IndexVec;
99
use rustc_middle::bug;
1010
use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
1111
use rustc_middle::ty::TyCtxt;
@@ -16,13 +16,12 @@ use {rustc_ast as ast, rustc_graphviz as dot};
1616

1717
use super::fmt::DebugWithContext;
1818
use super::{
19-
Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
20-
ResultsCursor, ResultsVisitor, graphviz, visit_results,
19+
Analysis, AnalysisDomain, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz,
20+
visit_results,
2121
};
2222
use crate::errors::{
2323
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
2424
};
25-
use crate::framework::BitSetExt;
2625

2726
type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
2827

@@ -82,53 +81,6 @@ where
8281
entry_sets: IndexVec<BasicBlock, A::Domain>,
8382
pass_name: Option<&'static str>,
8483
analysis: A,
85-
86-
/// Cached, cumulative transfer functions for each block.
87-
//
88-
// FIXME(ecstaticmorse): This boxed `Fn` trait object is invoked inside a tight loop for
89-
// gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade
90-
// performance in practice. I've tried a few ways to avoid this, but they have downsides. See
91-
// the message for the commit that added this FIXME for more information.
92-
apply_statement_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
93-
}
94-
95-
impl<'mir, 'tcx, A, D, T> Engine<'mir, 'tcx, A>
96-
where
97-
A: GenKillAnalysis<'tcx, Idx = T, Domain = D>,
98-
D: Clone + JoinSemiLattice + GenKill<T> + BitSetExt<T>,
99-
T: Idx,
100-
{
101-
/// Creates a new `Engine` to solve a gen-kill dataflow problem.
102-
pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, mut analysis: A) -> Self {
103-
// If there are no back-edges in the control-flow graph, we only ever need to apply the
104-
// transfer function for each block exactly once (assuming that we process blocks in RPO).
105-
//
106-
// In this case, there's no need to compute the block transfer functions ahead of time.
107-
if !body.basic_blocks.is_cfg_cyclic() {
108-
return Self::new(tcx, body, analysis, None);
109-
}
110-
111-
// Otherwise, compute and store the cumulative transfer function for each block.
112-
113-
let identity = GenKillSet::identity(analysis.domain_size(body));
114-
let mut trans_for_block = IndexVec::from_elem(identity, &body.basic_blocks);
115-
116-
for (block, block_data) in body.basic_blocks.iter_enumerated() {
117-
let trans = &mut trans_for_block[block];
118-
A::Direction::gen_kill_statement_effects_in_block(
119-
&mut analysis,
120-
trans,
121-
block,
122-
block_data,
123-
);
124-
}
125-
126-
let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
127-
trans_for_block[bb].apply(state);
128-
});
129-
130-
Self::new(tcx, body, analysis, Some(apply_trans as Box<_>))
131-
}
13284
}
13385

13486
impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A>
@@ -138,19 +90,7 @@ where
13890
{
13991
/// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
14092
/// function.
141-
///
142-
/// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for
143-
/// better performance.
144-
pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self {
145-
Self::new(tcx, body, analysis, None)
146-
}
147-
148-
fn new(
149-
tcx: TyCtxt<'tcx>,
150-
body: &'mir mir::Body<'tcx>,
151-
analysis: A,
152-
apply_statement_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
153-
) -> Self {
93+
pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self {
15494
let mut entry_sets =
15595
IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len());
15696
analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
@@ -160,7 +100,7 @@ where
160100
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
161101
}
162102

163-
Engine { analysis, tcx, body, pass_name: None, entry_sets, apply_statement_trans_for_block }
103+
Engine { analysis, tcx, body, pass_name: None, entry_sets }
164104
}
165105

166106
/// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
@@ -177,14 +117,7 @@ where
177117
where
178118
A::Domain: DebugWithContext<A>,
179119
{
180-
let Engine {
181-
mut analysis,
182-
body,
183-
mut entry_sets,
184-
tcx,
185-
apply_statement_trans_for_block,
186-
pass_name,
187-
} = self;
120+
let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self;
188121

189122
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
190123

@@ -213,13 +146,8 @@ where
213146
state.clone_from(&entry_sets[bb]);
214147

215148
// Apply the block transfer function, using the cached one if it exists.
216-
let edges = A::Direction::apply_effects_in_block(
217-
&mut analysis,
218-
&mut state,
219-
bb,
220-
bb_data,
221-
apply_statement_trans_for_block.as_deref(),
222-
);
149+
let edges =
150+
A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data);
223151

224152
A::Direction::join_state_into_successors_of(
225153
&mut analysis,

compiler/rustc_mir_dataflow/src/framework/mod.rs

+1-52
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
242242
where
243243
Self: Sized,
244244
{
245-
Engine::new_generic(tcx, body, self)
245+
Engine::new(tcx, body, self)
246246
}
247247
}
248248

@@ -376,19 +376,6 @@ where
376376
) {
377377
self.switch_int_edge_effects(block, discr, edge_effects);
378378
}
379-
380-
/* Extension methods */
381-
#[inline]
382-
fn into_engine<'mir>(
383-
self,
384-
tcx: TyCtxt<'tcx>,
385-
body: &'mir mir::Body<'tcx>,
386-
) -> Engine<'mir, 'tcx, Self>
387-
where
388-
Self: Sized,
389-
{
390-
Engine::new_gen_kill(tcx, body, self)
391-
}
392379
}
393380

394381
/// The legal operations for a transfer function in a gen/kill problem.
@@ -422,44 +409,6 @@ pub trait GenKill<T> {
422409
}
423410
}
424411

425-
/// Stores a transfer function for a gen/kill problem.
426-
///
427-
/// Calling `gen_`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be
428-
/// applied multiple times efficiently. When there are multiple calls to `gen_` and/or `kill` for
429-
/// the same element, the most recent one takes precedence.
430-
#[derive(Clone)]
431-
pub struct GenKillSet<T> {
432-
gen_: HybridBitSet<T>,
433-
kill: HybridBitSet<T>,
434-
}
435-
436-
impl<T: Idx> GenKillSet<T> {
437-
/// Creates a new transfer function that will leave the dataflow state unchanged.
438-
pub fn identity(universe: usize) -> Self {
439-
GenKillSet {
440-
gen_: HybridBitSet::new_empty(universe),
441-
kill: HybridBitSet::new_empty(universe),
442-
}
443-
}
444-
445-
pub fn apply(&self, state: &mut impl BitSetExt<T>) {
446-
state.union(&self.gen_);
447-
state.subtract(&self.kill);
448-
}
449-
}
450-
451-
impl<T: Idx> GenKill<T> for GenKillSet<T> {
452-
fn gen_(&mut self, elem: T) {
453-
self.gen_.insert(elem);
454-
self.kill.remove(elem);
455-
}
456-
457-
fn kill(&mut self, elem: T) {
458-
self.kill.insert(elem);
459-
self.gen_.remove(elem);
460-
}
461-
}
462-
463412
impl<T: Idx> GenKill<T> for BitSet<T> {
464413
fn gen_(&mut self, elem: T) {
465414
self.insert(elem);

0 commit comments

Comments
 (0)