1
Fork 0

rustc_mir: don't pass on_entry when building transfer functions.

This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).

Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.

Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
This commit is contained in:
Dylan MacKenzie 2019-06-12 15:00:43 -07:00
parent d4d5d67c1c
commit c054186ec7
9 changed files with 234 additions and 301 deletions

View file

@ -4,7 +4,7 @@
use rustc::mir::{BasicBlock, Location}; use rustc::mir::{BasicBlock, Location};
use rustc_data_structures::bit_set::{BitIter, BitSet, HybridBitSet}; use rustc_data_structures::bit_set::{BitIter, BitSet, HybridBitSet};
use crate::dataflow::{BitDenotation, BlockSets, DataflowResults}; use crate::dataflow::{BitDenotation, DataflowResults, GenKillSet};
use crate::dataflow::move_paths::{HasMoveData, MovePathIndex}; use crate::dataflow::move_paths::{HasMoveData, MovePathIndex};
use std::iter; use std::iter;
@ -66,8 +66,7 @@ where
{ {
base_results: DataflowResults<'tcx, BD>, base_results: DataflowResults<'tcx, BD>,
curr_state: BitSet<BD::Idx>, curr_state: BitSet<BD::Idx>,
stmt_gen: HybridBitSet<BD::Idx>, stmt_trans: GenKillSet<BD::Idx>,
stmt_kill: HybridBitSet<BD::Idx>,
} }
impl<'tcx, BD> FlowAtLocation<'tcx, BD> impl<'tcx, BD> FlowAtLocation<'tcx, BD>
@ -89,19 +88,17 @@ where
where where
F: FnMut(BD::Idx), F: FnMut(BD::Idx),
{ {
self.stmt_gen.iter().for_each(f) self.stmt_trans.gen_set.iter().for_each(f)
} }
pub fn new(results: DataflowResults<'tcx, BD>) -> Self { pub fn new(results: DataflowResults<'tcx, BD>) -> Self {
let bits_per_block = results.sets().bits_per_block(); let bits_per_block = results.sets().bits_per_block();
let curr_state = BitSet::new_empty(bits_per_block); let curr_state = BitSet::new_empty(bits_per_block);
let stmt_gen = HybridBitSet::new_empty(bits_per_block); let stmt_trans = GenKillSet::from_elem(HybridBitSet::new_empty(bits_per_block));
let stmt_kill = HybridBitSet::new_empty(bits_per_block);
FlowAtLocation { FlowAtLocation {
base_results: results, base_results: results,
curr_state: curr_state, curr_state,
stmt_gen: stmt_gen, stmt_trans,
stmt_kill: stmt_kill,
} }
} }
@ -127,8 +124,7 @@ where
F: FnOnce(BitIter<'_, BD::Idx>), F: FnOnce(BitIter<'_, BD::Idx>),
{ {
let mut curr_state = self.curr_state.clone(); let mut curr_state = self.curr_state.clone();
curr_state.union(&self.stmt_gen); self.stmt_trans.apply(&mut curr_state);
curr_state.subtract(&self.stmt_kill);
f(curr_state.iter()); f(curr_state.iter());
} }
@ -142,68 +138,41 @@ impl<'tcx, BD> FlowsAtLocation for FlowAtLocation<'tcx, BD>
where BD: BitDenotation<'tcx> where BD: BitDenotation<'tcx>
{ {
fn reset_to_entry_of(&mut self, bb: BasicBlock) { fn reset_to_entry_of(&mut self, bb: BasicBlock) {
self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index())); self.curr_state.overwrite(self.base_results.sets().entry_set_for(bb.index()));
} }
fn reset_to_exit_of(&mut self, bb: BasicBlock) { fn reset_to_exit_of(&mut self, bb: BasicBlock) {
self.reset_to_entry_of(bb); self.reset_to_entry_of(bb);
self.curr_state.union(self.base_results.sets().gen_set_for(bb.index())); let trans = self.base_results.sets().trans_for(bb.index());
self.curr_state.subtract(self.base_results.sets().kill_set_for(bb.index())); trans.apply(&mut self.curr_state)
} }
fn reconstruct_statement_effect(&mut self, loc: Location) { fn reconstruct_statement_effect(&mut self, loc: Location) {
self.stmt_gen.clear(); self.stmt_trans.clear();
self.stmt_kill.clear();
{
let mut sets = BlockSets {
on_entry: &mut self.curr_state,
gen_set: &mut self.stmt_gen,
kill_set: &mut self.stmt_kill,
};
self.base_results
.operator()
.before_statement_effect(&mut sets, loc);
}
self.apply_local_effect(loc);
let mut sets = BlockSets {
on_entry: &mut self.curr_state,
gen_set: &mut self.stmt_gen,
kill_set: &mut self.stmt_kill,
};
self.base_results self.base_results
.operator() .operator()
.statement_effect(&mut sets, loc); .before_statement_effect(&mut self.stmt_trans, loc);
self.stmt_trans.apply(&mut self.curr_state);
self.base_results
.operator()
.statement_effect(&mut self.stmt_trans, loc);
} }
fn reconstruct_terminator_effect(&mut self, loc: Location) { fn reconstruct_terminator_effect(&mut self, loc: Location) {
self.stmt_gen.clear(); self.stmt_trans.clear();
self.stmt_kill.clear();
{
let mut sets = BlockSets {
on_entry: &mut self.curr_state,
gen_set: &mut self.stmt_gen,
kill_set: &mut self.stmt_kill,
};
self.base_results
.operator()
.before_terminator_effect(&mut sets, loc);
}
self.apply_local_effect(loc);
let mut sets = BlockSets {
on_entry: &mut self.curr_state,
gen_set: &mut self.stmt_gen,
kill_set: &mut self.stmt_kill,
};
self.base_results self.base_results
.operator() .operator()
.terminator_effect(&mut sets, loc); .before_terminator_effect(&mut self.stmt_trans, loc);
self.stmt_trans.apply(&mut self.curr_state);
self.base_results
.operator()
.terminator_effect(&mut self.stmt_trans, loc);
} }
fn apply_local_effect(&mut self, _loc: Location) { fn apply_local_effect(&mut self, _loc: Location) {
self.curr_state.union(&self.stmt_gen); self.stmt_trans.apply(&mut self.curr_state)
self.curr_state.subtract(&self.stmt_kill);
} }
} }

View file

@ -170,7 +170,7 @@ where MWF: MirWithFlowState<'tcx>,
write!(w, "<tr>")?; write!(w, "<tr>")?;
// Entry // Entry
dump_set_for!(on_entry_set_for, interpret_set); dump_set_for!(entry_set_for, interpret_set);
// MIR statements // MIR statements
write!(w, "<td>")?; write!(w, "<td>")?;
@ -208,7 +208,7 @@ where MWF: MirWithFlowState<'tcx>,
write!(w, "<tr>")?; write!(w, "<tr>")?;
// Entry // Entry
let set = flow.sets.on_entry_set_for(i); let set = flow.sets.entry_set_for(i);
write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?; write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?;
// Terminator // Terminator
@ -221,13 +221,10 @@ where MWF: MirWithFlowState<'tcx>,
} }
write!(w, "</td>")?; write!(w, "</td>")?;
// Gen // Gen/Kill
let set = flow.sets.gen_set_for(i); let trans = flow.sets.trans_for(i);
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?; write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.gen_set)))?;
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.kill_set)))?;
// Kill
let set = flow.sets.kill_set_for(i);
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
write!(w, "</tr>")?; write!(w, "</tr>")?;

View file

@ -2,7 +2,7 @@ pub use super::*;
use rustc::mir::*; use rustc::mir::*;
use rustc::mir::visit::Visitor; use rustc::mir::visit::Visitor;
use crate::dataflow::BitDenotation; use crate::dataflow::{BitDenotation, GenKillSet};
/// This calculates if any part of a MIR local could have previously been borrowed. /// This calculates if any part of a MIR local could have previously been borrowed.
/// This means that once a local has been borrowed, its bit will be set /// This means that once a local has been borrowed, its bit will be set
@ -33,39 +33,39 @@ impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
self.body.local_decls.len() self.body.local_decls.len()
} }
fn start_block_effect(&self, _sets: &mut BitSet<Local>) { fn start_block_effect(&self, _on_entry: &mut BitSet<Local>) {
// Nothing is borrowed on function entry // Nothing is borrowed on function entry
} }
fn statement_effect(&self, fn statement_effect(&self,
sets: &mut BlockSets<'_, Local>, trans: &mut GenKillSet<Local>,
loc: Location) { loc: Location) {
let stmt = &self.body[loc.block].statements[loc.statement_index]; let stmt = &self.body[loc.block].statements[loc.statement_index];
BorrowedLocalsVisitor { BorrowedLocalsVisitor {
sets, trans,
}.visit_statement(stmt, loc); }.visit_statement(stmt, loc);
// StorageDead invalidates all borrows and raw pointers to a local // StorageDead invalidates all borrows and raw pointers to a local
match stmt.kind { match stmt.kind {
StatementKind::StorageDead(l) => sets.kill(l), StatementKind::StorageDead(l) => trans.kill(l),
_ => (), _ => (),
} }
} }
fn terminator_effect(&self, fn terminator_effect(&self,
sets: &mut BlockSets<'_, Local>, trans: &mut GenKillSet<Local>,
loc: Location) { loc: Location) {
let terminator = self.body[loc.block].terminator(); let terminator = self.body[loc.block].terminator();
BorrowedLocalsVisitor { BorrowedLocalsVisitor {
sets, trans,
}.visit_terminator(terminator, loc); }.visit_terminator(terminator, loc);
match &terminator.kind { match &terminator.kind {
// Drop terminators borrows the location // Drop terminators borrows the location
TerminatorKind::Drop { location, .. } | TerminatorKind::Drop { location, .. } |
TerminatorKind::DropAndReplace { location, .. } => { TerminatorKind::DropAndReplace { location, .. } => {
if let Some(local) = find_local(location) { if let Some(local) = find_local(location) {
sets.gen(local); trans.gen(local);
} }
} }
_ => (), _ => (),
@ -97,8 +97,8 @@ impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
} }
} }
struct BorrowedLocalsVisitor<'b, 'c> { struct BorrowedLocalsVisitor<'gk> {
sets: &'b mut BlockSets<'c, Local>, trans: &'gk mut GenKillSet<Local>,
} }
fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> { fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
@ -117,13 +117,13 @@ fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
}) })
} }
impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> { impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> {
fn visit_rvalue(&mut self, fn visit_rvalue(&mut self,
rvalue: &Rvalue<'tcx>, rvalue: &Rvalue<'tcx>,
location: Location) { location: Location) {
if let Rvalue::Ref(_, _, ref place) = *rvalue { if let Rvalue::Ref(_, _, ref place) = *rvalue {
if let Some(local) = find_local(place) { if let Some(local) = find_local(place) {
self.sets.gen(local); self.trans.gen(local);
} }
} }

View file

@ -9,7 +9,7 @@ use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use crate::dataflow::{BitDenotation, BlockSets, InitialFlow}; use crate::dataflow::{BitDenotation, InitialFlow, GenKillSet};
use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::region_infer::RegionInferenceContext;
use crate::borrow_check::nll::ToRegionVid; use crate::borrow_check::nll::ToRegionVid;
use crate::borrow_check::places_conflict; use crate::borrow_check::places_conflict;
@ -168,7 +168,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
/// Add all borrows to the kill set, if those borrows are out of scope at `location`. /// Add all borrows to the kill set, if those borrows are out of scope at `location`.
/// That means they went out of a nonlexical scope /// That means they went out of a nonlexical scope
fn kill_loans_out_of_scope_at_location(&self, fn kill_loans_out_of_scope_at_location(&self,
sets: &mut BlockSets<'_, BorrowIndex>, trans: &mut GenKillSet<BorrowIndex>,
location: Location) { location: Location) {
// NOTE: The state associated with a given `location` // NOTE: The state associated with a given `location`
// reflects the dataflow on entry to the statement. // reflects the dataflow on entry to the statement.
@ -182,14 +182,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
// region, then setting that gen-bit will override any // region, then setting that gen-bit will override any
// potential kill introduced here. // potential kill introduced here.
if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
sets.kill_all(indices); trans.kill_all(indices);
} }
} }
/// Kill any borrows that conflict with `place`. /// Kill any borrows that conflict with `place`.
fn kill_borrows_on_place( fn kill_borrows_on_place(
&self, &self,
sets: &mut BlockSets<'_, BorrowIndex>, trans: &mut GenKillSet<BorrowIndex>,
place: &Place<'tcx> place: &Place<'tcx>
) { ) {
debug!("kill_borrows_on_place: place={:?}", place); debug!("kill_borrows_on_place: place={:?}", place);
@ -206,7 +206,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
// local must conflict. This is purely an optimization so we don't have to call // local must conflict. This is purely an optimization so we don't have to call
// `places_conflict` for every borrow. // `places_conflict` for every borrow.
if let Place::Base(PlaceBase::Local(_)) = place { if let Place::Base(PlaceBase::Local(_)) = place {
sets.kill_all(other_borrows_of_local); trans.kill_all(other_borrows_of_local);
return; return;
} }
@ -224,7 +224,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
places_conflict::PlaceConflictBias::NoOverlap) places_conflict::PlaceConflictBias::NoOverlap)
}); });
sets.kill_all(definitely_conflicting_borrows); trans.kill_all(definitely_conflicting_borrows);
} }
} }
} }
@ -236,21 +236,24 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
self.borrow_set.borrows.len() * 2 self.borrow_set.borrows.len() * 2
} }
fn start_block_effect(&self, _entry_set: &mut BitSet<BorrowIndex>) { fn start_block_effect(&self, _entry_set: &mut BitSet<Self::Idx>) {
// no borrows of code region_scopes have been taken prior to // no borrows of code region_scopes have been taken prior to
// function execution, so this method has no effect on // function execution, so this method has no effect.
// `_sets`.
} }
fn before_statement_effect(&self, fn before_statement_effect(&self,
sets: &mut BlockSets<'_, BorrowIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) { location: Location) {
debug!("Borrows::before_statement_effect sets: {:?} location: {:?}", sets, location); debug!("Borrows::before_statement_effect trans: {:?} location: {:?}",
self.kill_loans_out_of_scope_at_location(sets, location); trans, location);
self.kill_loans_out_of_scope_at_location(trans, location);
} }
fn statement_effect(&self, sets: &mut BlockSets<'_, BorrowIndex>, location: Location) { fn statement_effect(&self,
debug!("Borrows::statement_effect: sets={:?} location={:?}", sets, location); trans: &mut GenKillSet<Self::Idx>,
location: Location) {
debug!("Borrows::statement_effect: trans={:?} location={:?}",
trans, location);
let block = &self.body.basic_blocks().get(location.block).unwrap_or_else(|| { let block = &self.body.basic_blocks().get(location.block).unwrap_or_else(|| {
panic!("could not find block at location {:?}", location); panic!("could not find block at location {:?}", location);
@ -264,7 +267,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
mir::StatementKind::Assign(ref lhs, ref rhs) => { mir::StatementKind::Assign(ref lhs, ref rhs) => {
// Make sure there are no remaining borrows for variables // Make sure there are no remaining borrows for variables
// that are assigned over. // that are assigned over.
self.kill_borrows_on_place(sets, lhs); self.kill_borrows_on_place(trans, lhs);
if let mir::Rvalue::Ref(_, _, ref place) = **rhs { if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
if place.ignore_borrow( if place.ignore_borrow(
@ -278,20 +281,20 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
panic!("could not find BorrowIndex for location {:?}", location); panic!("could not find BorrowIndex for location {:?}", location);
}); });
sets.gen(*index); trans.gen(*index);
} }
} }
mir::StatementKind::StorageDead(local) => { mir::StatementKind::StorageDead(local) => {
// Make sure there are no remaining borrows for locals that // Make sure there are no remaining borrows for locals that
// are gone out of scope. // are gone out of scope.
self.kill_borrows_on_place(sets, &Place::Base(PlaceBase::Local(local))); self.kill_borrows_on_place(trans, &Place::Base(PlaceBase::Local(local)));
} }
mir::StatementKind::InlineAsm(ref asm) => { mir::StatementKind::InlineAsm(ref asm) => {
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
if !kind.is_indirect && !kind.is_rw { if !kind.is_indirect && !kind.is_rw {
self.kill_borrows_on_place(sets, output); self.kill_borrows_on_place(trans, output);
} }
} }
} }
@ -307,13 +310,16 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
} }
fn before_terminator_effect(&self, fn before_terminator_effect(&self,
sets: &mut BlockSets<'_, BorrowIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) { location: Location) {
debug!("Borrows::before_terminator_effect sets: {:?} location: {:?}", sets, location); debug!("Borrows::before_terminator_effect: trans={:?} location={:?}",
self.kill_loans_out_of_scope_at_location(sets, location); trans, location);
self.kill_loans_out_of_scope_at_location(trans, location);
} }
fn terminator_effect(&self, _: &mut BlockSets<'_, BorrowIndex>, _: Location) {} fn terminator_effect(&self,
_: &mut GenKillSet<Self::Idx>,
_: Location) {}
fn propagate_call_return( fn propagate_call_return(
&self, &self,

View file

@ -12,7 +12,7 @@ use super::MoveDataParamEnv;
use crate::util::elaborate_drops::DropFlagState; use crate::util::elaborate_drops::DropFlagState;
use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex, InitKind}; use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex, InitKind};
use super::{BitDenotation, BlockSets, InitialFlow}; use super::{BitDenotation, InitialFlow, GenKillSet};
use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_function_entry;
use super::drop_flag_effects_for_location; use super::drop_flag_effects_for_location;
@ -226,34 +226,37 @@ impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> {
} }
impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
fn update_bits(sets: &mut BlockSets<'_, MovePathIndex>, path: MovePathIndex, fn update_bits(trans: &mut GenKillSet<MovePathIndex>,
path: MovePathIndex,
state: DropFlagState) state: DropFlagState)
{ {
match state { match state {
DropFlagState::Absent => sets.kill(path), DropFlagState::Absent => trans.kill(path),
DropFlagState::Present => sets.gen(path), DropFlagState::Present => trans.gen(path),
} }
} }
} }
impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
fn update_bits(sets: &mut BlockSets<'_, MovePathIndex>, path: MovePathIndex, fn update_bits(trans: &mut GenKillSet<MovePathIndex>,
path: MovePathIndex,
state: DropFlagState) state: DropFlagState)
{ {
match state { match state {
DropFlagState::Absent => sets.gen(path), DropFlagState::Absent => trans.gen(path),
DropFlagState::Present => sets.kill(path), DropFlagState::Present => trans.kill(path),
} }
} }
} }
impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
fn update_bits(sets: &mut BlockSets<'_, MovePathIndex>, path: MovePathIndex, fn update_bits(trans: &mut GenKillSet<MovePathIndex>,
path: MovePathIndex,
state: DropFlagState) state: DropFlagState)
{ {
match state { match state {
DropFlagState::Absent => sets.kill(path), DropFlagState::Absent => trans.kill(path),
DropFlagState::Present => sets.gen(path), DropFlagState::Present => trans.gen(path),
} }
} }
} }
@ -275,24 +278,24 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
} }
fn statement_effect(&self, fn statement_effect(&self,
sets: &mut BlockSets<'_, MovePathIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) location: Location)
{ {
drop_flag_effects_for_location( drop_flag_effects_for_location(
self.tcx, self.body, self.mdpe, self.tcx, self.body, self.mdpe,
location, location,
|path, s| Self::update_bits(sets, path, s) |path, s| Self::update_bits(trans, path, s)
) )
} }
fn terminator_effect(&self, fn terminator_effect(&self,
sets: &mut BlockSets<'_, MovePathIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) location: Location)
{ {
drop_flag_effects_for_location( drop_flag_effects_for_location(
self.tcx, self.body, self.mdpe, self.tcx, self.body, self.mdpe,
location, location,
|path, s| Self::update_bits(sets, path, s) |path, s| Self::update_bits(trans, path, s)
) )
} }
@ -333,24 +336,24 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> {
} }
fn statement_effect(&self, fn statement_effect(&self,
sets: &mut BlockSets<'_, MovePathIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) location: Location)
{ {
drop_flag_effects_for_location( drop_flag_effects_for_location(
self.tcx, self.body, self.mdpe, self.tcx, self.body, self.mdpe,
location, location,
|path, s| Self::update_bits(sets, path, s) |path, s| Self::update_bits(trans, path, s)
) )
} }
fn terminator_effect(&self, fn terminator_effect(&self,
sets: &mut BlockSets<'_, MovePathIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) location: Location)
{ {
drop_flag_effects_for_location( drop_flag_effects_for_location(
self.tcx, self.body, self.mdpe, self.tcx, self.body, self.mdpe,
location, location,
|path, s| Self::update_bits(sets, path, s) |path, s| Self::update_bits(trans, path, s)
) )
} }
@ -389,24 +392,24 @@ impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
} }
fn statement_effect(&self, fn statement_effect(&self,
sets: &mut BlockSets<'_, MovePathIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) location: Location)
{ {
drop_flag_effects_for_location( drop_flag_effects_for_location(
self.tcx, self.body, self.mdpe, self.tcx, self.body, self.mdpe,
location, location,
|path, s| Self::update_bits(sets, path, s) |path, s| Self::update_bits(trans, path, s)
) )
} }
fn terminator_effect(&self, fn terminator_effect(&self,
sets: &mut BlockSets<'_, MovePathIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) location: Location)
{ {
drop_flag_effects_for_location( drop_flag_effects_for_location(
self.tcx, self.body, self.mdpe, self.tcx, self.body, self.mdpe,
location, location,
|path, s| Self::update_bits(sets, path, s) |path, s| Self::update_bits(trans, path, s)
) )
} }
@ -439,7 +442,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
} }
fn statement_effect(&self, fn statement_effect(&self,
sets: &mut BlockSets<'_, InitIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) { location: Location) {
let (_, body, move_data) = (self.tcx, self.body, self.move_data()); let (_, body, move_data) = (self.tcx, self.body, self.move_data());
let stmt = &body[location.block].statements[location.statement_index]; let stmt = &body[location.block].statements[location.statement_index];
@ -449,7 +452,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
debug!("statement {:?} at loc {:?} initializes move_indexes {:?}", debug!("statement {:?} at loc {:?} initializes move_indexes {:?}",
stmt, location, &init_loc_map[location]); stmt, location, &init_loc_map[location]);
sets.gen_all(&init_loc_map[location]); trans.gen_all(&init_loc_map[location]);
match stmt.kind { match stmt.kind {
mir::StatementKind::StorageDead(local) => { mir::StatementKind::StorageDead(local) => {
@ -458,14 +461,14 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
let move_path_index = rev_lookup.find_local(local); let move_path_index = rev_lookup.find_local(local);
debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}", debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}",
stmt, location, &init_path_map[move_path_index]); stmt, location, &init_path_map[move_path_index]);
sets.kill_all(&init_path_map[move_path_index]); trans.kill_all(&init_path_map[move_path_index]);
} }
_ => {} _ => {}
} }
} }
fn terminator_effect(&self, fn terminator_effect(&self,
sets: &mut BlockSets<'_, InitIndex>, trans: &mut GenKillSet<Self::Idx>,
location: Location) location: Location)
{ {
let (body, move_data) = (self.body, self.move_data()); let (body, move_data) = (self.body, self.move_data());
@ -473,7 +476,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
let init_loc_map = &move_data.init_loc_map; let init_loc_map = &move_data.init_loc_map;
debug!("terminator {:?} at loc {:?} initializes move_indexes {:?}", debug!("terminator {:?} at loc {:?} initializes move_indexes {:?}",
term, location, &init_loc_map[location]); term, location, &init_loc_map[location]);
sets.gen_all( trans.gen_all(
init_loc_map[location].iter().filter(|init_index| { init_loc_map[location].iter().filter(|init_index| {
move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly
}) })

View file

@ -26,24 +26,24 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
self.body.local_decls.len() self.body.local_decls.len()
} }
fn start_block_effect(&self, _sets: &mut BitSet<Local>) { fn start_block_effect(&self, _on_entry: &mut BitSet<Local>) {
// Nothing is live on function entry // Nothing is live on function entry
} }
fn statement_effect(&self, fn statement_effect(&self,
sets: &mut BlockSets<'_, Local>, trans: &mut GenKillSet<Local>,
loc: Location) { loc: Location) {
let stmt = &self.body[loc.block].statements[loc.statement_index]; let stmt = &self.body[loc.block].statements[loc.statement_index];
match stmt.kind { match stmt.kind {
StatementKind::StorageLive(l) => sets.gen(l), StatementKind::StorageLive(l) => trans.gen(l),
StatementKind::StorageDead(l) => sets.kill(l), StatementKind::StorageDead(l) => trans.kill(l),
_ => (), _ => (),
} }
} }
fn terminator_effect(&self, fn terminator_effect(&self,
_sets: &mut BlockSets<'_, Local>, _trans: &mut GenKillSet<Local>,
_loc: Location) { _loc: Location) {
// Terminators have no effect // Terminators have no effect
} }

View file

@ -131,7 +131,7 @@ pub(crate) fn do_dataflow<'a, 'tcx, BD, P>(
p: P, p: P,
) -> DataflowResults<'tcx, BD> ) -> DataflowResults<'tcx, BD>
where where
BD: BitDenotation<'tcx> + InitialFlow, BD: BitDenotation<'tcx>,
P: Fn(&BD, BD::Idx) -> DebugFormatted, P: Fn(&BD, BD::Idx) -> DebugFormatted,
{ {
let flow_state = DataflowAnalysis::new(body, dead_unwinds, bd); let flow_state = DataflowAnalysis::new(body, dead_unwinds, bd);
@ -199,42 +199,27 @@ where
} }
fn build_sets(&mut self) { fn build_sets(&mut self) {
// First we need to build the entry-, gen- and kill-sets. // Build the transfer function for each block.
{
let sets = &mut self.flow_state.sets.for_block(mir::START_BLOCK.index());
self.flow_state.operator.start_block_effect(&mut sets.on_entry);
}
for (bb, data) in self.body.basic_blocks().iter_enumerated() { for (bb, data) in self.body.basic_blocks().iter_enumerated() {
let &mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = data; let &mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = data;
let mut interim_state; let trans = self.flow_state.sets.trans_mut_for(bb.index());
let sets = &mut self.flow_state.sets.for_block(bb.index());
let track_intrablock = BD::accumulates_intrablock_state();
if track_intrablock {
debug!("swapping in mutable on_entry, initially {:?}", sets.on_entry);
interim_state = sets.on_entry.to_owned();
sets.on_entry = &mut interim_state;
}
for j_stmt in 0..statements.len() { for j_stmt in 0..statements.len() {
let location = Location { block: bb, statement_index: j_stmt }; let location = Location { block: bb, statement_index: j_stmt };
self.flow_state.operator.before_statement_effect(sets, location); self.flow_state.operator.before_statement_effect(trans, location);
self.flow_state.operator.statement_effect(sets, location); self.flow_state.operator.statement_effect(trans, location);
if track_intrablock {
sets.apply_local_effect();
}
} }
if terminator.is_some() { if terminator.is_some() {
let location = Location { block: bb, statement_index: statements.len() }; let location = Location { block: bb, statement_index: statements.len() };
self.flow_state.operator.before_terminator_effect(sets, location); self.flow_state.operator.before_terminator_effect(trans, location);
self.flow_state.operator.terminator_effect(sets, location); self.flow_state.operator.terminator_effect(trans, location);
if track_intrablock {
sets.apply_local_effect();
}
} }
} }
// Initialize the flow state at entry to the start block.
let on_entry = self.flow_state.sets.entry_set_mut_for(mir::START_BLOCK.index());
self.flow_state.operator.start_block_effect(on_entry);
} }
} }
@ -247,14 +232,12 @@ where
WorkQueue::with_all(self.builder.body.basic_blocks().len()); WorkQueue::with_all(self.builder.body.basic_blocks().len());
let body = self.builder.body; let body = self.builder.body;
while let Some(bb) = dirty_queue.pop() { while let Some(bb) = dirty_queue.pop() {
let (on_entry, trans) = self.builder.flow_state.sets.get_mut(bb.index());
debug_assert!(in_out.words().len() == on_entry.words().len());
in_out.overwrite(on_entry);
trans.apply(in_out);
let bb_data = &body[bb]; let bb_data = &body[bb];
{
let sets = self.builder.flow_state.sets.for_block(bb.index());
debug_assert!(in_out.words().len() == sets.on_entry.words().len());
in_out.overwrite(sets.on_entry);
in_out.union(sets.gen_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);
} }
@ -366,33 +349,27 @@ pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location,
result: &DataflowResults<'tcx, T>, result: &DataflowResults<'tcx, T>,
body: &Body<'tcx>) body: &Body<'tcx>)
-> BitSet<T::Idx> { -> BitSet<T::Idx> {
let mut on_entry = result.sets().on_entry_set_for(loc.block.index()).to_owned(); let mut trans = GenKill::from_elem(HybridBitSet::new_empty(analysis.bits_per_block()));
let mut kill_set = on_entry.to_hybrid();
let mut gen_set = kill_set.clone();
{ for stmt in 0..loc.statement_index {
let mut sets = BlockSets { let mut stmt_loc = loc;
on_entry: &mut on_entry, stmt_loc.statement_index = stmt;
kill_set: &mut kill_set, analysis.before_statement_effect(&mut trans, stmt_loc);
gen_set: &mut gen_set, analysis.statement_effect(&mut trans, stmt_loc);
};
for stmt in 0..loc.statement_index {
let mut stmt_loc = loc;
stmt_loc.statement_index = stmt;
analysis.before_statement_effect(&mut sets, stmt_loc);
analysis.statement_effect(&mut sets, stmt_loc);
}
// Apply the pre-statement effect of the statement we're evaluating.
if loc.statement_index == body[loc.block].statements.len() {
analysis.before_terminator_effect(&mut sets, loc);
} else {
analysis.before_statement_effect(&mut sets, loc);
}
} }
gen_set.to_dense() // Apply the pre-statement effect of the statement we're evaluating.
if loc.statement_index == body[loc.block].statements.len() {
analysis.before_terminator_effect(&mut trans, loc);
} else {
analysis.before_statement_effect(&mut trans, loc);
}
// Apply the transfer function for all preceding statements to the fixpoint
// at the start of the block.
let mut state = result.sets().entry_set_for(loc.block.index()).to_owned();
trans.apply(&mut state);
state
} }
pub struct DataflowAnalysis<'a, 'tcx, O> pub struct DataflowAnalysis<'a, 'tcx, O>
@ -462,36 +439,8 @@ impl<'tcx, O: BitDenotation<'tcx>> DataflowState<'tcx, O> {
} }
} }
#[derive(Debug)] /// A 2-tuple representing the "gen" and "kill" bitsets during
pub struct AllSets<E: Idx> { /// dataflow analysis.
/// Analysis bitwidth for each block.
bits_per_block: usize,
/// For each block, bits valid on entry to the block.
on_entry_sets: Vec<BitSet<E>>,
/// For each block, bits generated by executing the statements +
/// terminator in the block -- with one caveat. In particular, for
/// *call terminators*, the effect of storing the destination is
/// not included, since that only takes effect on the **success**
/// edge (and not the unwind edge).
gen_sets: Vec<HybridBitSet<E>>,
/// For each block, bits killed by executing the statements +
/// terminator in the block -- with one caveat. In particular, for
/// *call terminators*, the effect of storing the destination is
/// not included, since that only takes effect on the **success**
/// edge (and not the unwind edge).
kill_sets: Vec<HybridBitSet<E>>,
}
/// Triple of sets associated with a given block.
///
/// Generally, one sets up `on_entry`, `gen_set`, and `kill_set` for
/// each block individually, and then runs the dataflow analysis which
/// iteratively modifies the various `on_entry` sets (but leaves the
/// other two sets unchanged, since they represent the effect of the
/// block, which should be invariant over the course of the analysis).
/// ///
/// It is best to ensure that the intersection of `gen_set` and /// It is best to ensure that the intersection of `gen_set` and
/// `kill_set` is empty; otherwise the results of the dataflow will /// `kill_set` is empty; otherwise the results of the dataflow will
@ -499,21 +448,32 @@ pub struct AllSets<E: Idx> {
/// killed during the iteration. (This is such a good idea that the /// killed during the iteration. (This is such a good idea that the
/// `fn gen` and `fn kill` methods that set their state enforce this /// `fn gen` and `fn kill` methods that set their state enforce this
/// for you.) /// for you.)
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
pub struct BlockSets<'a, E: Idx> { pub struct GenKill<T> {
/// Dataflow state immediately before control flow enters the given block. pub(crate) gen_set: T,
pub(crate) on_entry: &'a mut BitSet<E>, pub(crate) kill_set: T,
/// Bits that are set to 1 by the time we exit the given block. Hybrid
/// because it usually contains only 0 or 1 elements.
pub(crate) gen_set: &'a mut HybridBitSet<E>,
/// Bits that are set to 0 by the time we exit the given block. Hybrid
/// because it usually contains only 0 or 1 elements.
pub(crate) kill_set: &'a mut HybridBitSet<E>,
} }
impl<'a, E:Idx> BlockSets<'a, E> { type GenKillSet<T> = GenKill<HybridBitSet<T>>;
impl<T> GenKill<T> {
/// Creates a new tuple where `gen_set == kill_set == elem`.
pub(crate) fn from_elem(elem: T) -> Self
where T: Clone
{
GenKill {
gen_set: elem.clone(),
kill_set: elem,
}
}
}
impl<E:Idx> GenKillSet<E> {
pub(crate) fn clear(&mut self) {
self.gen_set.clear();
self.kill_set.clear();
}
fn gen(&mut self, e: E) { fn gen(&mut self, e: E) {
self.gen_set.insert(e); self.gen_set.insert(e);
self.kill_set.remove(e); self.kill_set.remove(e);
@ -541,30 +501,53 @@ impl<'a, E:Idx> BlockSets<'a, E> {
} }
} }
fn apply_local_effect(&mut self) { /// Computes `(set gen) - kill` and assigns the result to `set`.
self.on_entry.union(self.gen_set); pub(crate) fn apply(&self, set: &mut BitSet<E>) {
self.on_entry.subtract(self.kill_set); set.union(&self.gen_set);
set.subtract(&self.kill_set);
} }
} }
#[derive(Debug)]
pub struct AllSets<E: Idx> {
/// Analysis bitwidth for each block.
bits_per_block: usize,
/// For each block, bits valid on entry to the block.
on_entry: Vec<BitSet<E>>,
/// The transfer function of each block expressed as the set of bits
/// generated and killed by executing the statements + terminator in the
/// block -- with one caveat. In particular, for *call terminators*, the
/// effect of storing the destination is not included, since that only takes
/// effect on the **success** edge (and not the unwind edge).
trans: Vec<GenKillSet<E>>,
}
impl<E:Idx> AllSets<E> { impl<E:Idx> AllSets<E> {
pub fn bits_per_block(&self) -> usize { self.bits_per_block } pub fn bits_per_block(&self) -> usize { self.bits_per_block }
pub fn for_block(&mut self, block_idx: usize) -> BlockSets<'_, E> {
BlockSets { pub fn get_mut(&mut self, block_idx: usize) -> (&mut BitSet<E>, &mut GenKillSet<E>) {
on_entry: &mut self.on_entry_sets[block_idx], (&mut self.on_entry[block_idx], &mut self.trans[block_idx])
gen_set: &mut self.gen_sets[block_idx],
kill_set: &mut self.kill_sets[block_idx],
}
} }
pub fn on_entry_set_for(&self, block_idx: usize) -> &BitSet<E> { pub fn trans_for(&self, block_idx: usize) -> &GenKillSet<E> {
&self.on_entry_sets[block_idx] &self.trans[block_idx]
}
pub fn trans_mut_for(&mut self, block_idx: usize) -> &mut GenKillSet<E> {
&mut self.trans[block_idx]
}
pub fn entry_set_for(&self, block_idx: usize) -> &BitSet<E> {
&self.on_entry[block_idx]
}
pub fn entry_set_mut_for(&mut self, block_idx: usize) -> &mut BitSet<E> {
&mut self.on_entry[block_idx]
} }
pub fn gen_set_for(&self, block_idx: usize) -> &HybridBitSet<E> { pub fn gen_set_for(&self, block_idx: usize) -> &HybridBitSet<E> {
&self.gen_sets[block_idx] &self.trans_for(block_idx).gen_set
} }
pub fn kill_set_for(&self, block_idx: usize) -> &HybridBitSet<E> { pub fn kill_set_for(&self, block_idx: usize) -> &HybridBitSet<E> {
&self.kill_sets[block_idx] &self.trans_for(block_idx).kill_set
} }
} }
@ -579,35 +562,18 @@ pub trait InitialFlow {
fn bottom_value() -> bool; fn bottom_value() -> bool;
} }
pub trait BitDenotation<'tcx>: BitSetOperator { /// A specific flavor of dataflow analysis.
///
/// To run a dataflow analysis, one sets up an initial state for the
/// `START_BLOCK` via `start_block_effect` and a transfer function (`trans`)
/// for each block individually. The entry set for all other basic blocks is
/// initialized to `InitialFlow::bottom_value`. The dataflow analysis then
/// iteratively modifies the various entry sets (but leaves the the transfer
/// function unchanged).
pub trait BitDenotation<'tcx>: BitSetOperator + InitialFlow {
/// Specifies what index type is used to access the bitvector. /// Specifies what index type is used to access the bitvector.
type Idx: Idx; type Idx: Idx;
/// Some analyses want to accumulate knowledge within a block when
/// analyzing its statements for building the gen/kill sets. Override
/// this method to return true in such cases.
///
/// When this returns true, the statement-effect (re)construction
/// will clone the `on_entry` state and pass along a reference via
/// `sets.on_entry` to that local clone into `statement_effect` and
/// `terminator_effect`).
///
/// When it's false, no local clone is constructed; instead a
/// reference directly into `on_entry` is passed along via
/// `sets.on_entry` instead, which represents the flow state at
/// the block's start, not necessarily the state immediately prior
/// to the statement/terminator under analysis.
///
/// In either case, the passed reference is mutable, but this is a
/// wart from using the `BlockSets` type in the API; the intention
/// is that the `statement_effect` and `terminator_effect` methods
/// mutate only the gen/kill sets.
//
// FIXME: we should consider enforcing the intention described in
// the previous paragraph by passing the three sets in separate
// parameters to encode their distinct mutabilities.
fn accumulates_intrablock_state() -> bool { false }
/// A name describing the dataflow analysis that this /// A name describing the dataflow analysis that this
/// `BitDenotation` is supporting. The name should be something /// `BitDenotation` is supporting. The name should be something
/// suitable for plugging in as part of a filename (i.e., avoid /// suitable for plugging in as part of a filename (i.e., avoid
@ -640,7 +606,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator {
/// applied, in that order, before moving for the next /// applied, in that order, before moving for the next
/// statement. /// statement.
fn before_statement_effect(&self, fn before_statement_effect(&self,
_sets: &mut BlockSets<'_, Self::Idx>, _trans: &mut GenKillSet<Self::Idx>,
_location: Location) {} _location: Location) {}
/// Mutates the block-sets (the flow sets for the given /// Mutates the block-sets (the flow sets for the given
@ -654,7 +620,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator {
/// `bb_data` is the sequence of statements identified by `bb` in /// `bb_data` is the sequence of statements identified by `bb` in
/// the MIR. /// the MIR.
fn statement_effect(&self, fn statement_effect(&self,
sets: &mut BlockSets<'_, Self::Idx>, trans: &mut GenKillSet<Self::Idx>,
location: Location); location: Location);
/// Similar to `terminator_effect`, except it applies /// Similar to `terminator_effect`, except it applies
@ -669,7 +635,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator {
/// applied, in that order, before moving for the next /// applied, in that order, before moving for the next
/// terminator. /// terminator.
fn before_terminator_effect(&self, fn before_terminator_effect(&self,
_sets: &mut BlockSets<'_, Self::Idx>, _trans: &mut GenKillSet<Self::Idx>,
_location: Location) {} _location: Location) {}
/// Mutates the block-sets (the flow sets for the given /// Mutates the block-sets (the flow sets for the given
@ -683,7 +649,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator {
/// The effects applied here cannot depend on which branch the /// The effects applied here cannot depend on which branch the
/// terminator took. /// terminator took.
fn terminator_effect(&self, fn terminator_effect(&self,
sets: &mut BlockSets<'_, Self::Idx>, trans: &mut GenKillSet<Self::Idx>,
location: Location); location: Location);
/// Mutates the block-sets according to the (flow-dependent) /// Mutates the block-sets according to the (flow-dependent)
@ -718,17 +684,16 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx>
{ {
pub fn new(body: &'a Body<'tcx>, pub fn new(body: &'a Body<'tcx>,
dead_unwinds: &'a BitSet<mir::BasicBlock>, dead_unwinds: &'a BitSet<mir::BasicBlock>,
denotation: D) -> Self where D: InitialFlow { denotation: D) -> Self {
let bits_per_block = denotation.bits_per_block(); let bits_per_block = denotation.bits_per_block();
let num_blocks = body.basic_blocks().len(); let num_blocks = body.basic_blocks().len();
let on_entry_sets = if D::bottom_value() { let on_entry = if D::bottom_value() {
vec![BitSet::new_filled(bits_per_block); num_blocks] vec![BitSet::new_filled(bits_per_block); num_blocks]
} else { } else {
vec![BitSet::new_empty(bits_per_block); num_blocks] vec![BitSet::new_empty(bits_per_block); num_blocks]
}; };
let gen_sets = vec![HybridBitSet::new_empty(bits_per_block); num_blocks]; let nop = GenKill::from_elem(HybridBitSet::new_empty(bits_per_block));
let kill_sets = gen_sets.clone();
DataflowAnalysis { DataflowAnalysis {
body, body,
@ -736,9 +701,8 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx>
flow_state: DataflowState { flow_state: DataflowState {
sets: AllSets { sets: AllSets {
bits_per_block, bits_per_block,
on_entry_sets, on_entry,
gen_sets, trans: vec![nop; num_blocks],
kill_sets,
}, },
operator: denotation, operator: denotation,
} }
@ -836,7 +800,7 @@ where
in_out: &BitSet<D::Idx>, in_out: &BitSet<D::Idx>,
bb: mir::BasicBlock, bb: mir::BasicBlock,
dirty_queue: &mut WorkQueue<mir::BasicBlock>) { dirty_queue: &mut WorkQueue<mir::BasicBlock>) {
let entry_set = &mut self.flow_state.sets.for_block(bb.index()).on_entry; let entry_set = self.flow_state.sets.entry_set_mut_for(bb.index());
let set_changed = self.flow_state.operator.join(entry_set, &in_out); let set_changed = self.flow_state.operator.join(entry_set, &in_out);
if set_changed { if set_changed {
dirty_queue.insert(bb); dirty_queue.insert(bb);

View file

@ -95,7 +95,7 @@ fn find_dead_unwinds<'tcx>(
}; };
let mut init_data = InitializationData { let mut init_data = InitializationData {
live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), live: flow_inits.sets().entry_set_for(bb.index()).to_owned(),
dead: BitSet::new_empty(env.move_data.move_paths.len()), dead: BitSet::new_empty(env.move_data.move_paths.len()),
}; };
debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}",
@ -304,9 +304,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn initialization_data_at(&self, loc: Location) -> InitializationData { fn initialization_data_at(&self, loc: Location) -> InitializationData {
let mut data = InitializationData { let mut data = InitializationData {
live: self.flow_inits.sets().on_entry_set_for(loc.block.index()) live: self.flow_inits.sets().entry_set_for(loc.block.index())
.to_owned(), .to_owned(),
dead: self.flow_uninits.sets().on_entry_set_for(loc.block.index()) dead: self.flow_uninits.sets().entry_set_for(loc.block.index())
.to_owned(), .to_owned(),
}; };
for stmt in 0..loc.statement_index { for stmt in 0..loc.statement_index {

View file

@ -18,7 +18,6 @@ use crate::dataflow::{
}; };
use crate::dataflow::move_paths::{MovePathIndex, LookupResult}; use crate::dataflow::move_paths::{MovePathIndex, LookupResult};
use crate::dataflow::move_paths::{HasMoveData, MoveData}; use crate::dataflow::move_paths::{HasMoveData, MoveData};
use crate::dataflow;
use crate::dataflow::has_rustc_mir_with; use crate::dataflow::has_rustc_mir_with;
@ -133,9 +132,8 @@ fn each_block<'tcx, O>(
} }
}; };
let mut on_entry = results.0.sets.on_entry_set_for(bb.index()).to_owned(); let mut on_entry = results.0.sets.entry_set_for(bb.index()).to_owned();
let mut gen_set = results.0.sets.gen_set_for(bb.index()).clone(); let mut trans = results.0.sets.trans_for(bb.index()).clone();
let mut kill_set = results.0.sets.kill_set_for(bb.index()).clone();
// Emulate effect of all statements in the block up to (but not // Emulate effect of all statements in the block up to (but not
// including) the borrow within `peek_arg_place`. Do *not* include // including) the borrow within `peek_arg_place`. Do *not* include
@ -143,10 +141,6 @@ fn each_block<'tcx, O>(
// of the argument at time immediate preceding Call to // of the argument at time immediate preceding Call to
// `rustc_peek`). // `rustc_peek`).
let mut sets = dataflow::BlockSets { on_entry: &mut on_entry,
gen_set: &mut gen_set,
kill_set: &mut kill_set };
for (j, stmt) in statements.iter().enumerate() { for (j, stmt) in statements.iter().enumerate() {
debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
let (place, rvalue) = match stmt.kind { let (place, rvalue) = match stmt.kind {
@ -170,7 +164,7 @@ fn each_block<'tcx, O>(
// Okay, our search is over. // Okay, our search is over.
match move_data.rev_lookup.find(peeking_at_place) { match move_data.rev_lookup.find(peeking_at_place) {
LookupResult::Exact(peek_mpi) => { LookupResult::Exact(peek_mpi) => {
let bit_state = sets.on_entry.contains(peek_mpi); let bit_state = on_entry.contains(peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}", debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
place, peeking_at_place, bit_state); place, peeking_at_place, bit_state);
if !bit_state { if !bit_state {
@ -197,18 +191,18 @@ fn each_block<'tcx, O>(
debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}", debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}",
place, lhs_mpi, stmt); place, lhs_mpi, stmt);
// reset GEN and KILL sets before emulating their effect. // reset GEN and KILL sets before emulating their effect.
sets.gen_set.clear(); trans.clear();
sets.kill_set.clear();
results.0.operator.before_statement_effect( results.0.operator.before_statement_effect(
&mut sets, Location { block: bb, statement_index: j }); &mut trans,
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 trans,
sets.on_entry.union(sets.gen_set); Location { block: bb, statement_index: j });
sets.on_entry.subtract(sets.kill_set); trans.apply(&mut on_entry);
} }
results.0.operator.before_terminator_effect( results.0.operator.before_terminator_effect(
&mut sets, &mut trans,
Location { block: bb, statement_index: statements.len() }); Location { block: bb, statement_index: statements.len() });
tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \