diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 102e7439772..1ad2722d91b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -248,6 +248,7 @@ impl Direction for Backward { ); propagate(pred, &tmp); } + mir::TerminatorKind::InlineAsm { destination: Some(dest), ref operands, .. } if dest == bb => { @@ -266,6 +267,25 @@ impl Direction for Backward { propagate(pred, &tmp); } + mir::TerminatorKind::SwitchInt { ref targets, ref discr, switch_ty: _ } => { + let mut applier = BackwardSwitchIntEdgeEffectsApplier { + pred, + exit_state, + targets, + bb, + propagate: &mut propagate, + effects_applied: false, + }; + + analysis.apply_switch_int_edge_effects(pred, discr, &mut applier); + + let BackwardSwitchIntEdgeEffectsApplier { effects_applied, .. } = applier; + + if !effects_applied { + propagate(pred, exit_state) + } + } + // Ignore dead unwinds. mir::TerminatorKind::Call { cleanup: Some(unwind), .. } | mir::TerminatorKind::Assert { cleanup: Some(unwind), .. } @@ -286,6 +306,33 @@ impl Direction for Backward { } } +struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> { + pred: BasicBlock, + exit_state: &'a mut D, + targets: &'a SwitchTargets, + bb: BasicBlock, + propagate: &'a mut F, + + effects_applied: bool, +} + +impl super::SwitchIntEdgeEffects for BackwardSwitchIntEdgeEffectsApplier<'_, D, F> +where + D: Clone, + F: FnMut(BasicBlock, &D), +{ + fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { + assert!(!self.effects_applied); + + let value = + self.targets.iter().find_map(|(value, target)| (target == self.bb).then_some(value)); + apply_edge_effect(self.exit_state, SwitchIntTarget { value, target: self.bb }); + (self.propagate)(self.pred, self.exit_state); + + self.effects_applied = true; + } +} + /// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator). pub struct Forward; @@ -528,7 +575,7 @@ impl Direction for Forward { } SwitchInt { ref targets, ref discr, switch_ty: _ } => { - let mut applier = SwitchIntEdgeEffectApplier { + let mut applier = ForwardSwitchIntEdgeEffectsApplier { exit_state, targets, propagate, @@ -537,8 +584,11 @@ impl Direction for Forward { analysis.apply_switch_int_edge_effects(bb, discr, &mut applier); - let SwitchIntEdgeEffectApplier { - exit_state, mut propagate, effects_applied, .. + let ForwardSwitchIntEdgeEffectsApplier { + exit_state, + mut propagate, + effects_applied, + .. } = applier; if !effects_applied { @@ -551,7 +601,7 @@ impl Direction for Forward { } } -struct SwitchIntEdgeEffectApplier<'a, D, F> { +struct ForwardSwitchIntEdgeEffectsApplier<'a, D, F> { exit_state: &'a mut D, targets: &'a SwitchTargets, propagate: F, @@ -559,7 +609,7 @@ struct SwitchIntEdgeEffectApplier<'a, D, F> { effects_applied: bool, } -impl super::SwitchIntEdgeEffects for SwitchIntEdgeEffectApplier<'_, D, F> +impl super::SwitchIntEdgeEffects for ForwardSwitchIntEdgeEffectsApplier<'_, D, F> where D: Clone, F: FnMut(BasicBlock, &D), diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index c51dd06de25..67c16e6c084 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -234,8 +234,6 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the /// engine doesn't need to clone the exit state for a block unless /// `SwitchIntEdgeEffects::apply` is actually called. - /// - /// FIXME: This class of effects is not supported for backward dataflow analyses. fn apply_switch_int_edge_effects( &self, _block: BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 6c2d1b85646..c221b358670 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -28,7 +28,7 @@ pub use self::drop_flag_effects::{ pub use self::framework::{ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces, Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor, - ResultsRefCursor, ResultsVisitable, ResultsVisitor, + ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, }; use self::move_paths::MoveData;