split into two matrices

This commit is contained in:
Niko Matsakis 2018-07-22 19:46:48 +03:00
parent 40498bae65
commit 3f0fb4f7d8
4 changed files with 243 additions and 145 deletions

View File

@ -43,12 +43,27 @@ impl<C: Idx> BitVector<C> {
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 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
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());
}

View 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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
// 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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
});
// 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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// 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

View File

@ -10,11 +10,12 @@
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
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)
}
/// Converts an element of a region value into a `RegionElementIndex`.
crate fn index<T: ToElementIndex>(&self, elem: T) -> RegionElementIndex {
elem.to_element_index(self)
/// Range coverting all point indices.
fn all_points(&self) -> Range<PointIndex> {
PointIndex::new(0)..PointIndex::new(self.num_points)
}
/// 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))
}
/// 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();
/// Converts a particular `RegionElementIndex` to the `RegionElement` it represents.
crate fn to_element(&self, i: RegionElementIndex) -> RegionElement {
debug!("to_element(i={:?})", i);
// 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();
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
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 @@ crate enum RegionElement {
/// 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 @@ impl ToElementIndex for 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 @@ impl<N: Idx> RegionValues<N> {
&'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 @@ impl<N: Idx> RegionValues<N> {
&'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 @@ impl<N: Idx> RegionValues<N> {
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 @@ impl<N: Idx> RegionValues<N> {
}
}
}
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)
}
}

View File

@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
#![feature(core_intrinsics)]
#![feature(decl_macro)]
#![feature(fs_read_write)]
#![feature(in_band_lifetimes)]
#![feature(macro_vis_matcher)]
#![feature(exhaustive_patterns)]
#![feature(range_contains)]