Skip to content

Commit b2b0317

Browse files
committed
Implement dataflow state joins through the analysis. Make JoinSemiLattice the default implementation when the join does not require extra context.
1 parent c1699a7 commit b2b0317

File tree

8 files changed

+142
-113
lines changed

8 files changed

+142
-113
lines changed

compiler/rustc_mir_dataflow/src/framework/direction.rs

+48-34
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub trait Direction {
5555
body: &mir::Body<'tcx>,
5656
exit_state: &mut A::Domain,
5757
block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
58-
propagate: impl FnMut(BasicBlock, &A::Domain),
58+
propagate: impl FnMut(&mut A, BasicBlock, &A::Domain),
5959
) where
6060
A: Analysis<'tcx>;
6161
}
@@ -221,7 +221,7 @@ impl Direction for Backward {
221221
body: &mir::Body<'tcx>,
222222
exit_state: &mut A::Domain,
223223
(bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
224-
mut propagate: impl FnMut(BasicBlock, &A::Domain),
224+
mut propagate: impl FnMut(&mut A, BasicBlock, &A::Domain),
225225
) where
226226
A: Analysis<'tcx>,
227227
{
@@ -237,7 +237,7 @@ impl Direction for Backward {
237237
pred,
238238
CallReturnPlaces::Call(destination),
239239
);
240-
propagate(pred, &tmp);
240+
propagate(analysis, pred, &tmp);
241241
}
242242

243243
mir::TerminatorKind::InlineAsm {
@@ -249,13 +249,13 @@ impl Direction for Backward {
249249
pred,
250250
CallReturnPlaces::InlineAsm(operands),
251251
);
252-
propagate(pred, &tmp);
252+
propagate(analysis, pred, &tmp);
253253
}
254254

255255
mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => {
256256
let mut tmp = exit_state.clone();
257257
analysis.apply_yield_resume_effect(&mut tmp, resume, resume_arg);
258-
propagate(pred, &tmp);
258+
propagate(analysis, pred, &tmp);
259259
}
260260

261261
mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
@@ -271,11 +271,11 @@ impl Direction for Backward {
271271
analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
272272

273273
if !applier.effects_applied {
274-
propagate(pred, exit_state)
274+
propagate(analysis, pred, exit_state)
275275
}
276276
}
277277

278-
_ => propagate(pred, exit_state),
278+
_ => propagate(analysis, pred, exit_state),
279279
}
280280
}
281281
}
@@ -290,12 +290,17 @@ struct BackwardSwitchIntEdgeEffectsApplier<'a, 'tcx, D, F> {
290290
effects_applied: bool,
291291
}
292292

293-
impl<D, F> super::SwitchIntEdgeEffects<D> for BackwardSwitchIntEdgeEffectsApplier<'_, '_, D, F>
293+
impl<'tcx, A, F> super::SwitchIntEdgeEffects<'tcx, A>
294+
for BackwardSwitchIntEdgeEffectsApplier<'_, '_, A::Domain, F>
294295
where
295-
D: Clone,
296-
F: FnMut(BasicBlock, &D),
296+
A: Analysis<'tcx>,
297+
F: FnMut(&mut A, BasicBlock, &A::Domain),
297298
{
298-
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
299+
fn apply(
300+
&mut self,
301+
analysis: &mut A,
302+
mut apply_edge_effect: impl FnMut(&mut A, &mut A::Domain, SwitchIntTarget),
303+
) {
299304
assert!(!self.effects_applied);
300305

301306
let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)];
@@ -304,8 +309,8 @@ where
304309
let mut tmp = None;
305310
for target in targets {
306311
let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
307-
apply_edge_effect(tmp, target);
308-
(self.propagate)(self.pred, tmp);
312+
apply_edge_effect(analysis, tmp, target);
313+
(self.propagate)(analysis, self.pred, tmp);
309314
}
310315

