提交 71af40bb 编写于 作者: F Felix S. Klock II

revised mir-dataflow so bitvectors carry a phantom type for their index domain.

As some drive-by's:

 * moved bitwise operators into `mod bitslice`

 * factored out `fn gen` and `fn kill` methods on `BlockSets` type

 * removed outdated comment about `fn propagate_call_return`
上级 0796ee77
......@@ -109,3 +109,32 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String {
result.push(']');
return result
}
#[inline]
pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
in_vec: &[usize],
op: &Op) -> bool {
assert_eq!(out_vec.len(), in_vec.len());
let mut changed = false;
for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
let old_val = *out_elt;
let new_val = op.join(old_val, *in_elt);
*out_elt = new_val;
changed |= old_val != new_val;
}
changed
}
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;
}
pub struct Union;
impl BitwiseOperator for Union {
fn join(&self, a: usize, b: usize) -> usize { a | b }
}
pub struct Subtract;
impl BitwiseOperator for Subtract {
fn join(&self, a: usize, b: usize) -> usize { a & !b }
}
......@@ -54,8 +54,9 @@ struct Graph<'a, 'tcx, MWF:'a> where MWF: MirWithFlowState<'tcx>,
pub fn print_borrowck_graph_to<'a, 'tcx, BD>(
mbcx: &MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>,
path: &Path) -> io::Result<()> where BD: BitDenotation,
BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx>
path: &Path)
-> io::Result<()>
where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx>,
{
let g = Graph { mbcx: mbcx, phantom: PhantomData };
let mut v = Vec::new();
......@@ -180,7 +181,7 @@ fn chunked_present_left<D: Debug, W:io::Write>(w: &mut W,
<td></td></tr>",
bg = BG_FLOWCONTENT,
face = FACE_MONOSPACE,
entrybits=bits_to_string(entry, bits_per_block))
entrybits=bits_to_string(entry.words(), bits_per_block))
},
|w| {
let ctxt = self.mbcx.analysis_ctxt();
......@@ -197,7 +198,7 @@ fn chunked_present_left<D: Debug, W:io::Write>(w: &mut W,
<td></td></tr>",
bg = BG_FLOWCONTENT,
face = FACE_MONOSPACE,
genbits=bits_to_string(gen, bits_per_block))?;
genbits=bits_to_string(gen.words(), bits_per_block))?;
}
{
......@@ -209,7 +210,7 @@ fn chunked_present_left<D: Debug, W:io::Write>(w: &mut W,
bg = BG_FLOWCONTENT,
align = ALIGN_RIGHT,
face = FACE_MONOSPACE,
killbits=bits_to_string(kill, bits_per_block))?;
killbits=bits_to_string(kill.words(), bits_per_block))?;
}
// (chunked_present_right)
......
......@@ -15,10 +15,7 @@
use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};
use bitslice::BitSlice;
use super::super::gather_moves::MovePath;
use super::{bitwise, Union, Subtract};
use super::super::gather_moves::{MovePath, MovePathIndex};
use super::BitDenotation;
use super::DataflowResults;
use super::HasMoveData;
......@@ -45,7 +42,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_attributes: &[ast::Attribute],
flow_ctxt: &O::Ctxt,
results: &DataflowResults<O>)
where O: BitDenotation<Bit=MovePath<'tcx>>, O::Ctxt: HasMoveData<'tcx>
where O: BitDenotation<Bit=MovePath<'tcx>, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx>
{
debug!("sanity_check_via_rustc_peek id: {:?}", id);
// FIXME: this is not DRY. Figure out way to abstract this and
......@@ -87,9 +84,9 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// include terminator (since we are peeking the state of the
// argument at time immediate preceding Call to `rustc_peek`).
let mut sets = super::BlockSets { on_entry: &mut entry[..],
gen_set: &mut gen[..],
kill_set: &mut kill[..] };
let mut sets = super::BlockSets { on_entry: &mut entry,
gen_set: &mut gen,
kill_set: &mut kill };
for (j, stmt) in statements.iter().enumerate() {
debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
......@@ -105,7 +102,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ref peeking_at_lval) = *rvalue {
// Okay, our search is over.
let peek_mpi = move_data.rev_lookup.find(peeking_at_lval);
let bit_state = sets.on_entry.get_bit(peek_mpi.idx());
let bit_state = sets.on_entry.contains(&peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
lvalue, peeking_at_lval, bit_state);
if !bit_state {
......@@ -126,11 +123,11 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}",
lvalue, lhs_mpi, stmt);
// reset GEN and KILL sets before emulating their effect.
for e in &mut sets.gen_set[..] { *e = 0; }
for e in &mut sets.kill_set[..] { *e = 0; }
for e in sets.gen_set.words_mut() { *e = 0; }
for e in sets.kill_set.words_mut() { *e = 0; }
results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j);
bitwise(sets.on_entry, sets.gen_set, &Union);
bitwise(sets.on_entry, sets.kill_set, &Subtract);
sets.on_entry.union(sets.gen_set);
sets.on_entry.subtract(sets.kill_set);
}
tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
......
......@@ -20,6 +20,7 @@
use std::ops::Index;
use super::abs_domain::{AbstractElem, Lift};
use indexed_set::{Idx, Indexed};
// This submodule holds some newtype'd Index wrappers that are using
// NonZero to ensure that Option<Index> occupies only a single word.
......@@ -28,6 +29,7 @@
// (which is likely to yield a subtle off-by-one error).
mod indexes {
use core::nonzero::NonZero;
use indexed_set::Idx;
macro_rules! new_index {
($Index:ident) => {
......@@ -35,10 +37,13 @@ mod indexes {
pub struct $Index(NonZero<usize>);
impl $Index {
pub fn new(idx: usize) -> Self {
}
impl Idx for $Index {
fn new(idx: usize) -> Self {
unsafe { $Index(NonZero::new(idx + 1)) }
}
pub fn idx(&self) -> usize {
fn idx(&self) -> usize {
*self.0 - 1
}
}
......@@ -55,6 +60,14 @@ pub fn idx(&self) -> usize {
pub use self::indexes::MovePathIndex;
pub use self::indexes::MoveOutIndex;
impl<'tcx> Indexed for MovePath<'tcx> {
type Idx = MovePathIndex;
}
impl Indexed for MoveOut {
type Idx = MoveOutIndex;
}
impl self::indexes::MoveOutIndex {
pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex {
move_data.moves[self.idx()].path
......
......@@ -11,13 +11,16 @@
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut, Range};
use bitslice::{BitSlice, Word};
use bitslice::{bitwise, Union, Subtract};
pub trait Indexed {
type Idx: Idx;
}
pub trait Idx {
pub trait Idx: 'static {
fn new(usize) -> Self;
fn idx(&self) -> usize;
}
......@@ -26,10 +29,16 @@ pub struct OwnIdxSet<T: Idx> {
bits: Vec<Word>,
}
impl<T: Idx> Clone for OwnIdxSet<T> {
fn clone(&self) -> Self {
OwnIdxSet { _pd: PhantomData, bits: self.bits.clone() }
}
}
// pnkfelix wants to have this be `IdxSet<T>([Word]) and then pass
// around `&mut IdxSet<T>` or `&IdxSet<T>`.
//
// Mmapping a `&OwnIdxSet<T>` to `&IdxSet<T>` (at least today)
// WARNING: Mapping a `&OwnIdxSet<T>` to `&IdxSet<T>` (at least today)
// requires a transmute relying on representation guarantees that may
// not hold in the future.
......@@ -65,9 +74,41 @@ pub fn new_filled(universe_size: usize) -> Self {
pub fn new_empty(universe_size: usize) -> Self {
Self::new(0, universe_size)
}
}
impl<T: Idx> IdxSet<T> {
unsafe fn from_slice(s: &[Word]) -> &Self {
mem::transmute(s) // (see above WARNING)
}
unsafe fn from_slice_mut(s: &mut [Word]) -> &mut Self {
mem::transmute(s) // (see above WARNING)
}
}
impl<T: Idx> Deref for OwnIdxSet<T> {
type Target = IdxSet<T>;
fn deref(&self) -> &IdxSet<T> {
unsafe { IdxSet::from_slice(&self.bits[..]) }
}
}
impl<T: Idx> DerefMut for OwnIdxSet<T> {
fn deref_mut(&mut self) -> &mut IdxSet<T> {
unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) }
}
}
impl<T: Idx> IdxSet<T> {
pub fn to_owned(&self) -> OwnIdxSet<T> {
OwnIdxSet {
_pd: Default::default(),
bits: self.bits.to_owned(),
}
}
/// Removes `elem` from the set `self`; returns true iff this changed `self`.
pub fn clear(&mut self, elem: &T) -> bool {
pub fn remove(&mut self, elem: &T) -> bool {
self.bits.clear_bit(elem.idx())
}
......@@ -76,12 +117,38 @@ pub fn add(&mut self, elem: &T) -> bool {
self.bits.set_bit(elem.idx())
}
pub fn range(&self, elems: &Range<T>) -> &Self {
let elems = elems.start.idx()..elems.end.idx();
unsafe { Self::from_slice(&self.bits[elems]) }
}
pub fn range_mut(&mut self, elems: &Range<T>) -> &mut Self {
let elems = elems.start.idx()..elems.end.idx();
unsafe { Self::from_slice_mut(&mut self.bits[elems]) }
}
/// Returns true iff set `self` contains `elem`.
pub fn contains(&self, elem: &T) -> bool {
self.bits.get_bit(elem.idx())
}
pub fn bits(&self) -> &[Word] {
pub fn words(&self) -> &[Word] {
&self.bits[..]
}
pub fn words_mut(&mut self) -> &mut [Word] {
&mut self.bits[..]
}
pub fn clone_from(&mut self, other: &IdxSet<T>) {
self.words_mut().clone_from_slice(other.words());
}
pub fn union(&mut self, other: &IdxSet<T>) -> bool {
bitwise(self.words_mut(), other.words(), &Union)
}
pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
bitwise(self.words_mut(), other.words(), &Subtract)
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册