Skip to content

Commit

Permalink
Merge BitSetOperator and InitialFlow into one trait.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ecstatic-morse committed Jun 22, 2019
1 parent c054186 commit c8cbd4f
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 115 deletions.
5 changes: 0 additions & 5 deletions src/librustc_data_structures/bit_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,6 @@ impl<'a, T: Idx> Iterator for BitIter<'a, 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
Expand Down
15 changes: 3 additions & 12 deletions src/librustc_mir/dataflow/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,9 @@ impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
}
}

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> {
Expand Down
19 changes: 5 additions & 14 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use rustc::mir::{self, Location, Place, PlaceBase, Body};
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;
Expand Down Expand Up @@ -331,16 +331,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
}
}

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;
}
74 changes: 14 additions & 60 deletions src/librustc_mir/dataflow/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

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;

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;
Expand Down Expand Up @@ -505,68 +505,22 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
}
}

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> 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> 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> 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> BottomValue for MaybeInitializedPlaces<'a, 'tcx> {
/// bottom = uninitialized
const BOTTOM_VALUE: bool = false;
}

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> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> {
/// bottom = initialized (start_block_effect counters this at outset)
const BOTTOM_VALUE: bool = false;
}

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> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> {
/// bottom = initialized (start_block_effect counters this at outset)
const BOTTOM_VALUE: bool = true;
}

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;
}
15 changes: 3 additions & 12 deletions src/librustc_mir/dataflow/impls/storage_liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
}
}

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;
}
38 changes: 26 additions & 12 deletions src/librustc_mir/dataflow/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -552,25 +552,39 @@ impl<E:Idx> AllSets<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.
///
/// 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;

Expand Down Expand Up @@ -688,7 +702,7 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'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]
Expand Down

0 comments on commit c8cbd4f

Please sign in to comment.