1
Fork 0

Auto merge of #53656 - nnethercote:HybridIdxSet-tweaks, r=nikomatsakis

`HybridIdxSet` tweaks

A couple of tweaks to `HybridIdxSet`.

r? @nikomatsakis
This commit is contained in:
bors 2018-08-27 11:47:03 +00:00
commit b638d8c75f
4 changed files with 111 additions and 85 deletions

View file

@ -19,6 +19,20 @@ use bitslice::{bitwise, Union, Subtract, Intersect};
use indexed_vec::Idx; use indexed_vec::Idx;
use rustc_serialize; use rustc_serialize;
/// This is implemented by all the index sets so that IdxSet::union() can be
/// passed any type of index set.
pub trait UnionIntoIdxSet<T: Idx> {
// Performs `other = other | self`.
fn union_into(&self, other: &mut IdxSet<T>) -> bool;
}
/// This is implemented by all the index sets so that IdxSet::subtract() can be
/// passed any type of index set.
pub trait SubtractFromIdxSet<T: Idx> {
// Performs `other = other - self`.
fn subtract_from(&self, other: &mut IdxSet<T>) -> bool;
}
/// Represents a set of some element type E, where each E is identified by some /// Represents a set of some element type E, where each E is identified by some
/// unique index type `T`. /// unique index type `T`.
/// ///
@ -68,34 +82,34 @@ impl<T: Idx> fmt::Debug for IdxSet<T> {
} }
impl<T: Idx> IdxSet<T> { impl<T: Idx> IdxSet<T> {
fn new(init: Word, universe_size: usize) -> Self { fn new(init: Word, domain_size: usize) -> Self {
let num_words = (universe_size + (BITS_PER_WORD - 1)) / BITS_PER_WORD; let num_words = (domain_size + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
IdxSet { IdxSet {
_pd: Default::default(), _pd: Default::default(),
bits: vec![init; num_words], bits: vec![init; num_words],
} }
} }
/// Creates set holding every element whose index falls in range 0..universe_size. /// Creates set holding every element whose index falls in range 0..domain_size.
pub fn new_filled(universe_size: usize) -> Self { pub fn new_filled(domain_size: usize) -> Self {
let mut result = Self::new(!0, universe_size); let mut result = Self::new(!0, domain_size);
result.trim_to(universe_size); result.trim_to(domain_size);
result result
} }
/// Creates set holding no elements. /// Creates set holding no elements.
pub fn new_empty(universe_size: usize) -> Self { pub fn new_empty(domain_size: usize) -> Self {
Self::new(0, universe_size) Self::new(0, domain_size)
} }
/// Duplicates as a hybrid set. /// Duplicates as a hybrid set.
pub fn to_hybrid(&self) -> HybridIdxSet<T> { pub fn to_hybrid(&self) -> HybridIdxSet<T> {
// This universe_size may be slightly larger than the one specified // This domain_size may be slightly larger than the one specified
// upon creation, due to rounding up to a whole word. That's ok. // upon creation, due to rounding up to a whole word. That's ok.
let universe_size = self.bits.len() * BITS_PER_WORD; let domain_size = self.bits.len() * BITS_PER_WORD;
// Note: we currently don't bother trying to make a Sparse set. // Note: we currently don't bother trying to make a Sparse set.
HybridIdxSet::Dense(self.to_owned(), universe_size) HybridIdxSet::Dense(self.to_owned(), domain_size)
} }
/// Removes all elements /// Removes all elements
@ -105,19 +119,19 @@ impl<T: Idx> IdxSet<T> {
} }
} }
/// Sets all elements up to `universe_size` /// Sets all elements up to `domain_size`
pub fn set_up_to(&mut self, universe_size: usize) { pub fn set_up_to(&mut self, domain_size: usize) {
for b in &mut self.bits { for b in &mut self.bits {
*b = !0; *b = !0;
} }
self.trim_to(universe_size); self.trim_to(domain_size);
} }
/// Clear all elements above `universe_size`. /// Clear all elements above `domain_size`.
fn trim_to(&mut self, universe_size: usize) { fn trim_to(&mut self, domain_size: usize) {
// `trim_block` is the first block where some bits have // `trim_block` is the first block where some bits have
// to be cleared. // to be cleared.
let trim_block = universe_size / BITS_PER_WORD; let trim_block = domain_size / BITS_PER_WORD;
// all the blocks above it have to be completely cleared. // all the blocks above it have to be completely cleared.
if trim_block < self.bits.len() { if trim_block < self.bits.len() {
@ -125,9 +139,9 @@ impl<T: Idx> IdxSet<T> {
*b = 0; *b = 0;
} }
// at that block, the `universe_size % BITS_PER_WORD` lsbs // at that block, the `domain_size % BITS_PER_WORD` LSBs
// should remain. // should remain.
let remaining_bits = universe_size % BITS_PER_WORD; let remaining_bits = domain_size % BITS_PER_WORD;
let mask = (1<<remaining_bits)-1; let mask = (1<<remaining_bits)-1;
self.bits[trim_block] &= mask; self.bits[trim_block] &= mask;
} }
@ -164,48 +178,14 @@ impl<T: Idx> IdxSet<T> {
/// Set `self = self | other` and return true if `self` changed /// Set `self = self | other` and return true if `self` changed
/// (i.e., if new bits were added). /// (i.e., if new bits were added).
pub fn union(&mut self, other: &IdxSet<T>) -> bool { pub fn union(&mut self, other: &impl UnionIntoIdxSet<T>) -> bool {
bitwise(self.words_mut(), other.words(), &Union) other.union_into(self)
}
/// Like `union()`, but takes a `SparseIdxSet` argument.
fn union_sparse(&mut self, other: &SparseIdxSet<T>) -> bool {
let mut changed = false;
for elem in other.iter() {
changed |= self.add(&elem);
}
changed
}
/// Like `union()`, but takes a `HybridIdxSet` argument.
pub fn union_hybrid(&mut self, other: &HybridIdxSet<T>) -> bool {
match other {
HybridIdxSet::Sparse(sparse, _) => self.union_sparse(sparse),
HybridIdxSet::Dense(dense, _) => self.union(dense),
}
} }
/// Set `self = self - other` and return true if `self` changed. /// Set `self = self - other` and return true if `self` changed.
/// (i.e., if any bits were removed). /// (i.e., if any bits were removed).
pub fn subtract(&mut self, other: &IdxSet<T>) -> bool { pub fn subtract(&mut self, other: &impl SubtractFromIdxSet<T>) -> bool {
bitwise(self.words_mut(), other.words(), &Subtract) other.subtract_from(self)
}
/// Like `subtract()`, but takes a `SparseIdxSet` argument.
fn subtract_sparse(&mut self, other: &SparseIdxSet<T>) -> bool {
let mut changed = false;
for elem in other.iter() {
changed |= self.remove(&elem);
}
changed
}
/// Like `subtract()`, but takes a `HybridIdxSet` argument.
pub fn subtract_hybrid(&mut self, other: &HybridIdxSet<T>) -> bool {
match other {
HybridIdxSet::Sparse(sparse, _) => self.subtract_sparse(sparse),
HybridIdxSet::Dense(dense, _) => self.subtract(dense),
}
} }
/// Set `self = self & other` and return true if `self` changed. /// Set `self = self & other` and return true if `self` changed.
@ -223,6 +203,18 @@ impl<T: Idx> IdxSet<T> {
} }
} }
impl<T: Idx> UnionIntoIdxSet<T> for IdxSet<T> {
fn union_into(&self, other: &mut IdxSet<T>) -> bool {
bitwise(other.words_mut(), self.words(), &Union)
}
}
impl<T: Idx> SubtractFromIdxSet<T> for IdxSet<T> {
fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
bitwise(other.words_mut(), self.words(), &Subtract)
}
}
pub struct Iter<'a, T: Idx> { pub struct Iter<'a, T: Idx> {
cur: Option<(Word, usize)>, cur: Option<(Word, usize)>,
iter: iter::Enumerate<slice::Iter<'a, Word>>, iter: iter::Enumerate<slice::Iter<'a, Word>>,
@ -293,8 +285,8 @@ impl<T: Idx> SparseIdxSet<T> {
} }
} }
fn to_dense(&self, universe_size: usize) -> IdxSet<T> { fn to_dense(&self, domain_size: usize) -> IdxSet<T> {
let mut dense = IdxSet::new_empty(universe_size); let mut dense = IdxSet::new_empty(domain_size);
for elem in self.0.iter() { for elem in self.0.iter() {
dense.add(elem); dense.add(elem);
} }
@ -308,6 +300,26 @@ impl<T: Idx> SparseIdxSet<T> {
} }
} }
impl<T: Idx> UnionIntoIdxSet<T> for SparseIdxSet<T> {
fn union_into(&self, other: &mut IdxSet<T>) -> bool {
let mut changed = false;
for elem in self.iter() {
changed |= other.add(&elem);
}
changed
}
}
impl<T: Idx> SubtractFromIdxSet<T> for SparseIdxSet<T> {
fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
let mut changed = false;
for elem in self.iter() {
changed |= other.remove(&elem);
}
changed
}
}
pub struct SparseIter<'a, T: Idx> { pub struct SparseIter<'a, T: Idx> {
iter: slice::Iter<'a, T>, iter: slice::Iter<'a, T>,
} }
@ -323,7 +335,7 @@ impl<'a, T: Idx> Iterator for SparseIter<'a, T> {
/// Like IdxSet, but with a hybrid representation: sparse when there are few /// Like IdxSet, but with a hybrid representation: sparse when there are few
/// elements in the set, but dense when there are many. It's especially /// elements in the set, but dense when there are many. It's especially
/// efficient for sets that typically have a small number of elements, but a /// efficient for sets that typically have a small number of elements, but a
/// large `universe_size`, and are cleared frequently. /// large `domain_size`, and are cleared frequently.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum HybridIdxSet<T: Idx> { pub enum HybridIdxSet<T: Idx> {
Sparse(SparseIdxSet<T>, usize), Sparse(SparseIdxSet<T>, usize),
@ -331,20 +343,16 @@ pub enum HybridIdxSet<T: Idx> {
} }
impl<T: Idx> HybridIdxSet<T> { impl<T: Idx> HybridIdxSet<T> {
pub fn new_empty(universe_size: usize) -> Self { pub fn new_empty(domain_size: usize) -> Self {
HybridIdxSet::Sparse(SparseIdxSet::new(), universe_size) HybridIdxSet::Sparse(SparseIdxSet::new(), domain_size)
}
fn universe_size(&mut self) -> usize {
match *self {
HybridIdxSet::Sparse(_, size) => size,
HybridIdxSet::Dense(_, size) => size,
}
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {
let universe_size = self.universe_size(); let domain_size = match *self {
*self = HybridIdxSet::new_empty(universe_size); HybridIdxSet::Sparse(_, size) => size,
HybridIdxSet::Dense(_, size) => size,
};
*self = HybridIdxSet::new_empty(domain_size);
} }
/// Returns true iff set `self` contains `elem`. /// Returns true iff set `self` contains `elem`.
@ -374,11 +382,11 @@ impl<T: Idx> HybridIdxSet<T> {
// appease the borrow checker. // appease the borrow checker.
let dummy = HybridIdxSet::Sparse(SparseIdxSet::new(), 0); let dummy = HybridIdxSet::Sparse(SparseIdxSet::new(), 0);
match mem::replace(self, dummy) { match mem::replace(self, dummy) {
HybridIdxSet::Sparse(sparse, universe_size) => { HybridIdxSet::Sparse(sparse, domain_size) => {
let mut dense = sparse.to_dense(universe_size); let mut dense = sparse.to_dense(domain_size);
let changed = dense.add(elem); let changed = dense.add(elem);
assert!(changed); assert!(changed);
mem::replace(self, HybridIdxSet::Dense(dense, universe_size)); mem::replace(self, HybridIdxSet::Dense(dense, domain_size));
changed changed
} }
_ => panic!("impossible"), _ => panic!("impossible"),
@ -401,7 +409,7 @@ impl<T: Idx> HybridIdxSet<T> {
/// Converts to a dense set, consuming itself in the process. /// Converts to a dense set, consuming itself in the process.
pub fn to_dense(self) -> IdxSet<T> { pub fn to_dense(self) -> IdxSet<T> {
match self { match self {
HybridIdxSet::Sparse(sparse, universe_size) => sparse.to_dense(universe_size), HybridIdxSet::Sparse(sparse, domain_size) => sparse.to_dense(domain_size),
HybridIdxSet::Dense(dense, _) => dense, HybridIdxSet::Dense(dense, _) => dense,
} }
} }
@ -415,6 +423,24 @@ impl<T: Idx> HybridIdxSet<T> {
} }
} }
impl<T: Idx> UnionIntoIdxSet<T> for HybridIdxSet<T> {
fn union_into(&self, other: &mut IdxSet<T>) -> bool {
match self {
HybridIdxSet::Sparse(sparse, _) => sparse.union_into(other),
HybridIdxSet::Dense(dense, _) => dense.union_into(other),
}
}
}
impl<T: Idx> SubtractFromIdxSet<T> for HybridIdxSet<T> {
fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
match self {
HybridIdxSet::Sparse(sparse, _) => sparse.subtract_from(other),
HybridIdxSet::Dense(dense, _) => dense.subtract_from(other),
}
}
}
pub enum HybridIter<'a, T: Idx> { pub enum HybridIter<'a, T: Idx> {
Sparse(SparseIter<'a, T>), Sparse(SparseIter<'a, T>),
Dense(Iter<'a, T>), Dense(Iter<'a, T>),

View file

@ -129,8 +129,8 @@ where
F: FnOnce(Iter<BD::Idx>), F: FnOnce(Iter<BD::Idx>),
{ {
let mut curr_state = self.curr_state.clone(); let mut curr_state = self.curr_state.clone();
curr_state.union_hybrid(&self.stmt_gen); curr_state.union(&self.stmt_gen);
curr_state.subtract_hybrid(&self.stmt_kill); curr_state.subtract(&self.stmt_kill);
f(curr_state.iter()); f(curr_state.iter());
} }
} }
@ -193,8 +193,8 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
} }
fn apply_local_effect(&mut self, _loc: Location) { fn apply_local_effect(&mut self, _loc: Location) {
self.curr_state.union_hybrid(&self.stmt_gen); self.curr_state.union(&self.stmt_gen);
self.curr_state.subtract_hybrid(&self.stmt_kill); self.curr_state.subtract(&self.stmt_kill);
} }
} }

