]> git.lizzy.rs Git - rust.git/commitdiff
split into two matrices
authorNiko Matsakis <niko@alum.mit.edu>
Sun, 22 Jul 2018 16:46:48 +0000 (19:46 +0300)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 25 Jul 2018 03:38:19 +0000 (06:38 +0300)
src/librustc_data_structures/bitvec.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/values.rs
src/librustc_mir/lib.rs

index dec10416bcb7d81f7f95a53858d678d3fc3bb4be..bc7b8f8df46ec7775a26d121c07b9c850e22140b 100644 (file)
@@ -43,12 +43,27 @@ pub fn count(&self) -> usize {
         self.data.iter().map(|e| e.count_ones() as usize).sum()
     }
 
+    /// True if `self` contains the bit `bit`.
     #[inline]
     pub fn contains(&self, bit: C) -> bool {
         let (word, mask) = word_mask(bit);
         (self.data[word] & mask) != 0
     }
 
+    /// True if `self` contains all the bits in `other`.
+    ///
+    /// The two vectors must have the same length.
+    #[inline]
+    pub fn contains_all(&self, other: &BitVector<C>) -> bool {
+        assert_eq!(self.data.len(), other.data.len());
+        self.data.iter().zip(&other.data).all(|(a, b)| (a & b) == *b)
+    }
+
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.data.iter().all(|a| *a == 0)
+    }
+
     /// Returns true if the bit has changed.
     #[inline]
     pub fn insert(&mut self, bit: C) -> bool {
@@ -349,6 +364,10 @@ pub fn len(&self) -> usize {
         self.vector.len()
     }
 
+    pub fn rows(&self) -> impl Iterator<Item = R> {
+        self.vector.indices()
+    }
+
     /// Iterates through all the columns set to true in a given row of
     /// the matrix.
     pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
@@ -522,3 +541,45 @@ fn matrix_iter() {
     }
     assert!(iter.next().is_none());
 }
+
+#[test]
+fn sparse_matrix_iter() {
+    let mut matrix = SparseBitMatrix::new(64, 100);
+    matrix.add(3, 22);
+    matrix.add(3, 75);
+    matrix.add(2, 99);
+    matrix.add(4, 0);
+    matrix.merge(3, 5);
+
+    let expected = [99];
+    let mut iter = expected.iter();
+    for i in matrix.iter(2) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    for i in matrix.iter(3) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [0];
+    let mut iter = expected.iter();
+    for i in matrix.iter(4) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    for i in matrix.iter(5) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+}
index a74f4f5539fbc2140285f13015d58db500dc492c..3ba95895bfdaf7c672001fa31f780fd9ba07a33d 100644 (file)
@@ -48,9 +48,6 @@ pub struct RegionInferenceContext<'tcx> {
     /// from as well as its final inferred value.
     definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
 
-    /// Maps from points/universal-regions to a `RegionElementIndex`.
-    elements: Rc<RegionValueElements>,
-
     /// The liveness constraints added to each region. For most
     /// regions, these start out empty and steadily grow, though for
     /// each universally quantified region R they start out containing
