diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index fccd633aaa1e..9b8940098852 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -1,6 +1,5 @@ use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements}; -use crate::borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap}; -use crate::util::liveness::{categorize, DefUse, LiveVariableMap}; +use crate::util::liveness::{categorize, DefUse}; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::{Local, Location, Mir}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -9,26 +8,33 @@ use rustc_data_structures::vec_linked_list as vll; /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness /// computation. -crate struct LocalUseMap<'me> { - liveness_map: &'me NllLivenessMap, - +/// +/// We keep track only of `Local`s we'll do the liveness analysis later, +/// this means that our internal `IndexVec`s will only be sparsely populated. +/// In the time-memory trade-off between keeping compact vectors with new +/// indexes (and needing to continuously map the `Local` index to its compact +/// counterpart) and having `IndexVec`s that we only use a fraction of, time +/// (and code simplicity) was favored. The rationale is that we only keep +/// a small number of `IndexVec`s throughout the entire analysis while, in +/// contrast, we're accessing each `Local` *many* times. +crate struct LocalUseMap { /// Head of a linked list of **definitions** of each variable -- /// definition in this context means assignment, e.g., `x` is /// defined in `x = y` but not `y`; that first def is the head of /// a linked list that lets you enumerate all places the variable /// is assigned. - first_def_at: IndexVec>, + first_def_at: IndexVec>, /// Head of a linked list of **uses** of each variable -- use in /// this context means that the existing value of the variable is /// read or modified. e.g., `y` is used in `x = y` but not `x`. /// Note that `DROP(x)` terminators are excluded from this list. - first_use_at: IndexVec>, + first_use_at: IndexVec>, /// Head of a linked list of **drops** of each variable -- these /// are a special category of uses corresponding to the drop that /// we add for each local variable. - first_drop_at: IndexVec>, + first_drop_at: IndexVec>, appearances: IndexVec, } @@ -50,55 +56,68 @@ impl vll::LinkElem for Appearance { } } -impl LocalUseMap<'me> { +impl LocalUseMap { crate fn build( - liveness_map: &'me NllLivenessMap, + live_locals: &Vec, elements: &RegionValueElements, mir: &Mir<'_>, ) -> Self { - let nones = IndexVec::from_elem_n(None, liveness_map.num_variables()); + let nones = IndexVec::from_elem_n(None, mir.local_decls.len()); let mut local_use_map = LocalUseMap { - liveness_map, first_def_at: nones.clone(), first_use_at: nones.clone(), first_drop_at: nones, appearances: IndexVec::new(), }; + let mut locals_with_use_data: IndexVec = + IndexVec::from_elem_n(false, mir.local_decls.len()); + live_locals + .iter() + .for_each(|&local| locals_with_use_data[local] = true); + LocalUseMapBuild { local_use_map: &mut local_use_map, elements, - }.visit_mir(mir); + locals_with_use_data, + } + .visit_mir(mir); local_use_map } crate fn defs(&self, local: Local) -> impl Iterator + '_ { - let live_var = self.liveness_map.from_local(local).unwrap(); - vll::iter(self.first_def_at[live_var], &self.appearances) + vll::iter(self.first_def_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } crate fn uses(&self, local: Local) -> impl Iterator + '_ { - let live_var = self.liveness_map.from_local(local).unwrap(); - vll::iter(self.first_use_at[live_var], &self.appearances) + vll::iter(self.first_use_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } crate fn drops(&self, local: Local) -> impl Iterator + '_ { - let live_var = self.liveness_map.from_local(local).unwrap(); - vll::iter(self.first_drop_at[live_var], &self.appearances) + vll::iter(self.first_drop_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } } -struct LocalUseMapBuild<'me, 'map: 'me> { - local_use_map: &'me mut LocalUseMap<'map>, +struct LocalUseMapBuild<'me> { + local_use_map: &'me mut LocalUseMap, elements: &'me RegionValueElements, + + // Vector used in `visit_local` to signal which `Local`s do we need + // def/use/drop information on, constructed from `live_locals` (that + // contains the variables we'll do the liveness analysis for). + // This vector serves optimization purposes only: we could have + // obtained the same information from `live_locals` but we want to + // avoid repeatedly calling `Vec::contains()` (see `LocalUseMap` for + // the rationale on the time-memory trade-off we're favoring here). + locals_with_use_data: IndexVec, } -impl LocalUseMapBuild<'_, '_> { - fn insert_def(&mut self, local: LiveVar, location: Location) { +impl LocalUseMapBuild<'_> { + fn insert_def(&mut self, local: Local, location: Location) { Self::insert( self.elements, &mut self.local_use_map.first_def_at[local], @@ -107,7 +126,7 @@ impl LocalUseMapBuild<'_, '_> { ); } - fn insert_use(&mut self, local: LiveVar, location: Location) { + fn insert_use(&mut self, local: Local, location: Location) { Self::insert( self.elements, &mut self.local_use_map.first_use_at[local], @@ -116,7 +135,7 @@ impl LocalUseMapBuild<'_, '_> { ); } - fn insert_drop(&mut self, local: LiveVar, location: Location) { + fn insert_drop(&mut self, local: Local, location: Location) { Self::insert( self.elements, &mut self.local_use_map.first_drop_at[local], @@ -140,13 +159,13 @@ impl LocalUseMapBuild<'_, '_> { } } -impl Visitor<'tcx> for LocalUseMapBuild<'_, '_> { +impl Visitor<'tcx> for LocalUseMapBuild<'_> { fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, location: Location) { - if let Some(local_with_region) = self.local_use_map.liveness_map.from_local(local) { + if self.locals_with_use_data[local] { match categorize(context) { - Some(DefUse::Def) => self.insert_def(local_with_region, location), - Some(DefUse::Use) => self.insert_use(local_with_region, location), - Some(DefUse::Drop) => self.insert_drop(local_with_region, location), + Some(DefUse::Def) => self.insert_def(local, location), + Some(DefUse::Use) => self.insert_use(local, location), + Some(DefUse::Drop) => self.insert_drop(local, location), _ => (), } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 67dcf255f567..4950d0045d3f 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -46,7 +46,8 @@ pub(super) fn trace( return; } - let local_use_map = &LocalUseMap::build(liveness_map, elements, mir); + let live_locals: Vec = liveness_map.to_local.clone().into_iter().collect(); + let local_use_map = &LocalUseMap::build(&live_locals, elements, mir); let cx = LivenessContext { typeck, @@ -59,7 +60,6 @@ pub(super) fn trace( location_table, }; - let live_locals: Vec = liveness_map.to_local.clone().into_iter().collect(); LivenessResults::new(cx).compute_for_all_locals(live_locals); } @@ -92,7 +92,7 @@ where /// Index indicating where each variable is assigned, used, or /// dropped. - local_use_map: &'me LocalUseMap<'me>, + local_use_map: &'me LocalUseMap, /// Maps between a MIR Location and a LocationIndex location_table: &'me LocationTable,