about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJannis Christopher Köhl <mail@koehl.dev>2022-09-03 00:26:15 +0200
committerJannis Christopher Köhl <mail@koehl.dev>2022-11-07 10:35:14 +0100
commit2e4d0820d2f36d97f5db22496c1f71087d0e5323 (patch)
treeb999e47ade5fda9fc87aeb3b8c5e714bdad9a71f
parent895181b962cf39b7674023dc329c5c6d387a435f (diff)
downloadrust-2e4d0820d2f36d97f5db22496c1f71087d0e5323.tar.gz
rust-2e4d0820d2f36d97f5db22496c1f71087d0e5323.zip
Add more documentation
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs31
1 files changed, 29 insertions, 2 deletions
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 40d8aaea94d..355b7728e0c 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -193,6 +193,8 @@ pub trait ValueAnalysis<'tcx> {
         Self::Value::top()
     }
 
+    /// The effect of a successful function call return should not be
+    /// applied here, see [`Analysis::apply_terminator_effect`].
     fn handle_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) {
         self.super_terminator(terminator, state)
     }
@@ -267,6 +269,8 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
     }
 
     fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
+        // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
+        // This utilizes that reading from an uninitialized place is UB.
         assert!(matches!(state.0, StateData::Unreachable));
         let values = IndexVec::from_elem_n(T::Value::bottom(), self.0.map().value_count);
         *state = State(StateData::Reachable(values));
@@ -325,20 +329,38 @@ where
 }
 
 rustc_index::newtype_index!(
+    /// This index uniquely identifies a place.
+    ///
+    /// Not every place has a `PlaceIndex`, and not every `PlaceIndex` correspondends to a tracked
+    /// place. However, every tracked place and all places along its projection have a `PlaceIndex`.
     pub struct PlaceIndex {}
 );
 
 rustc_index::newtype_index!(
+    /// This index uniquely identifies a tracked place and therefore a slot in [`State`].
+    ///
+    /// It is an implementation detail of this module.
     struct ValueIndex {}
 );
 
+/// See [`State`].
 #[derive(PartialEq, Eq, Clone, Debug)]
 enum StateData<V> {
     Reachable(IndexVec<ValueIndex, V>),
     Unreachable,
 }
 
-/// All operations on unreachable states are ignored.
+/// The dataflow state for an instance of [`ValueAnalysis`].
+///
+/// Every instance specifies a lattice that represents the possible values of a single tracked
+/// place. If we call this lattice `V` and set set of tracked places `P`, then a [`State`] is an
+/// element of `{unreachable} ∪ (P -> V)`. This again forms a lattice, where the bottom element is
+/// `unreachable` and the top element is the mapping `p ↦ ⊤`. Note that the mapping `p ↦ ⊥` is not
+/// the bottom element (because joining an unreachable and any other reachable state yields a
+/// reachable state). All operations on unreachable states are ignored.
+///
+/// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place.
+/// Assigning a place (or reference thereof) to another place assumes that
 #[derive(PartialEq, Eq, Clone, Debug)]
 pub struct State<V>(StateData<V>);
 
@@ -383,8 +405,13 @@ impl<V: Clone + HasTop> State<V> {
         self.flood_idx_with(place, map, V::top())
     }
 
+    /// This method assumes that the given places are not overlapping, and that we can therefore
+    /// copy all entries one after another.
     pub fn assign_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
         let StateData::Reachable(values) = &mut self.0 else { return };
+        // If both places are tracked, we copy the value to the target. If the target is tracked,
+        // but the source is not, we have to invalidate the value in target. If the target is not
+        // tracked, then we don't have to do anything.
         if let Some(target_value) = map.places[target].value_index {
             if let Some(source_value) = map.places[source].value_index {
                 values[target_value] = values[source_value].clone();
@@ -393,7 +420,7 @@ impl<V: Clone + HasTop> State<V> {
             }
         }
         for target_child in map.children(target) {
-            // Try to find corresponding child in source.
+            // Try to find corresponding child and recurse. Reasoning is similar as above.
             let projection = map.places[target_child].proj_elem.unwrap();
             if let Some(source_child) = map.projections.get(&(source, projection)) {
                 self.assign_place_idx(target_child, *source_child, map);