311316
self.effects_applied = true;
@@ -468,43 +473,43 @@ impl Direction for Forward {
468473
_body: &mir::Body<'tcx>,
469474
exit_state: &mut A::Domain,
470475
(bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
471-
mut propagate: impl FnMut(BasicBlock, &A::Domain),
476+
mut propagate: impl FnMut(&mut A, BasicBlock, &A::Domain),
472477
) where
473478
A: Analysis<'tcx>,
474479
{
475480
use mir::TerminatorKind::*;
476481
match bb_data.terminator().kind {
477482
Return | Resume | Terminate | GeneratorDrop | Unreachable => {}
478483

479-
Goto { target } => propagate(target, exit_state),
484+
Goto { target } => propagate(analysis, target, exit_state),
480485

481486
Assert { target, unwind, expected: _, msg: _, cond: _ }
482487
| Drop { target, unwind, place: _, replace: _ }
483488
| FalseUnwind { real_target: target, unwind } => {
484489
if let UnwindAction::Cleanup(unwind) = unwind {
485-
propagate(unwind, exit_state);
490+
propagate(analysis, unwind, exit_state);
486491
}
487492

488-
propagate(target, exit_state);
493+
propagate(analysis, target, exit_state);
489494
}
490495

491496
FalseEdge { real_target, imaginary_target } => {
492-
propagate(real_target, exit_state);
493-
propagate(imaginary_target, exit_state);
497+
propagate(analysis, real_target, exit_state);
498+
propagate(analysis, imaginary_target, exit_state);
494499
}
495500

496501
Yield { resume: target, drop, resume_arg, value: _ } => {
497502
if let Some(drop) = drop {
498-
propagate(drop, exit_state);
503+
propagate(analysis, drop, exit_state);
499504
}
500505

501506
analysis.apply_yield_resume_effect(exit_state, target, resume_arg);
502-
propagate(target, exit_state);
507+
propagate(analysis, target, exit_state);
503508
}
504509

505510
Call { unwind, destination, target, func: _, args: _, call_source: _, fn_span: _ } => {
506511
if let UnwindAction::Cleanup(unwind) = unwind {
507-
propagate(unwind, exit_state);
512+
propagate(analysis, unwind, exit_state);
508513
}
509514

510515
if let Some(target) = target {
@@ -515,7 +520,7 @@ impl Direction for Forward {
515520
bb,
516521
CallReturnPlaces::Call(destination),
517522
);
518-
propagate(target, exit_state);
523+
propagate(analysis, target, exit_state);
519524
}
520525
}
521526

@@ -528,7 +533,7 @@ impl Direction for Forward {
528533
unwind,
529534
} => {
530535
if let UnwindAction::Cleanup(unwind) = unwind {
531-
propagate(unwind, exit_state);
536+
propagate(analysis, unwind, exit_state);
532537
}
533538

534539
if let Some(target) = destination {
@@ -539,7 +544,7 @@ impl Direction for Forward {
539544
bb,
540545
CallReturnPlaces::InlineAsm(operands),
541546
);
542-
propagate(target, exit_state);
547+
propagate(analysis, target, exit_state);
543548
}
544549
}
545550

@@ -562,7 +567,7 @@ impl Direction for Forward {
562567

563568
if !effects_applied {
564569
for target in targets.all_targets() {
565-
propagate(*target, exit_state);
570+
propagate(analysis, *target, exit_state);
566571
}
567572
}
568573
}
@@ -578,26 +583,35 @@ struct ForwardSwitchIntEdgeEffectsApplier<'a, D, F> {
578583
effects_applied: bool,
579584
}
580585

581-
impl<D, F> super::SwitchIntEdgeEffects<D> for ForwardSwitchIntEdgeEffectsApplier<'_, D, F>
586+
impl<'tcx, A, F> super::SwitchIntEdgeEffects<'tcx, A>
587+
for ForwardSwitchIntEdgeEffectsApplier<'_, A::Domain, F>
582588
where
583-
D: Clone,
584-
F: FnMut(BasicBlock, &D),
589+
A: Analysis<'tcx>,
590+
F: FnMut(&mut A, BasicBlock, &A::Domain),
585591
{
586-
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
592+
fn apply(
593+
&mut self,
594+
analysis: &mut A,
595+
mut apply_edge_effect: impl FnMut(&mut A, &mut A::Domain, SwitchIntTarget),
596+
) {
587597
assert!(!self.effects_applied);
588598

589599
let mut tmp = None;
590600
for (value, target) in self.targets.iter() {
591601
let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
592-
apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target });
593-
(self.propagate)(target, tmp);
602+
apply_edge_effect(analysis, tmp, SwitchIntTarget { value: Some(value), target });
603+
(self.propagate)(analysis, target, tmp);
594604
}
595605

596606
// Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`,
597607
// so pass it directly to `apply_edge_effect` to save a clone of the dataflow state.
598608
let otherwise = self.targets.otherwise();
599-
apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise });
600-
(self.propagate)(otherwise, self.exit_state);
609+
apply_edge_effect(
610+
analysis,
611+
self.exit_state,
612+
SwitchIntTarget { value: None, target: otherwise },
613+
);
614+
(self.propagate)(analysis, otherwise, self.exit_state);
601615