View file

@ -241,8 +241,8 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: Bi
let sets = self.builder.flow_state.sets.for_block(bb.index()); let sets = self.builder.flow_state.sets.for_block(bb.index());
debug_assert!(in_out.words().len() == sets.on_entry.words().len()); debug_assert!(in_out.words().len() == sets.on_entry.words().len());
in_out.overwrite(sets.on_entry); in_out.overwrite(sets.on_entry);
in_out.union_hybrid(sets.gen_set); in_out.union(sets.gen_set);
in_out.subtract_hybrid(sets.kill_set); in_out.subtract(sets.kill_set);
} }
self.builder.propagate_bits_into_graph_successors_of( self.builder.propagate_bits_into_graph_successors_of(
in_out, (bb, bb_data), &mut dirty_queue); in_out, (bb, bb_data), &mut dirty_queue);
@ -534,8 +534,8 @@ impl<'a, E:Idx> BlockSets<'a, E> {
} }
fn apply_local_effect(&mut self) { fn apply_local_effect(&mut self) {
self.on_entry.union_hybrid(&self.gen_set); self.on_entry.union(self.gen_set);
self.on_entry.subtract_hybrid(&self.kill_set); self.on_entry.subtract(self.kill_set);
} }
} }

View file

@ -209,8 +209,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
&mut sets, Location { block: bb, statement_index: j }); &mut sets, Location { block: bb, statement_index: j });
results.0.operator.statement_effect( results.0.operator.statement_effect(
&mut sets, Location { block: bb, statement_index: j }); &mut sets, Location { block: bb, statement_index: j });
sets.on_entry.union_hybrid(sets.gen_set); sets.on_entry.union(sets.gen_set);
sets.on_entry.subtract_hybrid(sets.kill_set); sets.on_entry.subtract(sets.kill_set);
} }
results.0.operator.before_terminator_effect( results.0.operator.before_terminator_effect(