about summary refs log tree commit diff
path: root/compiler/rustc_mir_dataflow/src/value_analysis.rs
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2023-01-16 22:12:36 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2023-10-21 06:58:38 +0000
commit751a079413a920ab380d63cdffbe99cf2476fe89 (patch)
tree9e4d9d302552943b52b3c779cd3f90f725b0b4ab /compiler/rustc_mir_dataflow/src/value_analysis.rs
parent3cb0c2e3851c8ec129216f63fdf322276dd1eb96 (diff)
downloadrust-751a079413a920ab380d63cdffbe99cf2476fe89.tar.gz
rust-751a079413a920ab380d63cdffbe99cf2476fe89.zip
Implement JumpThreading pass.
Diffstat (limited to 'compiler/rustc_mir_dataflow/src/value_analysis.rs')
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs107
1 files changed, 89 insertions, 18 deletions
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 04108aeedf6..77c9a22df79 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -463,7 +463,19 @@ impl<V: Clone> Clone for State<V> {
     }
 }
 
-impl<V: Clone + HasTop + HasBottom> State<V> {
+impl<V: Clone> State<V> {
+    pub fn new(init: V, map: &Map) -> State<V> {
+        let values = IndexVec::from_elem_n(init, map.value_count);
+        State(StateData::Reachable(values))
+    }
+
+    pub fn all(&self, f: impl Fn(&V) -> bool) -> bool {
+        match self.0 {
+            StateData::Unreachable => true,
+            StateData::Reachable(ref values) => values.iter().all(f),
+        }
+    }
+
     pub fn is_reachable(&self) -> bool {
         matches!(&self.0, StateData::Reachable(_))
     }
@@ -472,7 +484,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
         self.0 = StateData::Unreachable;
     }
 
-    pub fn flood_all(&mut self) {
+    pub fn flood_all(&mut self)
+    where
+        V: HasTop,
+    {
         self.flood_all_with(V::TOP)
     }
 
@@ -482,27 +497,40 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
     }
 
     pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
-        let StateData::Reachable(values) = &mut self.0 else { return };
-        map.for_each_aliasing_place(place, None, &mut |vi| {
-            values[vi] = value.clone();
-        });
+        self.flood_with_extra(place, None, map, value)
     }
 
-    pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) {
+    pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map)
+    where
+        V: HasTop,
+    {
         self.flood_with(place, map, V::TOP)
     }
 
     pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
-        let StateData::Reachable(values) = &mut self.0 else { return };
-        map.for_each_aliasing_place(place, Some(TrackElem::Discriminant), &mut |vi| {
-            values[vi] = value.clone();
-        });
+        self.flood_with_extra(place, Some(TrackElem::Discriminant), map, value)
     }
 
-    pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) {
+    pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map)
+    where
+        V: HasTop,
+    {
         self.flood_discr_with(place, map, V::TOP)
     }
 
+    pub fn flood_with_extra(
+        &mut self,
+        place: PlaceRef<'_>,
+        tail_elem: Option<TrackElem>,
+        map: &Map,
+        value: V,
+    ) {
+        let StateData::Reachable(values) = &mut self.0 else { return };
+        map.for_each_aliasing_place(place, tail_elem, &mut |vi| {
+            values[vi] = value.clone();
+        });
+    }
+
     /// Low-level method that assigns to a place.
     /// This does nothing if the place is not tracked.
     ///
@@ -553,7 +581,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
     }
 
     /// Helper method to interpret `target = result`.
-    pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map) {
+    pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
+    where
+        V: HasTop,
+    {
         self.flood(target, map);
         if let Some(target) = map.find(target) {
             self.insert_idx(target, result, map);
@@ -561,7 +592,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
     }
 
     /// Helper method for assignments to a discriminant.
-    pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map) {
+    pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
+    where
+        V: HasTop,
+    {
         self.flood_discr(target, map);
         if let Some(target) = map.find_discr(target) {
             self.insert_idx(target, result, map);
@@ -569,12 +603,43 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
     }
 
     /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
-    pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V {
+    pub fn try_get(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+        let place = map.find(place)?;
+        self.try_get_idx(place, map)
+    }
+
+    /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
+    pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+        let place = map.find_discr(place)?;
+        self.try_get_idx(place, map)
+    }
+
+    /// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
+    pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option<V> {
+        match &self.0 {
+            StateData::Reachable(values) => {
+                map.places[place].value_index.map(|v| values[v].clone())
+            }
+            StateData::Unreachable => {
+                // Because this is unreachable, we can return any value we want.
+                None
+            }
+        }
+    }
+
+    /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
+    pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V
+    where
+        V: HasBottom + HasTop,
+    {
         map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::TOP)
     }
 
     /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
-    pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V {
+    pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V
+    where
+        V: HasBottom + HasTop,
+    {
         match map.find_discr(place) {
             Some(place) => self.get_idx(place, map),
             None => V::TOP,
@@ -582,7 +647,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
     }
 
     /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
-    pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V {
+    pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V
+    where
+        V: HasBottom + HasTop,
+    {
         match map.find_len(place) {
             Some(place) => self.get_idx(place, map),
             None => V::TOP,
@@ -590,7 +658,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
     }
 
     /// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
-    pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V {
+    pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V
+    where
+        V: HasBottom + HasTop,
+    {
         match &self.0 {
             StateData::Reachable(values) => {
                 map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP)