Merge BitSetOperator
and InitialFlow
into one trait.
Since the value of `InitialFlow` defines the semantics of the `join` operation, there's no reason to have seperate traits for each. We can add a default impl of `join` which branches based on `BOTTOM_VALUE`. This should get optimized away.
This commit is contained in:
parent
c054186ec7
commit
c8cbd4fc78
@ -273,11 +273,6 @@ fn next(&mut self) -> Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BitSetOperator {
|
||||
/// Combine one bitset into another.
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
|
||||
where Op: Fn(Word, Word) -> Word
|
||||
|
@ -83,18 +83,9 @@ fn propagate_call_return(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitSetOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
inout_set.union(in_set) // "maybe" means we union effects of both preds
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
false // bottom = unborrowed
|
||||
}
|
||||
impl<'a, 'tcx> BottomValue for HaveBeenBorrowedLocals<'a, 'tcx> {
|
||||
// bottom = unborrowed
|
||||
const BOTTOM_VALUE: bool = false;
|
||||
}
|
||||
|
||||
struct BorrowedLocalsVisitor<'gk> {
|
||||
|
@ -5,11 +5,11 @@
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::RegionVid;
|
||||
|
||||
use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
|
||||
use rustc_data_structures::bit_set::BitSet;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
|
||||
use crate::dataflow::{BitDenotation, InitialFlow, GenKillSet};
|
||||
use crate::dataflow::{BitDenotation, BottomValue, GenKillSet};
|
||||
use crate::borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use crate::borrow_check::nll::ToRegionVid;
|
||||
use crate::borrow_check::places_conflict;
|
||||
@ -331,16 +331,7 @@ fn propagate_call_return(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitSetOperator for Borrows<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
inout_set.union(in_set) // "maybe" means we union effects of both preds
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InitialFlow for Borrows<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
false // bottom = nothing is reserved or activated yet
|
||||
}
|
||||
impl<'a, 'tcx> BottomValue for Borrows<'a, 'tcx> {
|
||||
/// bottom = nothing is reserved or activated yet;
|
||||
const BOTTOM_VALUE: bool = false;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::{self, Body, Location};
|
||||
use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
|
||||
use rustc_data_structures::bit_set::BitSet;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use super::MoveDataParamEnv;
|
||||
@ -12,7 +12,7 @@
|
||||
use crate::util::elaborate_drops::DropFlagState;
|
||||
|
||||
use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex, InitKind};
|
||||
use super::{BitDenotation, InitialFlow, GenKillSet};
|
||||
use super::{BitDenotation, BottomValue, GenKillSet};
|
||||
|
||||
use super::drop_flag_effects_for_function_entry;
|
||||
use super::drop_flag_effects_for_location;
|
||||
@ -505,68 +505,22 @@ fn propagate_call_return(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitSetOperator for MaybeInitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
inout_set.union(in_set) // "maybe" means we union effects of both preds
|
||||
}
|
||||
impl<'a, 'tcx> BottomValue for MaybeInitializedPlaces<'a, 'tcx> {
|
||||
/// bottom = uninitialized
|
||||
const BOTTOM_VALUE: bool = false;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitSetOperator for MaybeUninitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
inout_set.union(in_set) // "maybe" means we union effects of both preds
|
||||
}
|
||||
impl<'a, 'tcx> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> {
|
||||
/// bottom = initialized (start_block_effect counters this at outset)
|
||||
const BOTTOM_VALUE: bool = false;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitSetOperator for DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
inout_set.intersect(in_set) // "definitely" means we intersect effects of both preds
|
||||
}
|
||||
impl<'a, 'tcx> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
/// bottom = initialized (start_block_effect counters this at outset)
|
||||
const BOTTOM_VALUE: bool = true;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitSetOperator for EverInitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
inout_set.union(in_set) // inits from both preds are in scope
|
||||
}
|
||||
}
|
||||
|
||||
// The way that dataflow fixed point iteration works, you want to
|
||||
// start at bottom and work your way to a fixed point. Control-flow
|
||||
// merges will apply the `join` operator to each block entry's current
|
||||
// state (which starts at that bottom value).
|
||||
//
|
||||
// This means, for propagation across the graph, that you either want
|
||||
// to start at all-zeroes and then use Union as your merge when
|
||||
// propagating, or you start at all-ones and then use Intersect as
|
||||
// your merge when propagating.
|
||||
|
||||
impl<'a, 'tcx> InitialFlow for MaybeInitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
false // bottom = uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InitialFlow for MaybeUninitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
false // bottom = initialized (start_block_effect counters this at outset)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InitialFlow for DefinitelyInitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
true // bottom = initialized (start_block_effect counters this at outset)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InitialFlow for EverInitializedPlaces<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
false // bottom = no initialized variables by default
|
||||
}
|
||||
impl<'a, 'tcx> BottomValue for EverInitializedPlaces<'a, 'tcx> {
|
||||
/// bottom = no initialized variables by default
|
||||
const BOTTOM_VALUE: bool = false;
|
||||
}
|
||||
|
@ -59,16 +59,7 @@ fn propagate_call_return(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BitSetOperator for MaybeStorageLive<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
inout_set.union(in_set) // "maybe" means we union effects of both preds
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InitialFlow for MaybeStorageLive<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
false // bottom = dead
|
||||
}
|
||||
impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> {
|
||||
/// bottom = dead
|
||||
const BOTTOM_VALUE: bool = false;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use syntax::ast::{self, MetaItem};
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
|
||||
use rustc_data_structures::bit_set::{BitSet, BitSetOperator, HybridBitSet};
|
||||
use rustc_data_structures::bit_set::{BitSet, HybridBitSet};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_data_structures::work_queue::WorkQueue;
|
||||
|
||||
@ -552,14 +552,28 @@ pub fn kill_set_for(&self, block_idx: usize) -> &HybridBitSet<E> {
|
||||
}
|
||||
|
||||
/// Parameterization for the precise form of data flow that is used.
|
||||
/// `InitialFlow` handles initializing the bitvectors before any
|
||||
/// code is inspected by the analysis. Analyses that need more nuanced
|
||||
/// initialization (e.g., they need to consult the results of some other
|
||||
/// dataflow analysis to set up the initial bitvectors) should not
|
||||
/// implement this.
|
||||
pub trait InitialFlow {
|
||||
/// Specifies the initial value for each bit in the `on_entry` set
|
||||
fn bottom_value() -> bool;
|
||||
///
|
||||
/// `BottomValue` determines whether the initial entry set for each basic block is empty or full.
|
||||
/// This also determines the semantics of the lattice `join` operator used to merge dataflow
|
||||
/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed
|
||||
/// point.
|
||||
///
|
||||
/// This means, for propagation across the graph, that you either want to start at all-zeroes and
|
||||
/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect
|
||||
/// as your merge when propagating.
|
||||
pub trait BottomValue {
|
||||
/// Specifies the initial value for each bit in the entry set for each basic block.
|
||||
const BOTTOM_VALUE: bool;
|
||||
|
||||
/// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed.
|
||||
#[inline]
|
||||
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
||||
if Self::BOTTOM_VALUE == false {
|
||||
inout_set.union(in_set)
|
||||
} else {
|
||||
inout_set.intersect(in_set)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A specific flavor of dataflow analysis.
|
||||
@ -567,10 +581,10 @@ pub trait InitialFlow {
|
||||
/// 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
|
||||
/// initialized to `Self::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 {
|
||||
pub trait BitDenotation<'tcx>: BottomValue {
|
||||
/// Specifies what index type is used to access the bitvector.
|
||||
type Idx: Idx;
|
||||
|
||||
@ -688,7 +702,7 @@ pub fn new(body: &'a Body<'tcx>,
|
||||
let bits_per_block = denotation.bits_per_block();
|
||||
let num_blocks = body.basic_blocks().len();
|
||||
|
||||
let on_entry = if D::bottom_value() {
|
||||
let on_entry = if D::BOTTOM_VALUE == true {
|
||||
vec![BitSet::new_filled(bits_per_block); num_blocks]
|
||||
} else {
|
||||
vec![BitSet::new_empty(bits_per_block); num_blocks]
|
||||
|
Loading…
Reference in New Issue
Block a user