Skip to content

Commit

Permalink
Auto merge of #52335 - nnethercote:BitSlice-fixes, r=nikomatsakis
Browse files Browse the repository at this point in the history
`BitSlice` fixes

`propagate_bits_into_entry_set_for` and `BitSlice::bitwise` are hot for some benchmarks under NLL. I tried and failed to speed them up. (Increasing the size of `bit_slice::Word` from `usize` to `u128` caused a slowdown, even though decreasing the size of `bitvec::Word` from `u128` to `u64` also caused a slowdown. Weird.)

Anyway, along the way I fixed up several problems in and around the `BitSlice` code.

r? @nikomatsakis
  • Loading branch information
bors committed Jul 17, 2018
2 parents 9d6f4e5 + f2b0b67 commit 2ddc0cb
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 44 deletions.
28 changes: 11 additions & 17 deletions src/librustc_data_structures/bitslice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ impl BitSlice for [Word] {
fn clear_bit(&mut self, idx: usize) -> bool {
let words = self;
debug!("clear_bit: words={} idx={}",
bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
bits_to_string(words, words.len() * mem::size_of::<Word>() * 8), idx);
let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
debug!("word={} bit_in_word={} bit_mask=0x{:x}", word, bit_in_word, bit_mask);
let oldv = words[word];
let newv = oldv & !bit_mask;
words[word] = newv;
Expand All @@ -42,7 +42,7 @@ impl BitSlice for [Word] {
fn set_bit(&mut self, idx: usize) -> bool {
let words = self;
debug!("set_bit: words={} idx={}",
bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
bits_to_string(words, words.len() * mem::size_of::<Word>() * 8), idx);
let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
let oldv = words[word];
Expand Down Expand Up @@ -78,13 +78,6 @@ fn bit_lookup(bit: usize) -> BitLookup {
BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask }
}


fn bit_str(bit: Word) -> String {
let byte = bit >> 3;
let lobits = 1 << (bit & 0b111);
format!("[{}:{}-{:02x}]", bit, byte, lobits)
}

pub fn bits_to_string(words: &[Word], bits: usize) -> String {
let mut result = String::new();
let mut sep = '[';
Expand All @@ -95,7 +88,7 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String {
let mut i = 0;
for &word in words.iter() {
let mut v = word;
loop { // for each byte in `v`:
for _ in 0..mem::size_of::<Word>() { // for each byte in `v`:
let remain = bits - i;
// If less than a byte remains, then mask just that many bits.
let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
Expand All @@ -110,14 +103,15 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String {
i += 8;
sep = '-';
}
sep = '|';
}
result.push(']');
return result
}

#[inline]
pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
in_vec: &[usize],
pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [Word],
in_vec: &[Word],
op: &Op) -> bool {
assert_eq!(out_vec.len(), in_vec.len());
let mut changed = false;
Expand All @@ -132,21 +126,21 @@ pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],

pub trait BitwiseOperator {
/// Applies some bit-operation pointwise to each of the bits in the two inputs.
fn join(&self, pred1: usize, pred2: usize) -> usize;
fn join(&self, pred1: Word, pred2: Word) -> Word;
}

pub struct Intersect;
impl BitwiseOperator for Intersect {
#[inline]
fn join(&self, a: usize, b: usize) -> usize { a & b }
fn join(&self, a: Word, b: Word) -> Word { a & b }
}
pub struct Union;
impl BitwiseOperator for Union {
#[inline]
fn join(&self, a: usize, b: usize) -> usize { a | b }
fn join(&self, a: Word, b: Word) -> Word { a | b }
}
pub struct Subtract;
impl BitwiseOperator for Subtract {
#[inline]
fn join(&self, a: usize, b: usize) -> usize { a & !b }
fn join(&self, a: Word, b: Word) -> Word { a & !b }
}
2 changes: 1 addition & 1 deletion src/librustc_mir/dataflow/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {

impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc::ty::TyCtxt;
use rustc::ty::{RegionKind, RegionVid};
use rustc::ty::RegionKind::ReScope;

use rustc_data_structures::bitslice::BitwiseOperator;
use rustc_data_structures::bitslice::{BitwiseOperator, Word};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_set::IdxSet;
use rustc_data_structures::indexed_vec::IndexVec;
Expand Down Expand Up @@ -370,7 +370,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {

impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // union effects of preds when computing reservations
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/librustc_mir/dataflow/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use rustc::ty::TyCtxt;
use rustc::mir::{self, Mir, Location};
use rustc_data_structures::bitslice::{BitwiseOperator};
use rustc_data_structures::bitslice::{BitwiseOperator, Word};
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;

Expand Down Expand Up @@ -663,35 +663,35 @@ impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {

impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}

impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}

impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 & pred2 // "definitely" means we intersect effects of both preds
}
}

impl<'a, 'gcx, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'gcx, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // moves from both preds are in scope
}
}

impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // inits from both preds are in scope
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/dataflow/impls/storage_liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {

impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
#[inline]
fn join(&self, pred1: usize, pred2: usize) -> usize {
fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}
Expand Down
24 changes: 7 additions & 17 deletions src/librustc_mir/dataflow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use syntax::ast::{self, MetaItem};

use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
use rustc_data_structures::bitslice::{bitwise, BitwiseOperator, Word};
use rustc_data_structures::work_queue::WorkQueue;

use rustc::ty::{self, TyCtxt};
Expand Down Expand Up @@ -467,7 +467,7 @@ pub struct AllSets<E: Idx> {
bits_per_block: usize,

/// Number of words associated with each block entry
/// equal to bits_per_block / usize::BITS, rounded up.
/// equal to bits_per_block / (mem::size_of::<Word> * 8), rounded up.
words_per_block: usize,

/// For each block, bits generated by executing the statements in
Expand Down Expand Up @@ -734,9 +734,11 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
dead_unwinds: &'a IdxSet<mir::BasicBlock>,
denotation: D) -> Self where D: InitialFlow {
let bits_per_block = denotation.bits_per_block();
let usize_bits = mem::size_of::<usize>() * 8;
let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
let num_overall = Self::num_bits_overall(mir, bits_per_block);
let bits_per_word = mem::size_of::<Word>() * 8;
let words_per_block = (bits_per_block + bits_per_word - 1) / bits_per_word;
let bits_per_block_rounded_up = words_per_block * bits_per_word; // a multiple of word size
let num_blocks = mir.basic_blocks().len();
let num_overall = num_blocks * bits_per_block_rounded_up;

let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall));
let on_entry = Bits::new(if D::bottom_value() {
Expand Down Expand Up @@ -774,18 +776,6 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
}
}
}

fn num_bits_overall(mir: &Mir, bits_per_block: usize) -> usize {
let usize_bits = mem::size_of::<usize>() * 8;
let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;

// (now rounded up to multiple of word size)
let bits_per_block = words_per_block * usize_bits;

let num_blocks = mir.basic_blocks().len();
let num_overall = num_blocks * bits_per_block;
num_overall
}
}

impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
Expand Down

0 comments on commit 2ddc0cb

Please sign in to comment.