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.
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.
/// 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
#[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> {
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),
}
}
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.
&'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.
&'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.
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);
}
}
}
+
+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)
+ }
+}