@@ -219,14 +216,13 @@ pub(crate) fn new(
 
         let mut scc_values = RegionValues::new(elements);
 
-        for (region, location_set) in liveness_constraints.iter_enumerated() {
+        for region in liveness_constraints.regions_with_points() {
             let scc = constraint_sccs.scc(region);
-            scc_values.merge_into(scc, location_set);
+            scc_values.merge_row(scc, region, &liveness_constraints);
         }
 
         let mut result = Self {
             definitions,
-            elements: elements.clone(),
             liveness_constraints,
             constraints,
             constraint_graph,
@@ -273,7 +269,6 @@ fn init_universal_regions(&mut self) {
         }
 
         // For each universally quantified region X:
-        let elements = self.elements.clone();
         let universal_regions = self.universal_regions.clone();
         for variable in universal_regions.universal_regions() {
             // These should be free-region variables.
@@ -283,9 +278,9 @@ fn init_universal_regions(&mut self) {
             });
 
             // Add all nodes in the CFG to liveness constraints
-            for point_index in elements.all_point_indices() {
-                self.add_live_element(variable, point_index);
-            }
+            let variable_scc = self.constraint_sccs.scc(variable);
+            self.liveness_constraints.add_all_points(variable);
+            self.scc_values.add_all_points(variable_scc);
 
             // Add `end(X)` into the set for X.
             self.add_live_element(variable, variable);
@@ -782,7 +777,8 @@ fn eval_outlives(
         // now). Therefore, the sup-region outlives the sub-region if,
         // for each universal region R1 in the sub-region, there
         // exists some region R2 in the sup-region that outlives R1.
-        let universal_outlives = self.scc_values
+        let universal_outlives = self
+            .scc_values
             .universal_regions_outlived_by(sub_region_scc)
             .all(|r1| {
                 self.scc_values
index 4db5267cbd439390356b32513b97dcb9cdf3d4d0..8092b773eae8e90fa2725e507e8779a820e04c96 100644 (file)
 
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc::ty::RegionVid;
-use rustc_data_structures::bitvec::{BitVector, SparseBitMatrix};
+use rustc_data_structures::bitvec::SparseBitMatrix;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt::Debug;
 use std::rc::Rc;
+use std::ops::Range;
 
 /// Maps between the various kinds of elements of a region value to
 /// the internal indices that w use.
@@ -50,90 +51,65 @@ impl RegionValueElements {
 
         Self {
             statements_before_block,
-            num_universal_regions,
             num_points,
+            num_universal_regions,
         }
     }
 
-    /// Total number of element indices that exist.
-    crate fn num_elements(&self) -> usize {
-        self.num_points + self.num_universal_regions
-    }
-
-    /// Converts an element of a region value into a `RegionElementIndex`.
-    crate fn index<T: ToElementIndex>(&self, elem: T) -> RegionElementIndex {
-        elem.to_element_index(self)
+    fn point_from_location(&self, location: Location) -> PointIndex {
+        let Location {
+            block,
+            statement_index,
+        } = location;
+        let start_index = self.statements_before_block[block];
+        PointIndex::new(start_index + statement_index)
     }
 
-    /// Iterates over the `RegionElementIndex` for all points in the CFG.
-    crate fn all_point_indices<'a>(&'a self) -> impl Iterator<Item = RegionElementIndex> + 'a {
-        (0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions))
+    /// Range coverting all point indices.
+    fn all_points(&self) -> Range<PointIndex> {
+        PointIndex::new(0)..PointIndex::new(self.num_points)
     }
 
-    /// Converts a particular `RegionElementIndex` to the `RegionElement` it represents.
-    crate fn to_element(&self, i: RegionElementIndex) -> RegionElement {
-        debug!("to_element(i={:?})", i);
-
-        if let Some(r) = self.to_universal_region(i) {
-            RegionElement::UniversalRegion(r)
-        } else {
-            let point_index = i.index() - self.num_universal_regions;
-
-            // Find the basic block. We have a vector with the
-            // starting index of the statement in each block. Imagine
-            // we have statement #22, and we have a vector like:
-            //
-            // [0, 10, 20]
-            //
-            // In that case, this represents point_index 2 of
-            // basic block BB2. We know this because BB0 accounts for
-            // 0..10, BB1 accounts for 11..20, and BB2 accounts for
-            // 20...
-            //
-            // To compute this, we could do a binary search, but
-            // because I am lazy we instead iterate through to find
-            // the last point where the "first index" (0, 10, or 20)
-            // was less than the statement index (22). In our case, this will
-            // be (BB2, 20).
-            //
-            // Nit: we could do a binary search here but I'm too lazy.
-            let (block, &first_index) = self
-                .statements_before_block
-                .iter_enumerated()
-                .filter(|(_, first_index)| **first_index <= point_index)
-                .last()
-                .unwrap();
-
-            RegionElement::Location(Location {
-                block,
-                statement_index: point_index - first_index,
-            })
-        }
-    }
-
-    /// Converts a particular `RegionElementIndex` to a universal
-    /// region, if that is what it represents. Returns `None`
-    /// otherwise.
-    crate fn to_universal_region(&self, i: RegionElementIndex) -> Option<RegionVid> {
-        if i.index() < self.num_universal_regions {
-            Some(RegionVid::new(i.index()))
-        } else {
-            None
+    /// Converts a particular `RegionElementIndex` to a location, if
+    /// that is what it represents. Returns `None` otherwise.
+    crate fn to_location(&self, i: PointIndex) -> Location {
+        let point_index = i.index();
+
+        // Find the basic block. We have a vector with the
+        // starting index of the statement in each block. Imagine
+        // we have statement #22, and we have a vector like:
+        //
+        // [0, 10, 20]
+        //
+        // In that case, this represents point_index 2 of
+        // basic block BB2. We know this because BB0 accounts for
+        // 0..10, BB1 accounts for 11..20, and BB2 accounts for
+        // 20...
+        //
+        // To compute this, we could do a binary search, but
+        // because I am lazy we instead iterate through to find
+        // the last point where the "first index" (0, 10, or 20)
+        // was less than the statement index (22). In our case, this will
+        // be (BB2, 20).
+        //
+        // Nit: we could do a binary search here but I'm too lazy.
+        let (block, &first_index) = self
+            .statements_before_block
+            .iter_enumerated()
+            .filter(|(_, first_index)| **first_index <= point_index)
+            .last()
+            .unwrap();
+
+        Location {
+            block,
+            statement_index: point_index - first_index,
         }
     }
 }
 
-/// A newtype for the integers that represent one of the possible
-/// elements in a region. These are the rows in the `SparseBitMatrix` that
-/// is used to store the values of all regions. They have the following
-/// convention:
-///
-/// - The first N indices represent free regions (where N = universal_regions.len()).
-/// - The remainder represent the points in the CFG (see `point_indices` map).
-///
-/// You can convert a `RegionElementIndex` into a `RegionElement`
-/// using the `to_region_elem` method.
-newtype_index!(RegionElementIndex { DEBUG_FORMAT = "RegionElementIndex({})" });
+/// A single integer representing a `Location` in the MIR control-flow
+/// graph. Constructed efficiently from `RegionValueElements`.
+newtype_index!(PointIndex { DEBUG_FORMAT = "PointIndex({})" });
 
 /// An individual element in a region value -- the value of a
 /// particular region variable consists of a set of these elements.
@@ -142,36 +118,9 @@ impl RegionValueElements {
     /// A point in the control-flow graph.
     Location(Location),
 
-    /// An in-scope, universally quantified region (e.g., a lifetime parameter).
-    UniversalRegion(RegionVid),
-}
-
-crate trait ToElementIndex: Debug + Copy {
-    fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex;
-}
-
-impl ToElementIndex for Location {
-    fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex {
-        let Location {
-            block,
-            statement_index,
-        } = self;
-        let start_index = elements.statements_before_block[block];
-        RegionElementIndex::new(elements.num_universal_regions + start_index + statement_index)
-    }
-}
-
-impl ToElementIndex for RegionVid {
-    fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex {
-        assert!(self.index() < elements.num_universal_regions);
-        RegionElementIndex::new(self.index())
-    }
-}
-
-impl ToElementIndex for RegionElementIndex {
-    fn to_element_index(self, _elements: &RegionValueElements) -> RegionElementIndex {
-        self
-    }
+    /// A universally quantified region from the root universe (e.g.,
+    /// a lifetime parameter).
+    RootUniversalRegion(RegionVid),
 }
 
 /// Stores the values for a set of regions. These are stored in a
@@ -181,7 +130,8 @@ fn to_element_index(self, _elements: &RegionValueElements) -> RegionElementIndex
 #[derive(Clone)]
 crate struct RegionValues<N: Idx> {
     elements: Rc<RegionValueElements>,
-    matrix: SparseBitMatrix<N, RegionElementIndex>,
+    points: SparseBitMatrix<N, PointIndex>,
+    free_regions: SparseBitMatrix<N, RegionVid>,
 }
 
 impl<N: Idx> RegionValues<N> {
@@ -191,7 +141,8 @@ impl<N: Idx> RegionValues<N> {
     crate fn new(elements: &Rc<RegionValueElements>) -> Self {
         Self {
             elements: elements.clone(),
-            matrix: SparseBitMatrix::new(elements.num_elements()),
+            points: SparseBitMatrix::new(elements.num_points),
+            free_regions: SparseBitMatrix::new(elements.num_universal_regions),
         }
     }
 
@@ -202,53 +153,83 @@ impl<N: Idx> RegionValues<N> {
         r: N,
         elem: impl ToElementIndex,
     ) -> bool {
-        let i = self.elements.index(elem);
         debug!("add(r={:?}, elem={:?})", r, elem);
-        self.matrix.add(r, i)
+        elem.add_to_row(self, r)
+    }
+
+    /// Adds all the control-flow points to the values for `r`.
+    crate fn add_all_points(&mut self, r: N) {
+        // FIXME OMG so inefficient. We'll fix later.
+        for p in self.elements.all_points() {
+            self.points.add(r, p);
+        }
     }
 
     /// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
     /// r_from`).
     crate fn add_region(&mut self, r_to: N, r_from: N) -> bool {
-        self.matrix.merge(r_from, r_to)
+        self.points.merge(r_from, r_to) | self.free_regions.merge(r_from, r_to)
+        // FIXME universes?
     }
 
     /// True if the region `r` contains the given element.
-    crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool {
-        let i = self.elements.index(elem);
-        self.matrix.contains(r, i)
+    crate fn contains(
+        &self,
+        r: N,
+        elem: impl ToElementIndex,
+    ) -> bool {
+        elem.contained_in_row(self, r)
     }
 
-    /// Iterates through each row and the accompanying bit set.
-    pub fn iter_enumerated<'a>(
-        &'a self
-    ) -> impl Iterator<Item = (N, &'a BitVector<RegionElementIndex>)> + 'a {
-        self.matrix.iter_enumerated()
+    /// Iterate through each region that has a value in this set.
+    crate fn regions_with_points<'a>(&'a self) -> impl Iterator<Item = N> {
+        self.points.rows()
     }
 
-    /// Merge a row, `from`, originating in another `RegionValues` into the `into` row.
-    pub fn merge_into(&mut self, into: N, from: &BitVector<RegionElementIndex>) -> bool {
-        self.matrix.merge_into(into, from)
+    /// `self[to] |= values[from]`, essentially: that is, take all the
+    /// elements for the region `from` from `values` and add them to
+    /// the region `to` in `self`.
+    crate fn merge_row<M: Idx>(&mut self, to: N, from: M, values: &RegionValues<M>) {
+        if let Some(set) = values.points.row(from) {
+            self.points.merge_into(to, set);
+        }
+
+        if let Some(set) = values.free_regions.row(from) {
+            self.free_regions.merge_into(to, set);
+        }
     }
 
     /// True if `sup_region` contains all the CFG points that
     /// `sub_region` contains. Ignores universal regions.
-    crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
+    crate fn contains_points(
+        &self,
+        sup_region: N,
+        sub_region: N,
+    ) -> bool {
         // This could be done faster by comparing the bitsets. But I
         // am lazy.
-        self.element_indices_contained_in(sub_region)
-            .skip_while(|&i| self.elements.to_universal_region(i).is_some())
-            .all(|e| self.contains(sup_region, e))
+        if let Some(sub_row) = self.points.row(sub_region) {
+            if let Some(sup_row) = self.points.row(sup_region) {
+                sup_row.contains_all(sub_row)
+            } else {
+                // sup row is empty, so sub row must be empty
+                sub_row.is_empty()
+            }
+        } else {
+            // sub row is empty, always true
+            true
+        }
     }
 
-    /// Iterate over the value of the region `r`, yielding up element
-    /// indices. You may prefer `universal_regions_outlived_by` or
-    /// `elements_contained_in`.
-    crate fn element_indices_contained_in<'a>(
+    /// Returns the locations contained within a given region `r`.
+    crate fn locations_outlived_by<'a>(
         &'a self,
         r: N,
-    ) -> impl Iterator<Item = RegionElementIndex> + 'a {
-        self.matrix.iter(r).map(move |i| i)
+    ) -> impl Iterator<Item = Location> + 'a {
+        self.points
+            .row(r)
+            .into_iter()
+            .flat_map(move |set| set.iter().map(move |p| self.elements.to_location(p)))
     }
 
     /// Returns just the universal regions that are contained in a given region's value.
@@ -256,10 +237,10 @@ pub fn merge_into(&mut self, into: N, from: &BitVector<RegionElementIndex>) -> b
         &'a self,
         r: N,
     ) -> impl Iterator<Item = RegionVid> + 'a {
-        self.element_indices_contained_in(r)
-            .map(move |i| self.elements.to_universal_region(i))
-            .take_while(move |v| v.is_some()) // universal regions are a prefix
-            .map(move |v| v.unwrap())
+        self.free_regions
+            .row(r)
+            .into_iter()
+            .flat_map(|set| set.iter())
     }
 
     /// Returns all the elements contained in a given region's value.
@@ -267,8 +248,15 @@ pub fn merge_into(&mut self, into: N, from: &BitVector<RegionElementIndex>) -> b
         &'a self,
         r: N,
     ) -> impl Iterator<Item = RegionElement> + 'a {
-        self.element_indices_contained_in(r)
-            .map(move |r| self.elements.to_element(r))
+        let points_iter = self
+            .locations_outlived_by(r)
+            .map(RegionElement::Location);
+
+        let free_regions_iter = self
+            .universal_regions_outlived_by(r)
+            .map(RegionElement::RootUniversalRegion);
+
+        points_iter.chain(free_regions_iter)
     }
 
     /// Returns a "pretty" string value of the region. Meant for debugging.
@@ -306,7 +294,7 @@ pub fn merge_into(&mut self, into: N, from: &BitVector<RegionElementIndex>) -> b
                     open_location = Some((l, l));
                 }
 
-                RegionElement::UniversalRegion(fr) => {
+                RegionElement::RootUniversalRegion(fr) => {
                     if let Some((location1, location2)) = open_location {
                         push_sep(&mut result);
                         Self::push_location_range(&mut result, location1, location2);
@@ -341,3 +329,55 @@ fn push_location_range(str: &mut String, location1: Location, location2: Locatio
         }
     }
 }
+
+crate trait ToElementIndex: Debug + Copy {
+    fn add_to_row<N: Idx>(
+        self,
+        values: &mut RegionValues<N>,
+        row: N,
+    ) -> bool;
+
+    fn contained_in_row<N: Idx>(
+        self,
+        values: &RegionValues<N>,
+        row: N,
+    ) -> bool;
+}
+
+impl ToElementIndex for Location {
+    fn add_to_row<N: Idx>(
+        self,
+        values: &mut RegionValues<N>,
+        row: N,
+    ) -> bool {
+        let index = values.elements.point_from_location(self);
+        values.points.add(row, index)
+    }
+
+    fn contained_in_row<N: Idx>(
+        self,
+        values: &RegionValues<N>,
+        row: N,
+    ) -> bool {
+        let index = values.elements.point_from_location(self);
+        values.points.contains(row, index)
+    }
+}
+
+impl ToElementIndex for RegionVid {
+    fn add_to_row<N: Idx>(
+        self,
+        values: &mut RegionValues<N>,
+        row: N,
+    ) -> bool {
+        values.free_regions.add(row, self)
+    }
+
+    fn contained_in_row<N: Idx>(
+        self,
+        values: &RegionValues<N>,
+        row: N,
+    ) -> bool {
+        values.free_regions.contains(row, self)
+    }
+}
index 6483b9b3c68f0676fcf2616be67352ab8472f171..382248c2d15dca3479c31234fabc94029dd15922 100644 (file)
@@ -27,6 +27,7 @@
 #![feature(core_intrinsics)]
 #![feature(decl_macro)]
 #![feature(fs_read_write)]
+#![feature(in_band_lifetimes)]
 #![feature(macro_vis_matcher)]
 #![feature(exhaustive_patterns)]
 #![feature(range_contains)]