602616
self.effects_applied = true;
603617
}

compiler/rustc_mir_dataflow/src/framework/engine.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ use super::fmt::DebugWithContext;
2525
use super::graphviz;
2626
use super::{
2727
visit_results, Analysis, AnalysisDomain, CloneAnalysis, Direction, GenKill, GenKillAnalysis,
28-
GenKillSet, JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
29-
ResultsVisitor,
28+
GenKillSet, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, ResultsVisitor,
3029
};
3130

3231
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
@@ -150,7 +149,7 @@ where
150149
impl<'a, 'tcx, A, D, T> Engine<'a, 'tcx, A>
151150
where
152151
A: GenKillAnalysis<'tcx, Idx = T, Domain = D>,
153-
D: Clone + JoinSemiLattice + GenKill<T> + BitSetExt<T>,
152+
D: Clone + GenKill<T> + BitSetExt<T>,
154153
T: Idx,
155154
{
156155
/// Creates a new `Engine` to solve a gen-kill dataflow problem.
@@ -181,10 +180,9 @@ where
181180
}
182181
}
183182

184-
impl<'a, 'tcx, A, D> Engine<'a, 'tcx, A>
183+
impl<'a, 'tcx, A> Engine<'a, 'tcx, A>
185184
where
186-
A: Analysis<'tcx, Domain = D>,
187-
D: Clone + JoinSemiLattice,
185+
A: Analysis<'tcx>,
188186
{
189187
/// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
190188
/// function.
@@ -276,8 +274,8 @@ where
276274
body,
277275
&mut state,
278276
(bb, bb_data),
279-
|target: BasicBlock, state: &A::Domain| {
280-
let set_changed = entry_sets[target].join(state);
277+
|analysis: &mut A, target: BasicBlock, state: &A::Domain| {
278+
let set_changed = analysis.join(&mut entry_sets[target], state, target);
281279
if set_changed {
282280
dirty_queue.insert(target);
283281
}

compiler/rustc_mir_dataflow/src/framework/mod.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl<T: Idx> BitSetExt<T> for ChunkedBitSet<T> {
102102
/// initial value at the entry point of each basic block.
103103
pub trait AnalysisDomain<'tcx> {
104104
/// The type that holds the dataflow state at any given point in the program.
105-
type Domain: Clone + JoinSemiLattice;
105+
type Domain: Clone + Eq;
106106

107107
/// The direction of this analysis. Either `Forward` or `Backward`.
108108
type Direction: Direction = Forward;
@@ -127,6 +127,21 @@ pub trait AnalysisDomain<'tcx> {
127127
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain);
128128
}
129129

130+
/// Gets the context under which to perform a join.
131+
pub trait AnalysisJoin<'tcx>: AnalysisDomain<'tcx> {
132+
fn join(&mut self, state: &mut Self::Domain, other: &Self::Domain, loc: BasicBlock) -> bool;
133+
}
134+
135+
impl<'tcx, T> AnalysisJoin<'tcx> for T
136+
where
137+
T: ?Sized + AnalysisDomain<'tcx>,
138+
<T as AnalysisDomain<'tcx>>::Domain: JoinSemiLattice,
139+
{
140+
fn join(&mut self, state: &mut Self::Domain, other: &Self::Domain, _: BasicBlock) -> bool {
141+
state.join(other)
142+
}
143+
}
144+
130145
/// A dataflow problem with an arbitrarily complex transfer function.
131146
///
132147
/// # Convergence
@@ -143,7 +158,7 @@ pub trait AnalysisDomain<'tcx> {
143158
/// monotonically until fixpoint is reached. Note that this monotonicity requirement only applies
144159
/// to the same point in the program at different points in time. The dataflow state at a given
145160
/// point in the program may or may not be greater than the state at any preceding point.
146-
pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
161+
pub trait Analysis<'tcx>: AnalysisJoin<'tcx> {
147162
/// Updates the current dataflow state with the effect of evaluating a statement.
148163
fn apply_statement_effect(
149164
&mut self,
@@ -238,7 +253,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
238253
&mut self,
239254
_block: BasicBlock,
240255
_discr: &mir::Operand<'tcx>,
241-
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
256+
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<'tcx, Self>,
242257
) {
243258
}
244259

@@ -349,18 +364,18 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
349364
}
350365

351366
/// See `Analysis::apply_switch_int_edge_effects`.
352-
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
367+
fn switch_int_edge_effects(
353368
&mut self,
354369
_block: BasicBlock,
355370
_discr: &mir::Operand<'tcx>,
356-
_edge_effects: &mut impl SwitchIntEdgeEffects<G>,
371+
_edge_effects: &mut impl SwitchIntEdgeEffects<'tcx, Self>,
357372
) {
358373
}
359374
}
360375

361376
impl<'tcx, A> Analysis<'tcx> for A
362377
where
363-
A: GenKillAnalysis<'tcx>,
378+
A: GenKillAnalysis<'tcx> + ?Sized,
364379
A::Domain: GenKill<A::Idx> + BitSetExt<A::Idx>,
365380
{
366381
fn apply_statement_effect(
@@ -423,7 +438,7 @@ where
423438
&mut self,
424439
block: BasicBlock,
425440
discr: &mir::Operand<'tcx>,
426-
edge_effects: &mut impl SwitchIntEdgeEffects<A::Domain>,
441+
edge_effects: &mut impl SwitchIntEdgeEffects<'tcx, Self>,
427442
) {
428443
self.switch_int_edge_effects(block, discr, edge_effects);
429444
}
@@ -606,10 +621,14 @@ pub struct SwitchIntTarget {
606621
}
607622

608623
/// A type that records the edge-specific effects for a `SwitchInt` terminator.
609-
pub trait SwitchIntEdgeEffects<D> {
624+
pub trait SwitchIntEdgeEffects<'tcx, A: ?Sized + AnalysisDomain<'tcx>> {
610625
/// Calls `apply_edge_effect` for each outgoing edge from a `SwitchInt` terminator and
611626
/// records the results.
612-
fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget));
627+
fn apply(
628+
&mut self,
629+
analysis: &mut A,
630+
apply_edge_effect: impl FnMut(&mut A, &mut A::Domain, SwitchIntTarget),
631+
);
613632
}
614633

615634
/// List of places that are written to after a successful (non-unwind) return

0 commit comments

Comments
 (0)