提交 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)
......
......@@ -24,6 +24,8 @@
use super::DropFlagState;
use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
use bitslice::{bitwise, BitwiseOperator};
use indexed_set::{Idx, IdxSet, OwnIdxSet};
pub use self::sanity_check::sanity_check_via_rustc_peek;
......@@ -35,7 +37,9 @@ pub trait Dataflow {
}
impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
where BD: BitDenotation + DataflowOperator, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx>
where BD: BitDenotation + DataflowOperator,
BD::Bit: Debug,
BD::Ctxt: HasMoveData<'tcx>
{
fn dataflow(&mut self) {
self.flow_state.build_sets();
......@@ -46,7 +50,7 @@ fn dataflow(&mut self) {
}
struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O>
where O: 'b + BitDenotation, O::Ctxt: HasMoveData<'tcx>,
where O: 'b + BitDenotation, O::Ctxt: HasMoveData<'tcx>
{
builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
changed: bool,
......@@ -56,7 +60,7 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD>
where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx>
{
fn propagate(&mut self) {
let mut temp = vec![0; self.flow_state.sets.words_per_block];
let mut temp = OwnIdxSet::new_empty(self.flow_state.sets.bits_per_block);
let mut propcx = PropagationContext {
builder: self,
changed: true,
......@@ -102,23 +106,23 @@ fn build_sets(&mut self) {
impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD>
where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx>
{
fn reset(&mut self, bits: &mut [usize]) {
let e = if BD::bottom_value() {usize::MAX} else {0};
for b in bits {
fn reset(&mut self, bits: &mut IdxSet<BD::Idx>) {
let e = if BD::bottom_value() {!0} else {0};
for b in bits.words_mut() {
*b = e;
}
}
fn walk_cfg(&mut self, in_out: &mut [usize]) {
fn walk_cfg(&mut self, in_out: &mut IdxSet<BD::Idx>) {
let mir = self.builder.mir;
for (bb_idx, bb_data) in mir.basic_blocks.iter().enumerate() {
let builder = &mut self.builder;
{
let sets = builder.flow_state.sets.for_block(bb_idx);
debug_assert!(in_out.len() == sets.on_entry.len());
in_out.clone_from_slice(sets.on_entry);
bitwise(in_out, sets.gen_set, &Union);
bitwise(in_out, sets.kill_set, &Subtract);
debug_assert!(in_out.words().len() == sets.on_entry.words().len());
in_out.clone_from(sets.on_entry);
in_out.union(sets.gen_set);
in_out.subtract(sets.kill_set);
}
builder.propagate_bits_into_graph_successors_of(in_out,
&mut self.changed,
......@@ -161,14 +165,18 @@ fn post_dataflow_instrumentation(&self) -> io::Result<()> {
}
/// Maps each block to a set of bits
#[derive(Clone, Debug)]
struct Bits {
bits: Vec<usize>,
#[derive(Debug)]
struct Bits<E:Idx> {
bits: OwnIdxSet<E>,
}
impl<E:Idx> Clone for Bits<E> {
fn clone(&self) -> Self { Bits { bits: self.bits.clone() } }
}
impl Bits {
fn new(init_word: usize, num_words: usize) -> Self {
Bits { bits: vec![init_word; num_words] }
impl<E:Idx> Bits<E> {
fn new(bits: OwnIdxSet<E>) -> Self {
Bits { bits: bits }
}
}
......@@ -201,25 +209,23 @@ pub fn results(self) -> (O::Ctxt, DataflowResults<O>) {
pub fn mir(&self) -> &'a Mir<'tcx> { self.mir }
}
#[derive(Debug)]
pub struct DataflowResults<O: BitDenotation>(DataflowState<O>);
pub struct DataflowResults<O>(DataflowState<O>) where O: BitDenotation;
// FIXME: This type shouldn't be public, but the graphviz::MirWithFlowState trait
// references it in a method signature. Look into using `pub(crate)` to address this.
#[derive(Debug)]
pub struct DataflowState<O: BitDenotation>
{
/// All the sets for the analysis. (Factored into its
/// own structure so that we can borrow it mutably
/// on its own separate from other fields.)
pub sets: AllSets,
pub sets: AllSets<O::Idx>,
/// operator used to initialize, combine, and interpret bits.
operator: O,
}
#[derive(Debug)]
pub struct AllSets {
pub struct AllSets<E: Idx> {
/// Analysis bitwidth for each block.
bits_per_block: usize,
......@@ -230,59 +236,71 @@ pub struct AllSets {
/// For each block, bits generated by executing the statements in
/// the block. (For comparison, the Terminator for each block is
/// handled in a flow-specific manner during propagation.)
gen_sets: Bits,
gen_sets: Bits<E>,
/// For each block, bits killed by executing the statements in the
/// block. (For comparison, the Terminator for each block is
/// handled in a flow-specific manner during propagation.)
kill_sets: Bits,
kill_sets: Bits<E>,
/// For each block, bits valid on entry to the block.
on_entry_sets: Bits,
on_entry_sets: Bits<E>,
}
pub struct BlockSets<'a> {
on_entry: &'a mut [usize],
gen_set: &'a mut [usize],
kill_set: &'a mut [usize],
pub struct BlockSets<'a, E: Idx> {
on_entry: &'a mut IdxSet<E>,
gen_set: &'a mut IdxSet<E>,
kill_set: &'a mut IdxSet<E>,
}
impl AllSets {
impl<'a, E:Idx> BlockSets<'a, E> {
fn gen(&mut self, e: &E) {
self.gen_set.add(e);
self.kill_set.remove(e);
}
fn kill(&mut self, e: &E) {
self.gen_set.remove(e);
self.kill_set.add(e);
}
}
impl<E:Idx> AllSets<E> {
pub fn bits_per_block(&self) -> usize { self.bits_per_block }
pub fn for_block(&mut self, block_idx: usize) -> BlockSets {
pub fn for_block(&mut self, block_idx: usize) -> BlockSets<E> {
let offset = self.words_per_block * block_idx;
let range = offset..(offset + self.words_per_block);
let range = E::new(offset)..E::new(offset + self.words_per_block);
BlockSets {
on_entry: &mut self.on_entry_sets.bits[range.clone()],
gen_set: &mut self.gen_sets.bits[range.clone()],
kill_set: &mut self.kill_sets.bits[range],
on_entry: self.on_entry_sets.bits.range_mut(&range),
gen_set: self.gen_sets.bits.range_mut(&range),
kill_set: self.kill_sets.bits.range_mut(&range),
}
}
fn lookup_set_for<'a>(&self, sets: &'a Bits, block_idx: usize) -> &'a [usize] {
fn lookup_set_for<'a>(&self, sets: &'a Bits<E>, block_idx: usize) -> &'a IdxSet<E> {
let offset = self.words_per_block * block_idx;
&sets.bits[offset..(offset + self.words_per_block)]
let range = E::new(offset)..E::new(offset + self.words_per_block);
sets.bits.range(&range)
}
pub fn gen_set_for(&self, block_idx: usize) -> &[usize] {
pub fn gen_set_for(&self, block_idx: usize) -> &IdxSet<E> {
self.lookup_set_for(&self.gen_sets, block_idx)
}
pub fn kill_set_for(&self, block_idx: usize) -> &[usize] {
pub fn kill_set_for(&self, block_idx: usize) -> &IdxSet<E> {
self.lookup_set_for(&self.kill_sets, block_idx)
}
pub fn on_entry_set_for(&self, block_idx: usize) -> &[usize] {
pub fn on_entry_set_for(&self, block_idx: usize) -> &IdxSet<E> {
self.lookup_set_for(&self.on_entry_sets, block_idx)
}
}
impl<O: BitDenotation> DataflowState<O> {
fn each_bit<F>(&self, ctxt: &O::Ctxt, words: &[usize], mut f: F)
fn each_bit<F>(&self, ctxt: &O::Ctxt, words: &IdxSet<O::Idx>, mut f: F)
where F: FnMut(usize) {
//! Helper for iterating over the bits in a bitvector.
let bits_per_block = self.operator.bits_per_block(ctxt);
let usize_bits: usize = mem::size_of::<usize>() * 8;
for (word_index, &word) in words.iter().enumerate() {
for (word_index, &word) in words.words().iter().enumerate() {
if word != 0 {
let base_index = word_index * usize_bits;
for offset in 0..usize_bits {
......@@ -307,7 +325,7 @@ fn each_bit<F>(&self, ctxt: &O::Ctxt, words: &[usize], mut f: F)
}
}
pub fn interpret_set<'c>(&self, ctxt: &'c O::Ctxt, words: &[usize]) -> Vec<&'c O::Bit> {
pub fn interpret_set<'c>(&self, ctxt: &'c O::Ctxt, words: &IdxSet<O::Idx>) -> Vec<&'c O::Bit> {
let mut v = Vec::new();
self.each_bit(ctxt, words, |i| {
v.push(self.operator.interpret(ctxt, i));
......@@ -316,11 +334,6 @@ pub fn interpret_set<'c>(&self, ctxt: &'c O::Ctxt, words: &[usize]) -> Vec<&'c O
}
}
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;
}
/// Parameterization for the precise form of data flow that is used.
pub trait DataflowOperator: BitwiseOperator {
/// Specifies the initial value for each bit in the `on_entry` set
......@@ -331,6 +344,9 @@ pub trait BitDenotation {
/// Specifies what is represented by each bit in the dataflow bitvector.
type Bit;
/// Specifies what index type is used to access the bitvector.
type Idx: Idx;
/// Specifies what, if any, separate context needs to be supplied for methods below.
type Ctxt;
......@@ -359,7 +375,7 @@ pub trait BitDenotation {
/// (Typically this should only modify `sets.on_entry`, since the
/// gen and kill sets should reflect the effects of *executing*
/// the start block itself.)
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets);
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<Self::Idx>);
/// Mutates the block-sets (the flow sets for the given
/// basic block) according to the effects of evaluating statement.
......@@ -373,7 +389,7 @@ pub trait BitDenotation {
/// in the basic block.
fn statement_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<Self::Idx>,
bb: repr::BasicBlock,
idx_stmt: usize);
......@@ -393,7 +409,7 @@ fn statement_effect(&self,
/// terminator took.
fn terminator_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<Self::Idx>,
bb: repr::BasicBlock,
idx_term: usize);
......@@ -411,21 +427,17 @@ fn terminator_effect(&self,
/// flow-dependent, the current MIR cannot encode them via just
/// GEN and KILL sets attached to the block, and so instead we add
/// this extra machinery to represent the flow-dependent effect.
///
/// Note: as a historical artifact, this currently takes as input
/// the *entire* packed collection of bitvectors in `in_out`. We
/// might want to look into narrowing that to something more
/// specific, just to make the interface more self-documenting.
fn propagate_call_return(&self,
ctxt: &Self::Ctxt,
in_out: &mut [usize],
in_out: &mut IdxSet<Self::Idx>,
call_bb: repr::BasicBlock,
dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue);
}
impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
where D: BitDenotation + DataflowOperator, D::Ctxt: HasMoveData<'tcx>
where D: BitDenotation + DataflowOperator,
D::Ctxt: HasMoveData<'tcx>
{
pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
......@@ -434,33 +446,41 @@ pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
let bits_per_block = denotation.bits_per_block(&ctxt);
let usize_bits = mem::size_of::<usize>() * 8;
let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
let num_blocks = mir.basic_blocks.len();
let num_words = num_blocks * words_per_block;
let entry = if D::bottom_value() { usize::MAX } else {0};
// (now rounded up to multiple of word size)
let bits_per_block = words_per_block * usize_bits;
let zeroes = Bits::new(0, num_words);
let on_entry = Bits::new(entry, num_words);
let num_blocks = mir.basic_blocks.len();
let num_overall = num_blocks * bits_per_block;
DataflowAnalysis { flow_state: DataflowState {
sets: AllSets {
bits_per_block: bits_per_block,
words_per_block: words_per_block,
gen_sets: zeroes.clone(),
kill_sets: zeroes,
on_entry_sets: on_entry,
let zeroes = Bits::new(OwnIdxSet::new_empty(num_overall));
let on_entry = Bits::new(if D::bottom_value() {
OwnIdxSet::new_filled(num_overall)
} else {
OwnIdxSet::new_empty(num_overall)
});
DataflowAnalysis {
ctxt: ctxt,
mir: mir,
flow_state: DataflowState {
sets: AllSets {
bits_per_block: bits_per_block,
words_per_block: words_per_block,
gen_sets: zeroes.clone(),
kill_sets: zeroes,
on_entry_sets: on_entry,
},
operator: denotation,
},
operator: denotation,
},
ctxt: ctxt,
mir: mir,
}
}
}
impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
where D: BitDenotation + DataflowOperator, D::Ctxt: HasMoveData<'tcx>
where D: BitDenotation + DataflowOperator,
D::Ctxt: HasMoveData<'tcx>,
{
/// Propagates the bits of `in_out` into all the successors of `bb`,
/// using bitwise operator denoted by `self.operator`.
......@@ -477,7 +497,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
/// unwind target).
fn propagate_bits_into_graph_successors_of(
&mut self,
in_out: &mut [usize],
in_out: &mut IdxSet<D::Idx>,
changed: &mut bool,
(bb, bb_data): (repr::BasicBlock, &repr::BasicBlockData))
{
......@@ -518,11 +538,13 @@ fn propagate_bits_into_graph_successors_of(
}
fn propagate_bits_into_entry_set_for(&mut self,
in_out: &[usize],
in_out: &IdxSet<D::Idx>,
changed: &mut bool,
bb: &repr::BasicBlock) {
let entry_set = self.flow_state.sets.for_block(bb.index()).on_entry;
let set_changed = bitwise(entry_set, in_out, &self.flow_state.operator);
let set_changed = bitwise(entry_set.words_mut(),
in_out.words(),
&self.flow_state.operator);
if set_changed {
*changed = true;
}
......@@ -694,6 +716,7 @@ pub struct MovingOutStatements<'a, 'tcx: 'a> {
}
impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
type Idx = MoveOutIndex;
type Bit = MoveOut;
type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>);
fn name() -> &'static str { "moving_out" }
......@@ -703,13 +726,13 @@ fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit {
&ctxt.2.moves[idx]
}
fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) {
fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets<MoveOutIndex>) {
// no move-statements have been executed prior to function
// execution, so this method has no effect on `_sets`.
}
fn statement_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MoveOutIndex>,
bb: repr::BasicBlock,
idx: usize) {
let &(tcx, mir, ref move_data) = ctxt;
......@@ -725,7 +748,7 @@ fn statement_effect(&self,
// Every path deinitialized by a *particular move*
// has corresponding bit, "gen'ed" (i.e. set)
// here, in dataflow vector
zero_to_one(&mut sets.gen_set, *move_index);
zero_to_one(sets.gen_set.words_mut(), *move_index);
}
let bits_per_block = self.bits_per_block(ctxt);
match stmt.kind {
......@@ -740,7 +763,7 @@ fn statement_effect(&self,
move_path_index,
|mpi| for moi in &path_map[mpi] {
assert!(moi.idx() < bits_per_block);
sets.kill_set.set_bit(moi.idx());
sets.kill_set.add(&moi);
});
}
}
......@@ -748,7 +771,7 @@ fn statement_effect(&self,
fn terminator_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MoveOutIndex>,
bb: repr::BasicBlock,
statements_len: usize)
{
......@@ -761,13 +784,13 @@ fn terminator_effect(&self,
let bits_per_block = self.bits_per_block(ctxt);
for move_index in &loc_map[loc] {
assert!(move_index.idx() < bits_per_block);
zero_to_one(&mut sets.gen_set, *move_index);
zero_to_one(sets.gen_set.words_mut(), *move_index);
}
}
fn propagate_call_return(&self,
ctxt: &Self::Ctxt,
in_out: &mut [usize],
in_out: &mut IdxSet<MoveOutIndex>,
_call_bb: repr::BasicBlock,
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
......@@ -782,63 +805,46 @@ fn propagate_call_return(&self,
move_path_index,
|mpi| for moi in &path_map[mpi] {
assert!(moi.idx() < bits_per_block);
in_out.clear_bit(moi.idx());
in_out.remove(&moi);
});
}
}
impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> {
fn update_bits(sets: &mut BlockSets, path: MovePathIndex,
fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
state: super::DropFlagState)
{
match state {
DropFlagState::Absent => {
sets.gen_set.clear_bit(path.idx());
sets.kill_set.set_bit(path.idx());
}
DropFlagState::Present => {
sets.gen_set.set_bit(path.idx());
sets.kill_set.clear_bit(path.idx());
}
DropFlagState::Absent => sets.kill(&path),
DropFlagState::Present => sets.gen(&path),
}
}
}
impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> {
fn update_bits(sets: &mut BlockSets, path: MovePathIndex,
fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
state: super::DropFlagState)
{
match state {
DropFlagState::Absent => {
sets.gen_set.set_bit(path.idx());
sets.kill_set.clear_bit(path.idx());
}
DropFlagState::Present => {
sets.gen_set.clear_bit(path.idx());
sets.kill_set.set_bit(path.idx());
}
DropFlagState::Absent => sets.gen(&path),
DropFlagState::Present => sets.kill(&path),
}
}
}
impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> {
fn update_bits(sets: &mut BlockSets, path: MovePathIndex,
fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
state: super::DropFlagState)
{
match state {
DropFlagState::Absent => {
sets.gen_set.clear_bit(path.idx());
sets.kill_set.set_bit(path.idx());
}
DropFlagState::Present => {
sets.gen_set.set_bit(path.idx());
sets.kill_set.clear_bit(path.idx());
}
DropFlagState::Absent => sets.kill(&path),
DropFlagState::Present => sets.gen(&path),
}
}
}
impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
type Bit = MovePath<'tcx>;
type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>);
fn name() -> &'static str { "maybe_init" }
......@@ -848,19 +854,19 @@ fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit {
&ctxt.2.move_paths[MovePathIndex::new(idx)]
}
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets)
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>)
{
super::drop_flag_effects_for_function_entry(
ctxt.0, ctxt.1, &ctxt.2,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.set_bit(path.idx());
sets.on_entry.add(&path);
});
}
fn statement_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MovePathIndex>,
bb: repr::BasicBlock,
idx: usize)
{
......@@ -873,7 +879,7 @@ fn statement_effect(&self,
fn terminator_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MovePathIndex>,
bb: repr::BasicBlock,
statements_len: usize)
{
......@@ -886,7 +892,7 @@ fn terminator_effect(&self,
fn propagate_call_return(&self,
ctxt: &Self::Ctxt,
in_out: &mut [usize],
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: repr::BasicBlock,
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
......@@ -897,12 +903,13 @@ fn propagate_call_return(&self,
super::on_all_children_bits(
ctxt.0, ctxt.1, &ctxt.2,
move_path_index,
|mpi| { in_out.set_bit(mpi.idx()); }
|mpi| { in_out.add(&mpi); }
);
}
}
impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
type Bit = MovePath<'tcx>;
type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>);
fn name() -> &'static str { "maybe_uninit" }
......@@ -914,21 +921,21 @@ fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit {
}
// sets on_entry bits for Arg lvalues
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) {
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>) {
// set all bits to 1 (uninit) before gathering counterevidence
for e in &mut sets.on_entry[..] { *e = !0; }
for e in sets.on_entry.words_mut() { *e = !0; }
super::drop_flag_effects_for_function_entry(
ctxt.0, ctxt.1, &ctxt.2,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.clear_bit(path.idx());
sets.on_entry.remove(&path);
});
}
fn statement_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MovePathIndex>,
bb: repr::BasicBlock,
idx: usize)
{
......@@ -941,7 +948,7 @@ fn statement_effect(&self,
fn terminator_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MovePathIndex>,
bb: repr::BasicBlock,
statements_len: usize)
{
......@@ -954,7 +961,7 @@ fn terminator_effect(&self,
fn propagate_call_return(&self,
ctxt: &Self::Ctxt,
in_out: &mut [usize],
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: repr::BasicBlock,
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
......@@ -964,12 +971,13 @@ fn propagate_call_return(&self,
super::on_all_children_bits(
ctxt.0, ctxt.1, &ctxt.2,
move_path_index,
|mpi| { in_out.clear_bit(mpi.idx()); }
|mpi| { in_out.remove(&mpi); }
);
}
}
impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
type Bit = MovePath<'tcx>;
type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>);
fn name() -> &'static str { "definite_init" }
......@@ -981,20 +989,20 @@ fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit {
}
// sets on_entry bits for Arg lvalues
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) {
for e in &mut sets.on_entry[..] { *e = 0; }
fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>) {
for e in sets.on_entry.words_mut() { *e = 0; }
super::drop_flag_effects_for_function_entry(
ctxt.0, ctxt.1, &ctxt.2,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.set_bit(path.idx());
sets.on_entry.add(&path);
});
}
fn statement_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MovePathIndex>,
bb: repr::BasicBlock,
idx: usize)
{
......@@ -1007,7 +1015,7 @@ fn statement_effect(&self,
fn terminator_effect(&self,
ctxt: &Self::Ctxt,
sets: &mut BlockSets,
sets: &mut BlockSets<MovePathIndex>,
bb: repr::BasicBlock,
statements_len: usize)
{
......@@ -1020,7 +1028,7 @@ fn terminator_effect(&self,
fn propagate_call_return(&self,
ctxt: &Self::Ctxt,
in_out: &mut [usize],
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: repr::BasicBlock,
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
......@@ -1030,7 +1038,7 @@ fn propagate_call_return(&self,
super::on_all_children_bits(
ctxt.0, ctxt.1, &ctxt.2,
move_path_index,
|mpi| { in_out.set_bit(mpi.idx()); }
|mpi| { in_out.add(&mpi); }
);
}
}
......@@ -1106,26 +1114,3 @@ fn bottom_value() -> bool {
}
}
#[inline]
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
}
struct Union;
impl BitwiseOperator for Union {
fn join(&self, a: usize, b: usize) -> usize { a | b }
}
struct Subtract;
impl BitwiseOperator for Subtract {
fn join(&self, a: usize, b: usize) -> usize { a & !b }
}
......@@ -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.
先完成此消息的编辑!
想要评论请 注册