Skip to content

[NLL] Remove LiveVar #58505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/librustc_mir/borrow_check/nll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::borrow_check::borrow_set::BorrowSet;
use crate::borrow_check::location::{LocationIndex, LocationTable};
use crate::borrow_check::nll::facts::AllFactsExt;
use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
use crate::borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap;
use crate::borrow_check::nll::region_infer::values::RegionValueElements;
use crate::dataflow::indexes::BorrowIndex;
use crate::dataflow::move_paths::MoveData;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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<LiveVar, Option<AppearanceIndex>>,
first_def_at: IndexVec<Local, Option<AppearanceIndex>>,

/// 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<LiveVar, Option<AppearanceIndex>>,
first_use_at: IndexVec<Local, Option<AppearanceIndex>>,

/// 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<LiveVar, Option<AppearanceIndex>>,
first_drop_at: IndexVec<Local, Option<AppearanceIndex>>,

appearances: IndexVec<AppearanceIndex, Appearance>,
}
Expand All @@ -50,52 +56,68 @@ impl vll::LinkElem for Appearance {
}
}

impl LocalUseMap<'me> {
impl LocalUseMap {
crate fn build(
liveness_map: &'me NllLivenessMap,
live_locals: &Vec<Local>,
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<Local, bool> =
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: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
crate fn defs(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
vll::iter(self.first_def_at[local], &self.appearances)
.map(move |aa| self.appearances[aa].point_index)
}

crate fn uses(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
crate fn uses(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
vll::iter(self.first_use_at[local], &self.appearances)
.map(move |aa| self.appearances[aa].point_index)
}

crate fn drops(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
crate fn drops(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
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<Local, bool>,
}

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],
Expand All @@ -104,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],
Expand All @@ -113,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],
Expand All @@ -137,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),
_ => (),
}
}
Expand Down
85 changes: 70 additions & 15 deletions src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use crate::borrow_check::location::LocationTable;
use crate::borrow_check::nll::region_infer::values::RegionValueElements;
use crate::borrow_check::nll::constraints::ConstraintSet;
use crate::borrow_check::nll::NllLivenessMap;
use crate::borrow_check::nll::facts::{AllFacts, AllFactsExt};
use crate::borrow_check::nll::region_infer::values::RegionValueElements;
use crate::borrow_check::nll::universal_regions::UniversalRegions;
use crate::borrow_check::nll::ToRegionVid;
use crate::dataflow::move_paths::MoveData;
use crate::dataflow::MaybeInitializedPlaces;
use crate::dataflow::FlowAtLocation;
use rustc::mir::Mir;
use rustc::ty::RegionVid;
use crate::dataflow::MaybeInitializedPlaces;
use rustc::mir::{Local, Mir};
use rustc::ty::{RegionVid, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use std::rc::Rc;

use super::TypeChecker;

crate mod liveness_map;
mod local_use_map;
mod trace;

Expand All @@ -34,16 +34,71 @@ pub(super) fn generate<'gcx, 'tcx>(
location_table: &LocationTable,
) {
debug!("liveness::generate");
let free_regions = {
let borrowck_context = typeck.borrowck_context.as_ref().unwrap();
regions_that_outlive_free_regions(
typeck.infcx.num_region_vars(),
&borrowck_context.universal_regions,
&borrowck_context.constraints.outlives_constraints,
)

let live_locals: Vec<Local> = if AllFacts::enabled(typeck.tcx()) {
// If "dump facts from NLL analysis" was requested perform
// the liveness analysis for all `Local`s. This case opens
// the possibility of the variables being analyzed in `trace`
// to be *any* `Local`, not just the "live" ones, so we can't
// make any assumptions past this point as to the characteristics
// of the `live_locals`.
// FIXME: Review "live" terminology past this point, we should
// not be naming the `Local`s as live.
mir.local_decls.indices().collect()
} else {
let free_regions = {
let borrowck_context = typeck.borrowck_context.as_ref().unwrap();
regions_that_outlive_free_regions(
typeck.infcx.num_region_vars(),
&borrowck_context.universal_regions,
&borrowck_context.constraints.outlives_constraints,
)
};
compute_live_locals(typeck.tcx(), &free_regions, mir)
};
let liveness_map = NllLivenessMap::compute(typeck.tcx(), &free_regions, mir);
trace::trace(typeck, mir, elements, flow_inits, move_data, &liveness_map, location_table);

if !live_locals.is_empty() {
trace::trace(
typeck,
mir,
elements,
flow_inits,
move_data,
live_locals,
location_table,
);
}
}

// The purpose of `compute_live_locals` is to define the subset of `Local`
// variables for which we need to do a liveness computation. We only need
// to compute whether a variable `X` is live if that variable contains
// some region `R` in its type where `R` is not known to outlive a free
// region (i.e., where `R` may be valid for just a subset of the fn body).
fn compute_live_locals(
tcx: TyCtxt<'_, '_, 'tcx>,
free_regions: &FxHashSet<RegionVid>,
mir: &Mir<'tcx>,
) -> Vec<Local> {
let live_locals: Vec<Local> = mir
.local_decls
.iter_enumerated()
.filter_map(|(local, local_decl)| {
if tcx.all_free_regions_meet(&local_decl.ty, |r| {
free_regions.contains(&r.to_region_vid())
}) {
None
} else {
Some(local)
}
})
.collect();

debug!("{} total variables", mir.local_decls.len());
debug!("{} variables need liveness", live_locals.len());
debug!("{} regions outlive free regions", free_regions.len());

live_locals
}

/// Computes all regions that are (currently) known to outlive free
Expand Down
Loading