diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 1f642099f0899..1f41c4dba0472 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -10,11 +10,9 @@ use rustc_middle::mir::{ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_mir_dataflow::points::LivenessValues; -use crate::{ - borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict, - region_infer::values::LivenessValues, -}; +use crate::{borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict}; pub(super) fn generate_constraints<'tcx>( infcx: &InferCtxt<'tcx>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 0ea4401a87847..4a37c76022a5e 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -12,6 +12,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::symbol::sym; use std::env; use std::io; @@ -33,7 +34,7 @@ use crate::{ facts::{AllFacts, AllFactsExt, RustcFacts}, invalidation, location::LocationTable, - region_infer::{values::RegionValueElements, RegionInferenceContext}, + region_infer::RegionInferenceContext, renumber, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, universal_regions::UniversalRegions, @@ -179,7 +180,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( let universal_regions = Rc::new(universal_regions); - let elements = &Rc::new(RegionValueElements::new(&body)); + let elements = &Rc::new(DenseLocationMap::new(&body)); // Run the MIR type-checker. let MirTypeckResults { diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index 4d620ac9de615..004a58978f53d 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -67,7 +67,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { with_msg: &mut dyn FnMut(&str) -> io::Result<()>, ) -> io::Result<()> { for region in self.definitions.indices() { - let value = self.liveness_constraints.region_value_str(region); + let value = self.region_value_str(region); if value != "{}" { with_msg(&format!("{region:?} live at {value}"))?; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 96cbe98c21694..ca0b87bf14d7f 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::mir::{ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_mir_dataflow::points::{DenseLocationMap, LivenessValues, PointIndex}; use rustc_span::Span; use crate::dataflow::BorrowIndex; @@ -31,10 +32,7 @@ use crate::{ member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, nll::PoloniusOutput, region_infer::reverse_sccs::ReverseSccGraph, - region_infer::values::{ - LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements, - RegionValues, ToElementIndex, - }, + region_infer::values::{PlaceholderIndices, RegionElement, RegionValues, ToElementIndex}, type_check::{free_region_relations::UniversalRegionRelations, Locations}, universal_regions::UniversalRegions, BorrowckInferCtxt, @@ -334,7 +332,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe_causes: FxIndexMap>, type_tests: Vec>, liveness_constraints: LivenessValues, - elements: &Rc, + elements: &Rc, live_loans: SparseBitMatrix, ) -> Self { debug!("universal_regions: {:#?}", universal_regions); @@ -1970,7 +1968,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); self.find_constraint_paths_between_regions(fr1, |r| { // First look for some `r` such that `fr1: r` and `r` is live at `elem` - trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r)); + trace!(?r, liveness_constraints=?self.region_value_str(r)); self.liveness_constraints.contains(r, elem) }) .or_else(|| { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 38452df32e9ed..40e45ddbe4e12 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -2,98 +2,14 @@ #![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::fx::FxIndexSet; use rustc_index::bit_set::SparseBitMatrix; -use rustc_index::interval::IntervalSet; use rustc_index::interval::SparseIntervalMatrix; use rustc_index::Idx; -use rustc_index::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, Location}; +use rustc_middle::mir::{BasicBlock, Location}; use rustc_middle::ty::{self, RegionVid}; +use rustc_mir_dataflow::points::{DenseLocationMap, LivenessValues, PointIndex}; use std::fmt::Debug; use std::rc::Rc; -/// Maps between a `Location` and a `PointIndex` (and vice versa). -pub(crate) struct RegionValueElements { - /// For each basic block, how many points are contained within? - statements_before_block: IndexVec, - - /// Map backward from each point to the basic block that it - /// belongs to. - basic_blocks: IndexVec, - - num_points: usize, -} - -impl RegionValueElements { - pub(crate) fn new(body: &Body<'_>) -> Self { - let mut num_points = 0; - let statements_before_block: IndexVec = body - .basic_blocks - .iter() - .map(|block_data| { - let v = num_points; - num_points += block_data.statements.len() + 1; - v - }) - .collect(); - debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block); - debug!("RegionValueElements: num_points={:#?}", num_points); - - let mut basic_blocks = IndexVec::with_capacity(num_points); - for (bb, bb_data) in body.basic_blocks.iter_enumerated() { - basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); - } - - Self { statements_before_block, basic_blocks, num_points } - } - - /// Total number of point indices - pub(crate) fn num_points(&self) -> usize { - self.num_points - } - - /// Converts a `Location` into a `PointIndex`. O(1). - pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index + statement_index) - } - - /// Converts a `Location` into a `PointIndex`. O(1). - pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex { - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index) - } - - /// Return the PointIndex for the block start of this index. - pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex { - PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) - } - - /// Converts a `PointIndex` back to a location. O(1). - pub(crate) fn to_location(&self, index: PointIndex) -> Location { - assert!(index.index() < self.num_points); - let block = self.basic_blocks[index]; - let start_index = self.statements_before_block[block]; - let statement_index = index.index() - start_index; - Location { block, statement_index } - } - - /// Sometimes we get point-indices back from bitsets that may be - /// out of range (because they round up to the nearest 2^N number - /// of bits). Use this function to filter such points out if you - /// like. - pub(crate) fn point_in_range(&self, index: PointIndex) -> bool { - index.index() < self.num_points - } -} - -rustc_index::newtype_index! { - /// A single integer representing a `Location` in the MIR control-flow - /// graph. Constructed efficiently from `RegionValueElements`. - #[debug_format = "PointIndex({})"] - pub struct PointIndex {} -} - rustc_index::newtype_index! { /// A single integer representing a `ty::Placeholder`. #[debug_format = "PlaceholderIndex({})"] @@ -116,73 +32,6 @@ pub(crate) enum RegionElement { PlaceholderRegion(ty::PlaceholderRegion), } -/// When we initially compute liveness, we use an interval matrix storing -/// liveness ranges for each region-vid. -pub(crate) struct LivenessValues { - elements: Rc, - points: SparseIntervalMatrix, -} - -impl LivenessValues { - /// 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. - pub(crate) fn new(elements: Rc) -> Self { - Self { points: SparseIntervalMatrix::new(elements.num_points), elements } - } - - /// Iterate through each region that has a value in this set. - pub(crate) fn rows(&self) -> impl Iterator { - self.points.rows() - } - - /// Adds the given element to the value for the given region. Returns whether - /// the element is newly added (i.e., was not already present). - pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool { - debug!("LivenessValues::add(r={:?}, location={:?})", row, location); - let index = self.elements.point_from_location(location); - self.points.insert(row, index) - } - - /// Adds all the elements in the given bit array into the given - /// region. Returns whether any of them are newly added. - pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet) -> bool { - debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); - self.points.union_row(row, locations) - } - - /// Adds all the control-flow points to the values for `r`. - pub(crate) fn add_all_points(&mut self, row: N) { - self.points.insert_all_into_row(row); - } - - /// Returns `true` if the region `r` contains the given element. - pub(crate) fn contains(&self, row: N, location: Location) -> bool { - let index = self.elements.point_from_location(location); - self.points.row(row).is_some_and(|r| r.contains(index)) - } - - /// Returns an iterator of all the elements contained by the region `r` - pub(crate) fn get_elements(&self, row: N) -> impl Iterator + '_ { - self.points - .row(row) - .into_iter() - .flat_map(|set| set.iter()) - .take_while(move |&p| self.elements.point_in_range(p)) - .map(move |p| self.elements.to_location(p)) - } - - /// Returns a "pretty" string value of the region. Meant for debugging. - pub(crate) fn region_value_str(&self, r: N) -> String { - region_value_str(self.get_elements(r).map(RegionElement::Location)) - } - - #[inline] - pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { - self.elements.point_from_location(location) - } -} - /// Maps from `ty::PlaceholderRegion` values that are used in the rest of /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. @@ -234,7 +83,7 @@ impl PlaceholderIndices { /// it would also contain various points from within the function. #[derive(Clone)] pub(crate) struct RegionValues { - elements: Rc, + elements: Rc, placeholder_indices: Rc, points: SparseIntervalMatrix, free_regions: SparseBitMatrix, @@ -249,14 +98,14 @@ impl RegionValues { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. pub(crate) fn new( - elements: &Rc, + elements: &Rc, num_universal_regions: usize, placeholder_indices: &Rc, ) -> Self { let num_placeholders = placeholder_indices.len(); Self { elements: elements.clone(), - points: SparseIntervalMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points()), placeholder_indices: placeholder_indices.clone(), free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), @@ -308,7 +157,7 @@ impl RegionValues { /// elements for the region `from` from `values` and add them to /// the region `to` in `self`. pub(crate) fn merge_liveness(&mut self, to: N, from: M, values: &LivenessValues) { - if let Some(set) = values.points.row(from) { + if let Some(set) = values.get_intervals(from) { self.points.union_row(to, set); } } @@ -421,7 +270,7 @@ impl ToElementIndex for ty::PlaceholderRegion { } pub(crate) fn location_set_str( - elements: &RegionValueElements, + elements: &DenseLocationMap, points: impl IntoIterator, ) -> String { region_value_str( diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index a9ca94567878a..b06cca65f771c 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -2,9 +2,9 @@ use rustc_data_structures::vec_linked_list as vll; use rustc_index::IndexVec; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use crate::def_use::{self, DefUse}; -use crate::region_infer::values::{PointIndex, RegionValueElements}; /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness @@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance { impl LocalUseMap { pub(crate) fn build( live_locals: &[Local], - elements: &RegionValueElements, + elements: &DenseLocationMap, body: &Body<'_>, ) -> Self { let nones = IndexVec::from_elem(None, &body.local_decls); @@ -103,7 +103,7 @@ impl LocalUseMap { struct LocalUseMapBuild<'me> { local_use_map: &'me mut LocalUseMap, - elements: &'me RegionValueElements, + elements: &'me DenseLocationMap, // Vector used in `visit_local` to signal which `Local`s do we need // def/use/drop information on, constructed from `live_locals` (that @@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> { } fn insert( - elements: &RegionValueElements, + elements: &DenseLocationMap, first_appearance: &mut Option, appearances: &mut IndexVec, location: Location, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index f1ad0ca55ccfd..60691d82f8a35 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -4,6 +4,7 @@ use rustc_middle::mir::{Body, Local}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::ResultsCursor; use std::rc::Rc; @@ -11,7 +12,6 @@ use crate::{ constraints::OutlivesConstraintSet, facts::{AllFacts, AllFactsExt}, location::LocationTable, - region_infer::values::RegionValueElements, universal_regions::UniversalRegions, }; @@ -32,7 +32,7 @@ mod trace; pub(super) fn generate<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc, + elements: &Rc, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, location_table: &LocationTable, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 80e6c6c1dfb77..107edb652e2e8 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -6,6 +6,7 @@ use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -17,7 +18,7 @@ use rustc_mir_dataflow::ResultsCursor; use crate::dataflow::BorrowIndex; use crate::{ - region_infer::values::{self, PointIndex, RegionValueElements}, + region_infer::values::{self}, type_check::liveness::local_use_map::LocalUseMap, type_check::liveness::polonius, type_check::NormalizeLocation, @@ -41,7 +42,7 @@ use crate::{ pub(super) fn trace<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc, + elements: &Rc, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, @@ -107,7 +108,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { typeck: &'me mut TypeChecker<'typeck, 'tcx>, /// Defines the `PointIndex` mapping - elements: &'me RegionValueElements, + elements: &'me DenseLocationMap, /// MIR we are analyzing. body: &'me Body<'tcx>, @@ -589,7 +590,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { } fn make_all_regions_live( - elements: &RegionValueElements, + elements: &DenseLocationMap, typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeVisitable>, live_at: &IntervalSet, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9eb02be2f155b..83f4a5e2afb0b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -37,6 +37,7 @@ use rustc_middle::ty::{ OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_middle::ty::{GenericArgsRef, UserArgs}; +use rustc_mir_dataflow::points::{DenseLocationMap, LivenessValues}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -49,10 +50,10 @@ use rustc_trait_selection::traits::PredicateObligation; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::points::PointIndex; use rustc_mir_dataflow::ResultsCursor; use crate::dataflow::BorrowIndex; -use crate::region_infer::values::PointIndex; use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst}; use crate::{ borrow_set::BorrowSet, @@ -62,9 +63,7 @@ use crate::{ location::LocationTable, member_constraints::MemberConstraintSet, path_utils, - region_infer::values::{ - LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, - }, + region_infer::values::{PlaceholderIndex, PlaceholderIndices}, region_infer::TypeTest, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, @@ -137,7 +136,7 @@ pub(crate) fn type_check<'mir, 'tcx>( all_facts: &mut Option, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, - elements: &Rc, + elements: &Rc, upvars: &[Upvar<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { @@ -557,7 +556,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let all_facts = &mut None; let mut constraints = Default::default(); let mut liveness_constraints = - LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body))); + LivenessValues::new(Rc::new(DenseLocationMap::new(&promoted_body))); // Don't try to add borrow_region facts for the promoted MIR let mut swap_constraints = |this: &mut Self| { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index ecf46715cd088..346e521c569ce 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -42,6 +42,7 @@ mod errors; mod framework; pub mod impls; pub mod move_paths; +pub mod points; pub mod rustc_peek; pub mod storage; pub mod un_derefer; diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs new file mode 100644 index 0000000000000..ddc0e8616e212 --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -0,0 +1,164 @@ +use rustc_index::interval::IntervalSet; +use rustc_index::interval::SparseIntervalMatrix; +use rustc_index::Idx; +use rustc_index::IndexVec; +use rustc_middle::mir::{BasicBlock, Body, Location}; +use std::rc::Rc; + +/// Maps between a `Location` and a `PointIndex` (and vice versa). +pub struct DenseLocationMap { + /// For each basic block, how many points are contained within? + statements_before_block: IndexVec, + + /// Map backward from each point to the basic block that it + /// belongs to. + basic_blocks: IndexVec, + + num_points: usize, +} + +impl DenseLocationMap { + #[inline] + pub fn new(body: &Body<'_>) -> Self { + let mut num_points = 0; + let statements_before_block: IndexVec = body + .basic_blocks + .iter() + .map(|block_data| { + let v = num_points; + num_points += block_data.statements.len() + 1; + v + }) + .collect(); + debug!("DenseLocationMap: statements_before_block={:#?}", statements_before_block); + debug!("DenseLocationMap: num_points={:#?}", num_points); + + let mut basic_blocks = IndexVec::with_capacity(num_points); + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { + basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); + } + + Self { statements_before_block, basic_blocks, num_points } + } + + /// Total number of point indices + #[inline] + pub fn num_points(&self) -> usize { + self.num_points + } + + /// Converts a `Location` into a `PointIndex`. O(1). + #[inline] + pub fn point_from_location(&self, location: Location) -> PointIndex { + let Location { block, statement_index } = location; + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index + statement_index) + } + + /// Converts a `Location` into a `PointIndex`. O(1). + #[inline] + pub fn entry_point(&self, block: BasicBlock) -> PointIndex { + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index) + } + + /// Return the PointIndex for the block start of this index. + #[inline] + pub fn to_block_start(&self, index: PointIndex) -> PointIndex { + PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) + } + + /// Converts a `PointIndex` back to a location. O(1). + #[inline] + pub fn to_location(&self, index: PointIndex) -> Location { + assert!(index.index() < self.num_points); + let block = self.basic_blocks[index]; + let start_index = self.statements_before_block[block]; + let statement_index = index.index() - start_index; + Location { block, statement_index } + } + + /// Sometimes we get point-indices back from bitsets that may be + /// out of range (because they round up to the nearest 2^N number + /// of bits). Use this function to filter such points out if you + /// like. + #[inline] + pub fn point_in_range(&self, index: PointIndex) -> bool { + index.index() < self.num_points + } +} + +rustc_index::newtype_index! { + /// A single integer representing a `Location` in the MIR control-flow + /// graph. Constructed efficiently from `DenseLocationMap`. + #[debug_format = "PointIndex({})"] + pub struct PointIndex {} +} + +/// When we initially compute liveness, we use an interval matrix storing +/// liveness ranges for each region-vid. +pub struct LivenessValues { + elements: Rc, + points: SparseIntervalMatrix, +} + +impl LivenessValues { + /// 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. + pub fn new(elements: Rc) -> Self { + Self { points: SparseIntervalMatrix::new(elements.num_points), elements } + } + + /// Converts a `Location` into a `PointIndex`. O(1). + #[inline] + pub fn point_from_location(&self, location: Location) -> PointIndex { + self.elements.point_from_location(location) + } + + /// Iterate through each region that has a value in this set. + pub fn rows(&self) -> impl Iterator { + self.points.rows() + } + + /// Adds the given element to the value for the given region. Returns whether + /// the element is newly added (i.e., was not already present). + pub fn add_element(&mut self, row: N, location: Location) -> bool { + debug!("LivenessValues::add(r={:?}, location={:?})", row, location); + let index = self.elements.point_from_location(location); + self.points.insert(row, index) + } + + /// Adds all the elements in the given bit array into the given + /// region. Returns whether any of them are newly added. + pub fn add_elements(&mut self, row: N, locations: &IntervalSet) -> bool { + debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); + self.points.union_row(row, locations) + } + + /// Adds all the control-flow points to the values for `r`. + pub fn add_all_points(&mut self, row: N) { + self.points.insert_all_into_row(row); + } + + /// Returns `true` if the region `r` contains the given element. + pub fn contains(&self, row: N, location: Location) -> bool { + let index = self.elements.point_from_location(location); + self.points.row(row).is_some_and(|r| r.contains(index)) + } + + /// Returns an iterator of all the elements contained by the region `r` + pub fn get_elements(&self, row: N) -> impl Iterator + '_ { + self.points + .row(row) + .into_iter() + .flat_map(|set| set.iter()) + .take_while(move |&p| self.elements.point_in_range(p)) + .map(move |p| self.elements.to_location(p)) + } + + /// Return all the elements associated to the given region. + pub fn get_intervals(&self, region: N) -> Option<&IntervalSet> { + self.points.row(region) + } +} diff --git a/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir index 49f0a43295a88..b13c06d69d399 100644 --- a/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir +++ b/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir @@ -19,11 +19,15 @@ | '?8 | U0 | {bb0[0..=1], '?3} | | Inference Constraints -| '?0 live at {bb0[0..=1]} -| '?1 live at {bb0[0..=1]} -| '?2 live at {bb0[0..=1]} -| '?3 live at {bb0[0..=1]} -| '?4 live at {bb0[0..=1]} +| '?0 live at {bb0[0..=1], '?0, '?1, '?2, '?3, '?4} +| '?1 live at {bb0[0..=1], '?1} +| '?2 live at {bb0[0..=1], '?2} +| '?3 live at {bb0[0..=1], '?3} +| '?4 live at {bb0[0..=1], '?4} +| '?5 live at {bb0[0..=1], '?1} +| '?6 live at {bb0[0..=1], '?2} +| '?7 live at {bb0[0..=1], '?1} +| '?8 live at {bb0[0..=1], '?3} | '?1: '?5 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:13:26: 13:27) ($DIR/named_lifetimes_basic.rs:13:26: 13:27 (#0) | '?1: '?7 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:13:54: 13:55) ($DIR/named_lifetimes_basic.rs:13:54: 13:55 (#0) | '?2: '?6 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:13:42: 13:43) ($DIR/named_lifetimes_basic.rs:13:42: 13:43 (#0) diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index ad456600b0ab6..830261f49d88a 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -12,10 +12,10 @@ | '?4 | U0 | {bb1[4..=7], bb2[0..=2]} | | Inference Constraints -| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '?2 live at {bb1[0]} -| '?3 live at {bb1[1..=3]} +| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1} +| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1} +| '?2 live at {bb1[0..=7], bb2[0..=2]} +| '?3 live at {bb1[1..=7], bb2[0..=2]} | '?4 live at {bb1[4..=7], bb2[0..=2]} | '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) | '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index a15d47cd66fef..311bc05a01b59 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -12,10 +12,10 @@ | '?4 | U0 | {bb1[4..=7], bb2[0..=2]} | | Inference Constraints -| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '?2 live at {bb1[0]} -| '?3 live at {bb1[1..=3]} +| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1} +| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1} +| '?2 live at {bb1[0..=7], bb2[0..=2]} +| '?3 live at {bb1[1..=7], bb2[0..=2]} | '?4 live at {bb1[4..=7], bb2[0..=2]} | '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) | '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) diff --git a/tests/mir-opt/storage_ranges.main.nll.0.mir b/tests/mir-opt/storage_ranges.main.nll.0.mir index 782efd5acc625..b9eb5f6188240 100644 --- a/tests/mir-opt/storage_ranges.main.nll.0.mir +++ b/tests/mir-opt/storage_ranges.main.nll.0.mir @@ -11,9 +11,9 @@ | '?3 | U0 | {bb0[11]} | | Inference Constraints -| '?0 live at {bb0[0..=22]} -| '?1 live at {bb0[0..=22]} -| '?2 live at {bb0[10]} +| '?0 live at {bb0[0..=22], '?0, '?1} +| '?1 live at {bb0[0..=22], '?1} +| '?2 live at {bb0[10..=11]} | '?3 live at {bb0[11]} | '?2: '?3 due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:7:17: 7:25 (#0) |