fn clear_bit(&mut self, idx: usize) -> bool {
let words = self;
debug!("clear_bit: words={} idx={}",
- bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
+ bits_to_string(words, words.len() * mem::size_of::<Word>() * 8), idx);
let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
- debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
+ debug!("word={} bit_in_word={} bit_mask=0x{:x}", word, bit_in_word, bit_mask);
let oldv = words[word];
let newv = oldv & !bit_mask;
words[word] = newv;
fn set_bit(&mut self, idx: usize) -> bool {
let words = self;
debug!("set_bit: words={} idx={}",
- bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
+ bits_to_string(words, words.len() * mem::size_of::<Word>() * 8), idx);
let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
let oldv = words[word];
BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask }
}
-
-fn bit_str(bit: Word) -> String {
- let byte = bit >> 3;
- let lobits = 1 << (bit & 0b111);
- format!("[{}:{}-{:02x}]", bit, byte, lobits)
-}
-
pub fn bits_to_string(words: &[Word], bits: usize) -> String {
let mut result = String::new();
let mut sep = '[';
let mut i = 0;
for &word in words.iter() {
let mut v = word;
- loop { // for each byte in `v`:
+ for _ in 0..mem::size_of::<Word>() { // for each byte in `v`:
let remain = bits - i;
// If less than a byte remains, then mask just that many bits.
let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
i += 8;
sep = '-';
}
+ sep = '|';
}
result.push(']');
return result
}
#[inline]
-pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
- in_vec: &[usize],
+pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [Word],
+ in_vec: &[Word],
op: &Op) -> bool {
assert_eq!(out_vec.len(), in_vec.len());
let mut changed = false;
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;
+ fn join(&self, pred1: Word, pred2: Word) -> Word;
}
pub struct Intersect;
impl BitwiseOperator for Intersect {
#[inline]
- fn join(&self, a: usize, b: usize) -> usize { a & b }
+ fn join(&self, a: Word, b: Word) -> Word { a & b }
}
pub struct Union;
impl BitwiseOperator for Union {
#[inline]
- fn join(&self, a: usize, b: usize) -> usize { a | b }
+ fn join(&self, a: Word, b: Word) -> Word { a | b }
}
pub struct Subtract;
impl BitwiseOperator for Subtract {
#[inline]
- fn join(&self, a: usize, b: usize) -> usize { a & !b }
+ fn join(&self, a: Word, b: Word) -> Word { a & !b }
}
}
impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
- /// Create a new `rows x columns` matrix, initially empty.
- pub fn new(rows: R, _columns: C) -> SparseBitMatrix<R, C> {
- SparseBitMatrix {
- vector: IndexVec::from_elem_n(SparseBitSet::new(), rows.index()),
+ /// Create a new empty sparse bit matrix with no rows or columns.
+ pub fn new() -> Self {
+ Self {
+ vector: IndexVec::new(),
}
}
///
/// Returns true if this changed the matrix, and false otherwise.
pub fn add(&mut self, row: R, column: C) -> bool {
+ debug!(
+ "add(row={:?}, column={:?}, current_len={})",
+ row,
+ column,
+ self.vector.len()
+ );
+ self.vector
+ .ensure_contains_elem(row, || SparseBitSet::new());
self.vector[row].insert(column)
}
/// if the matrix represents (transitive) reachability, can
/// `row` reach `column`?
pub fn contains(&self, row: R, column: C) -> bool {
- self.vector[row].contains(column)
+ self.vector.get(row).map_or(false, |r| r.contains(column))
}
/// Add the bits from row `read` to the bits from row `write`,
let mut changed = false;
if read != write {
- let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write);
+ if self.vector.get(read).is_some() {
+ self.vector
+ .ensure_contains_elem(write, || SparseBitSet::new());
+ let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write);
- for read_chunk in bit_set_read.chunks() {
- changed = changed | bit_set_write.insert_chunk(read_chunk).any();
+ for read_chunk in bit_set_read.chunks() {
+ changed = changed | bit_set_write.insert_chunk(read_chunk).any();
+ }
}
}
changed
}
+ /// Merge a row, `from`, into the `into` row.
+ pub fn merge_into(&mut self, into: R, from: &SparseBitSet<C>) -> bool {
+ self.vector
+ .ensure_contains_elem(into, || SparseBitSet::new());
+ self.vector[into].insert_from(from)
+ }
+
/// True if `sub` is a subset of `sup`
pub fn is_subset(&self, sub: R, sup: R) -> bool {
sub == sup || {
}
}
+ /// Number of elements in the matrix.
+ pub fn len(&self) -> usize {
+ self.vector.len()
+ }
+
/// Iterates through all the columns set to true in a given row of
/// the matrix.
pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
- self.vector[row].iter()
+ self.vector.get(row).into_iter().flat_map(|r| r.iter())
+ }
+
+ /// Iterates through each row and the accompanying bit set.
+ pub fn iter_enumerated<'a>(&'a self) -> impl Iterator<Item = (R, &'a SparseBitSet<C>)> + 'a {
+ self.vector.iter_enumerated()
}
}
}
}
+ /// Insert into bit set from another bit set.
+ pub fn insert_from(&mut self, from: &SparseBitSet<I>) -> bool {
+ let mut changed = false;
+ for read_chunk in from.chunks() {
+ changed = changed | self.insert_chunk(read_chunk).any();
+ }
+ changed
+ }
+
pub fn remove_chunk(&mut self, chunk: SparseChunk<I>) -> SparseChunk<I> {
if chunk.bits == 0 {
return chunk;
}
impl<I: Idx, T: Clone> IndexVec<I, T> {
+ /// Grows the index vector so that it contains an entry for
+ /// `elem`; if that is already true, then has no
+ /// effect. Otherwise, inserts new values as needed by invoking
+ /// `fill_value`.
+ #[inline]
+ pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+ let min_new_len = elem.index() + 1;
+ if self.len() < min_new_len {
+ self.raw.resize_with(min_new_len, fill_value);
+ }
+ }
+
#[inline]
pub fn resize(&mut self, new_len: usize, value: T) {
self.raw.resize(new_len, value)
}
+
+ #[inline]
+ pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+ let min_new_len = elem.index() + 1;
+ self.raw.resize_with(min_new_len, fill_value);
+ }
}
impl<I: Idx, T: Ord> IndexVec<I, T> {
#![feature(optin_builtin_traits)]
#![feature(macro_vis_matcher)]
#![feature(allow_internal_unstable)]
+#![feature(vec_resize_with)]
#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts};
-use std::iter;
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
location_table: &LocationTable,
mir: &Mir<'tcx>,
borrow_set: &BorrowSet<'tcx>,
- liveness_set_from_typeck: &[(ty::Region<'tcx>, Location)],
) {
let mut cg = ConstraintGeneration {
borrow_set,
all_facts,
};
- cg.add_region_liveness_constraints_from_type_check(liveness_set_from_typeck);
-
for (bb, data) in mir.basic_blocks().iter_enumerated() {
cg.visit_basic_block_data(bb, data);
}
}
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
- /// The MIR type checker generates region liveness constraints
- /// that we also have to respect.
- fn add_region_liveness_constraints_from_type_check(
- &mut self,
- liveness_set: &[(ty::Region<'tcx>, Location)],
- ) {
- debug!(
- "add_region_liveness_constraints_from_type_check(liveness_set={} items)",
- liveness_set.len(),
- );
-
- let ConstraintGeneration {
- regioncx,
- location_table,
- all_facts,
- ..
- } = self;
-
- for (region, location) in liveness_set {
- debug!("generate: {:#?} is live at {:#?}", region, location);
- let region_vid = regioncx.to_region_vid(region);
- regioncx.add_live_element(region_vid, *location);
- }
-
- if let Some(all_facts) = all_facts {
- all_facts
- .region_live_at
- .extend(liveness_set.into_iter().flat_map(|(region, location)| {
- let r = regioncx.to_region_vid(region);
- let p1 = location_table.start_index(*location);
- let p2 = location_table.mid_index(*location);
- iter::once((r, p1)).chain(iter::once((r, p2)))
- }));
- }
- }
-
/// Some variable with type `live_ty` is "regular live" at
/// `location` -- i.e., it may be used later. This means that all
/// regions appearing in the type `live_ty` must be live at
use borrow_check::location::{LocationIndex, LocationTable};
use borrow_check::nll::facts::AllFactsExt;
use borrow_check::nll::type_check::MirTypeckRegionConstraints;
+use borrow_check::nll::region_infer::values::RegionValueElements;
use dataflow::indexes::BorrowIndex;
use dataflow::move_paths::MoveData;
use dataflow::FlowAtLocation;
None
};
+ let elements = &Rc::new(RegionValueElements::new(mir, universal_regions.len()));
+
// Run the MIR type-checker.
let liveness = &LivenessResults::compute(mir);
let constraint_sets = type_check::type_check(
&mut all_facts,
flow_inits,
move_data,
+ elements,
);
if let Some(all_facts) = &mut all_facts {
// base constraints generated by the type-check.
let var_origins = infcx.take_region_var_origins();
let MirTypeckRegionConstraints {
- liveness_set,
+ liveness_constraints,
outlives_constraints,
type_tests,
} = constraint_sets;
mir,
outlives_constraints,
type_tests,
+ liveness_constraints,
+ elements,
);
// Generate various additional constraints.
location_table,
&mir,
borrow_set,
- &liveness_set,
);
invalidation::generate_invalidates(
infcx,
mod dump_mir;
mod error_reporting;
mod graphviz;
-mod values;
+pub mod values;
use self::values::{RegionValueElements, RegionValues};
use super::ToRegionVid;
/// the SCC (see `constraint_sccs`) and for error reporting.
constraint_graph: Rc<ConstraintGraph>,
- /// The SCC computed from `constraints` and
- /// `constraint_graph`. Used to compute the values of each region.
+ /// The SCC computed from `constraints` and the constraint graph. Used to compute the values
+ /// of each region.
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
/// The final inferred values of the region variables; we compute
pub(crate) fn new(
var_infos: VarInfos,
universal_regions: UniversalRegions<'tcx>,
- mir: &Mir<'tcx>,
+ _mir: &Mir<'tcx>,
outlives_constraints: ConstraintSet,
type_tests: Vec<TypeTest<'tcx>>,
+ liveness_constraints: RegionValues<RegionVid>,
+ elements: &Rc<RegionValueElements>,
) -> Self {
let universal_regions = Rc::new(universal_regions);
- let num_region_variables = var_infos.len();
- let num_universal_regions = universal_regions.len();
-
- let elements = &Rc::new(RegionValueElements::new(mir, num_universal_regions));
// Create a RegionDefinition for each inference variable.
let definitions: IndexVec<_, _> = var_infos
let constraint_graph = Rc::new(constraints.graph(definitions.len()));
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph));
- let scc_values = RegionValues::new(elements, constraint_sccs.num_sccs());
+ let mut scc_values = RegionValues::new(elements);
+
+ for (region, location_set) in liveness_constraints.iter_enumerated() {
+ let scc = constraint_sccs.scc(region);
+ scc_values.merge_into(scc, location_set);
+ }
let mut result = Self {
definitions,
elements: elements.clone(),
- liveness_constraints: RegionValues::new(elements, num_region_variables),
+ liveness_constraints,
constraints,
- constraint_sccs,
constraint_graph,
+ constraint_sccs,
scc_values,
type_tests,
universal_regions,
constraints
});
- // To propagate constriants, we walk the DAG induced by the
+ // To propagate constraints, we walk the DAG induced by the
// SCC. For each SCC, we visit its successors and compute
// their values, then we union all those values to get our
// own.
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::ty::RegionVid;
-use rustc_data_structures::bitvec::SparseBitMatrix;
+use rustc_data_structures::bitvec::{SparseBitMatrix, SparseBitSet};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt::Debug;
}
}
- /// Total number of element indices that exist.
- crate fn num_elements(&self) -> usize {
- self.num_points + self.num_universal_regions
- }
-
/// Converts an element of a region value into a `RegionElementIndex`.
crate fn index<T: ToElementIndex>(&self, elem: T) -> RegionElementIndex {
elem.to_element_index(self)
/// Creates a new set of "region values" that tracks causal information.
/// Each of the regions in num_region_variables will be initialized with an
/// empty set of points and no causal information.
- crate fn new(elements: &Rc<RegionValueElements>, num_region_variables: usize) -> Self {
- assert!(
- elements.num_universal_regions <= num_region_variables,
- "universal regions are a subset of the region variables"
- );
-
+ crate fn new(elements: &Rc<RegionValueElements>) -> Self {
Self {
elements: elements.clone(),
- matrix: SparseBitMatrix::new(
- N::new(num_region_variables),
- RegionElementIndex::new(elements.num_elements()),
- ),
+ matrix: SparseBitMatrix::new(),
}
}
self.matrix.contains(r, i)
}
+ /// Iterates through each row and the accompanying bit set.
+ pub fn iter_enumerated<'a>(
+ &'a self
+ ) -> impl Iterator<Item = (N, &'a SparseBitSet<RegionElementIndex>)> + 'a {
+ self.matrix.iter_enumerated()
+ }
+
+ /// Merge a row, `from`, originating in another `RegionValues` into the `into` row.
+ pub fn merge_into(&mut self, into: N, from: &SparseBitSet<RegionElementIndex>) -> bool {
+ self.matrix.merge_into(into, from)
+ }
+
/// True if `sup_region` contains all the CFG points that
/// `sub_region` contains. Ignores universal regions.
crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
);
cx.tcx().for_each_free_region(&value, |live_region| {
- cx.constraints.liveness_set.push((live_region, location));
+ if let Some(ref mut borrowck_context) = cx.borrowck_context {
+ let region_vid = borrowck_context.universal_regions.to_region_vid(live_region);
+ borrowck_context.constraints.liveness_constraints.add_element(region_vid, location);
+
+ if let Some(all_facts) = borrowck_context.all_facts {
+ let start_index = borrowck_context.location_table.start_index(location);
+ all_facts.region_live_at.push((region_vid, start_index));
+
+ let mid_index = borrowck_context.location_table.mid_index(location);
+ all_facts.region_live_at.push((region_vid, mid_index));
+ }
+ }
});
}
use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
use borrow_check::nll::facts::AllFacts;
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
+use borrow_check::nll::region_infer::values::{RegionValues, RegionValueElements};
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::ToRegionVid;
use dataflow::move_paths::MoveData;
use rustc::traits::query::type_op;
use rustc::traits::query::{Fallible, NoSolution};
use rustc::ty::fold::TypeFoldable;
-use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
+use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants, RegionVid};
use std::fmt;
+use std::rc::Rc;
use syntax_pos::{Span, DUMMY_SP};
use transform::{MirPass, MirSource};
use util::liveness::LivenessResults;
all_facts: &mut Option<AllFacts>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
+ elements: &Rc<RegionValueElements>,
) -> MirTypeckRegionConstraints<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
- type_check_internal(
- infcx,
- mir_def_id,
- param_env,
- mir,
- &universal_regions.region_bound_pairs,
- Some(implicit_region_bound),
- Some(BorrowCheckContext {
+ let mut constraints = MirTypeckRegionConstraints {
+ liveness_constraints: RegionValues::new(elements),
+ outlives_constraints: ConstraintSet::default(),
+ type_tests: Vec::default(),
+ };
+
+ {
+ let mut borrowck_context = BorrowCheckContext {
universal_regions,
location_table,
borrow_set,
all_facts,
- }),
- &mut |cx| {
- liveness::generate(cx, mir, liveness, flow_inits, move_data);
+ constraints: &mut constraints,
+ };
+
+ type_check_internal(
+ infcx,
+ mir_def_id,
+ param_env,
+ mir,
+ &universal_regions.region_bound_pairs,
+ Some(implicit_region_bound),
+ Some(&mut borrowck_context),
+ |cx| {
+ liveness::generate(cx, mir, liveness, flow_inits, move_data);
- cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
- },
- )
+ cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
+ },
+ );
+ }
+
+ constraints
}
-fn type_check_internal<'gcx, 'tcx>(
- infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+fn type_check_internal<'a, 'gcx, 'tcx, F>(
+ infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
mir_def_id: DefId,
param_env: ty::ParamEnv<'gcx>,
- mir: &Mir<'tcx>,
- region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
+ mir: &'a Mir<'tcx>,
+ region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>,
- borrowck_context: Option<BorrowCheckContext<'_, 'tcx>>,
- extra: &mut dyn FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
-) -> MirTypeckRegionConstraints<'tcx> {
+ borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
+ mut extra: F,
+)
+ where F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>)
+{
let mut checker = TypeChecker::new(
infcx,
mir,
}
extra(&mut checker);
-
- checker.constraints
}
fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>,
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
- constraints: MirTypeckRegionConstraints<'tcx>,
- borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
+ borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
}
struct BorrowCheckContext<'a, 'tcx: 'a> {
location_table: &'a LocationTable,
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
+ constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
}
/// A collection of region constraints that must be satisfied for the
/// program to be considered well-typed.
-#[derive(Default)]
crate struct MirTypeckRegionConstraints<'tcx> {
/// In general, the type-checker is not responsible for enforcing
/// liveness constraints; this job falls to the region inferencer,
/// not otherwise appear in the MIR -- in particular, the
/// late-bound regions that it instantiates at call-sites -- and
/// hence it must report on their liveness constraints.
- crate liveness_set: Vec<(ty::Region<'tcx>, Location)>,
+ crate liveness_constraints: RegionValues<RegionVid>,
crate outlives_constraints: ConstraintSet,
param_env: ty::ParamEnv<'gcx>,
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>,
- borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
+ borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
) -> Self {
TypeChecker {
infcx,
implicit_region_bound,
borrowck_context,
reported_errors: FxHashSet(),
- constraints: MirTypeckRegionConstraints::default(),
}
}
locations, data
);
- if let Some(borrowck_context) = &mut self.borrowck_context {
+ if let Some(ref mut borrowck_context) = self.borrowck_context {
constraint_conversion::ConstraintConversion::new(
self.infcx.tcx,
borrowck_context.universal_regions,
self.implicit_region_bound,
self.param_env,
locations,
- &mut self.constraints.outlives_constraints,
- &mut self.constraints.type_tests,
+ &mut borrowck_context.constraints.outlives_constraints,
+ &mut borrowck_context.constraints.type_tests,
&mut borrowck_context.all_facts,
).convert_all(&data);
}
// output) types in the signature must be live, since
// all the inputs that fed into it were live.
for &late_bound_region in map.values() {
- self.constraints
- .liveness_set
- .push((late_bound_region, term_location));
+ if let Some(ref mut borrowck_context) = self.borrowck_context {
+ let region_vid = borrowck_context.universal_regions.to_region_vid(
+ late_bound_region);
+ borrowck_context.constraints
+ .liveness_constraints
+ .add_element(region_vid, term_location);
+ }
}
self.check_call_inputs(mir, term, &sig, args, term_location);
borrow_set,
location_table,
all_facts,
+ constraints,
..
- } = match &mut self.borrowck_context {
- Some(borrowck_context) => borrowck_context,
+ } = match self.borrowck_context {
+ Some(ref mut borrowck_context) => borrowck_context,
None => return,
};
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.sty {
ty::TyRef(ref_region, _, mutbl) => {
- self.constraints
+ constraints
.outlives_constraints
.push(OutlivesConstraint {
sup: ref_region.to_region_vid(),
let param_env = tcx.param_env(def_id);
tcx.infer_ctxt().enter(|infcx| {
- let _ =
- type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, &mut |_| ());
+ type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, |_| ());
// For verification purposes, we just ignore the resulting
// region constraint sets. Not our problem. =)
impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}
use rustc::ty::{RegionKind, RegionVid};
use rustc::ty::RegionKind::ReScope;
-use rustc_data_structures::bitslice::BitwiseOperator;
+use rustc_data_structures::bitslice::{BitwiseOperator, Word};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_set::IdxSet;
use rustc_data_structures::indexed_vec::IndexVec;
impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // union effects of preds when computing reservations
}
}
use rustc::ty::TyCtxt;
use rustc::mir::{self, Mir, Location};
-use rustc_data_structures::bitslice::{BitwiseOperator};
+use rustc_data_structures::bitslice::{BitwiseOperator, Word};
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}
impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}
impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 & pred2 // "definitely" means we intersect effects of both preds
}
}
impl<'a, 'gcx, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // moves from both preds are in scope
}
}
impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // inits from both preds are in scope
}
}
impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
#[inline]
- fn join(&self, pred1: usize, pred2: usize) -> usize {
+ fn join(&self, pred1: Word, pred2: Word) -> Word {
pred1 | pred2 // "maybe" means we union effects of both preds
}
}
use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
+use rustc_data_structures::bitslice::{bitwise, BitwiseOperator, Word};
use rustc_data_structures::work_queue::WorkQueue;
use rustc::ty::{self, TyCtxt};
bits_per_block: usize,
/// Number of words associated with each block entry
- /// equal to bits_per_block / usize::BITS, rounded up.
+ /// equal to bits_per_block / (mem::size_of::<Word> * 8), rounded up.
words_per_block: usize,
/// For each block, bits generated by executing the statements in
dead_unwinds: &'a IdxSet<mir::BasicBlock>,
denotation: D) -> Self where D: InitialFlow {
let bits_per_block = denotation.bits_per_block();
- let usize_bits = mem::size_of::<usize>() * 8;
- let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
- let num_overall = Self::num_bits_overall(mir, bits_per_block);
+ let bits_per_word = mem::size_of::<Word>() * 8;
+ let words_per_block = (bits_per_block + bits_per_word - 1) / bits_per_word;
+ let bits_per_block_rounded_up = words_per_block * bits_per_word; // a multiple of word size
+ let num_blocks = mir.basic_blocks().len();
+ let num_overall = num_blocks * bits_per_block_rounded_up;
let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall));
let on_entry = Bits::new(if D::bottom_value() {
}
}
}
-
- fn num_bits_overall(mir: &Mir, bits_per_block: usize) -> usize {
- let usize_bits = mem::size_of::<usize>() * 8;
- let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
-
- // (now rounded up to multiple of word size)
- let bits_per_block = words_per_block * usize_bits;
-
- let num_blocks = mir.basic_blocks().len();
- let num_overall = num_blocks * bits_per_block;
- num_overall
- }
}
impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation