about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel E. Moelius III <sam@moeli.us>2022-03-19 12:04:59 -0400
committerSamuel E. Moelius III <sam@moeli.us>2022-03-24 20:08:45 -0400
commitee7413b94cd0f953518ad73f37cac28feb6e8d52 (patch)
treec8498d2810b67b5217da929bd1edecf7d86f6ad0
parent9c7f6d60b103e940f939f568ee2e06de6e914d09 (diff)
downloadrust-ee7413b94cd0f953518ad73f37cac28feb6e8d52.tar.gz
rust-ee7413b94cd0f953518ad73f37cac28feb6e8d52.zip
Implement `apply_switch_int_edge_effects` for backward analyses
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs60
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs2
3 files changed, 56 insertions, 8 deletions
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<D, F> super::SwitchIntEdgeEffects<D> 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<D, F> super::SwitchIntEdgeEffects<D> for SwitchIntEdgeEffectApplier<'_, D, F>
+impl<D, F> super::SwitchIntEdgeEffects<D> 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;