Skip to content

only compute liveness for variables whose types include regions #52115

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 16 commits into from
Jul 21, 2018
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
77 changes: 77 additions & 0 deletions src/librustc_mir/borrow_check/nll/liveness_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a module doc comment here explaining what is going on. Something like this:


For the NLL computation, we need to compute liveness, but only for those local variables whose types contain regions. The others are not of interest to us. This file defines a new index type (LocalWithRegion) that indexes into a list of "variables whose type contain regions". It also defines a map from Local to LocalWithRegion and vice versa -- this map can be given to the liveness code so that it only operates over variables with regions in their types, instead of all variables.

//! For the NLL computation, we need to compute liveness, but only for those
//! local variables whose types contain regions. The others are not of interest
//! to us. This file defines a new index type (LocalWithRegion) that indexes into
//! a list of "variables whose type contain regions". It also defines a map from
//! Local to LocalWithRegion and vice versa -- this map can be given to the
//! liveness code so that it only operates over variables with regions in their
//! types, instead of all variables.

use rustc::ty::TypeFoldable;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::mir::{Mir, Local};
use util::liveness::LiveVariableMap;

use rustc_data_structures::indexed_vec::Idx;

/// Map between Local and LocalWithRegion indices: this map is supplied to the
/// liveness code so that it will only analyze those variables whose types
/// contain regions.
crate struct NllLivenessMap {
/// For each local variable, contains either None (if the type has no regions)
/// or Some(i) with a suitable index.
pub from_local: IndexVec<Local, Option<LocalWithRegion>>,
/// For each LocalWithRegion, maps back to the original Local index.
pub to_local: IndexVec<LocalWithRegion, Local>,

}

impl LiveVariableMap for NllLivenessMap {

fn from_local(&self, local: Local) -> Option<Self::LiveVar> {
self.from_local[local]
}

type LiveVar = LocalWithRegion;

fn from_live_var(&self, local: Self::LiveVar) -> Local {
self.to_local[local]
}

fn num_variables(&self) -> usize {
self.to_local.len()
}
}

impl NllLivenessMap {
/// Iterates over the variables in Mir and assigns each Local whose type contains
/// regions a LocalWithRegion index. Returns a map for converting back and forth.
pub fn compute(mir: &Mir) -> Self {
let mut to_local = IndexVec::default();
let from_local: IndexVec<Local,Option<_>> = mir
.local_decls
.iter_enumerated()
.map(|(local, local_decl)| {
if local_decl.ty.has_free_regions() {
Some(to_local.push(local))
}
else {
None
}
}).collect();

Self { from_local, to_local }
}
}

/// Index given to each local variable whose type contains a region.
newtype_index!(LocalWithRegion);
22 changes: 15 additions & 7 deletions src/librustc_mir/borrow_check/nll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ 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 borrow_check::nll::liveness_map::{NllLivenessMap, LocalWithRegion};
use dataflow::indexes::BorrowIndex;
use dataflow::move_paths::MoveData;
use dataflow::FlowAtLocation;
Expand All @@ -30,7 +31,7 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
use transform::MirSource;
use util::liveness::{LivenessResults, LocalSet};
use util::liveness::{LivenessResults, LiveVarSet};

use self::mir_util::PassWhere;
use polonius_engine::{Algorithm, Output};
Expand All @@ -45,6 +46,7 @@ crate mod region_infer;
mod renumber;
crate mod type_check;
mod universal_regions;
crate mod liveness_map;

mod constraints;

Expand Down Expand Up @@ -103,7 +105,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
let elements = &Rc::new(RegionValueElements::new(mir, universal_regions.len()));

// Run the MIR type-checker.
let liveness = &LivenessResults::compute(mir);
let liveness_map = NllLivenessMap::compute(&mir);
let liveness = LivenessResults::compute(mir, &liveness_map);
let constraint_sets = type_check::type_check(
infcx,
param_env,
Expand Down Expand Up @@ -193,7 +196,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
// write unit-tests, as well as helping with debugging.
dump_mir_results(
infcx,
liveness,
&liveness,
MirSource::item(def_id),
&mir,
&regioncx,
Expand All @@ -209,7 +212,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(

fn dump_mir_results<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
liveness: &LivenessResults,
liveness: &LivenessResults<LocalWithRegion>,
source: MirSource,
mir: &Mir<'tcx>,
regioncx: &RegionInferenceContext,
Expand All @@ -219,14 +222,16 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
return;
}

let map = &NllLivenessMap::compute(mir);

let regular_liveness_per_location: FxHashMap<_, _> = mir
.basic_blocks()
.indices()
.flat_map(|bb| {
let mut results = vec![];
liveness
.regular
.simulate_block(&mir, bb, |location, local_set| {
.simulate_block(&mir, bb, map, |location, local_set| {
results.push((location, local_set.clone()));
});
results
Expand All @@ -240,7 +245,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
let mut results = vec![];
liveness
.drop
.simulate_block(&mir, bb, |location, local_set| {
.simulate_block(&mir, bb, map, |location, local_set| {
results.push((location, local_set.clone()));
});
results
Expand Down Expand Up @@ -405,7 +410,10 @@ impl ToRegionVid for RegionVid {
}
}

fn live_variable_set(regular: &LocalSet, drops: &LocalSet) -> String {
fn live_variable_set(
regular: &LiveVarSet<LocalWithRegion>,
drops: &LiveVarSet<LocalWithRegion>
) -> String {
// sort and deduplicate:
let all_locals: BTreeSet<_> = regular.iter().chain(drops.iter()).collect();

Expand Down
27 changes: 16 additions & 11 deletions src/librustc_mir/borrow_check/nll/type_check/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use borrow_check::nll::{NllLivenessMap, LocalWithRegion};
use borrow_check::nll::type_check::AtLocation;
use dataflow::move_paths::{HasMoveData, MoveData};
use dataflow::MaybeInitializedPlaces;
use dataflow::{FlowAtLocation, FlowsAtLocation};
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::mir::Local;
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
use rustc::traits::query::type_op::outlives::DropckOutlives;
use rustc::traits::query::type_op::TypeOp;
use rustc::ty::{Ty, TypeFoldable};
use rustc_data_structures::fx::FxHashMap;
use std::rc::Rc;
use util::liveness::LivenessResults;
use util::liveness::{LivenessResults, LiveVariableMap };

use super::TypeChecker;

Expand All @@ -36,7 +36,7 @@ use super::TypeChecker;
pub(super) fn generate<'gcx, 'tcx>(
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
liveness: &LivenessResults,
liveness: &LivenessResults<LocalWithRegion>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
Expand All @@ -47,6 +47,7 @@ pub(super) fn generate<'gcx, 'tcx>(
flow_inits,
move_data,
drop_data: FxHashMap(),
map: &NllLivenessMap::compute(mir),
};

for bb in mir.basic_blocks().indices() {
Expand All @@ -63,10 +64,11 @@ where
{
cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
mir: &'gen Mir<'tcx>,
liveness: &'gen LivenessResults,
liveness: &'gen LivenessResults<LocalWithRegion>,
flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
move_data: &'gen MoveData<'tcx>,
drop_data: FxHashMap<Ty<'tcx>, DropData<'tcx>>,
map: &'gen NllLivenessMap,
}

struct DropData<'tcx> {
Expand All @@ -84,17 +86,18 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo

self.liveness
.regular
.simulate_block(self.mir, bb, |location, live_locals| {
.simulate_block(self.mir, bb, self.map, |location, live_locals| {
for live_local in live_locals.iter() {
let live_local_ty = self.mir.local_decls[live_local].ty;
let local = self.map.from_live_var(live_local);
let live_local_ty = self.mir.local_decls[local].ty;
Self::push_type_live_constraint(&mut self.cx, live_local_ty, location);
}
});

let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
let mut all_live_locals: Vec<(Location, Vec<LocalWithRegion>)> = vec![];
self.liveness
.drop
.simulate_block(self.mir, bb, |location, live_locals| {
.simulate_block(self.mir, bb, self.map, |location, live_locals| {
all_live_locals.push((location, live_locals.iter().collect()));
});
debug!(
Expand All @@ -121,15 +124,17 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
});
}

let mpi = self.move_data.rev_lookup.find_local(live_local);
let local = self.map.from_live_var(live_local);
let mpi = self.move_data.rev_lookup.find_local(local);
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
debug!(
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
self.move_data.move_paths[mpi],
self.move_data.move_paths[initialized_child]
);

let live_local_ty = self.mir.local_decls[live_local].ty;
let local = self.map.from_live_var(live_local);
let live_local_ty = self.mir.local_decls[local].ty;
self.add_drop_live_constraint(live_local, live_local_ty, location);
}
}
Expand Down Expand Up @@ -190,7 +195,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
/// particular this takes `#[may_dangle]` into account.
fn add_drop_live_constraint(
&mut self,
dropped_local: Local,
dropped_local: LocalWithRegion,
dropped_ty: Ty<'tcx>,
location: Location,
) {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ 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 borrow_check::nll::LocalWithRegion;
use dataflow::move_paths::MoveData;
use dataflow::FlowAtLocation;
use dataflow::MaybeInitializedPlaces;
Expand Down Expand Up @@ -109,7 +110,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
universal_regions: &UniversalRegions<'tcx>,
location_table: &LocationTable,
borrow_set: &BorrowSet<'tcx>,
liveness: &LivenessResults,
liveness: &LivenessResults<LocalWithRegion>,
all_facts: &mut Option<AllFacts>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
Expand Down
41 changes: 26 additions & 15 deletions src/librustc_mir/transform/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
use rustc::ty::{self, TyCtxt, AdtDef, Ty};
use rustc::ty::subst::Substs;
use util::dump_mir;
use util::liveness::{self, LivenessMode};
use util::liveness::{self, IdentityMap, LivenessMode};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_set::IdxSetBuf;
use std::collections::HashMap;
Expand Down Expand Up @@ -130,7 +130,7 @@ struct SuspensionPoint {
state: u32,
resume: BasicBlock,
drop: Option<BasicBlock>,
storage_liveness: liveness::LocalSet,
storage_liveness: liveness::LiveVarSet<Local>,
}

struct TransformVisitor<'a, 'tcx: 'a> {
Expand All @@ -145,7 +145,7 @@ struct TransformVisitor<'a, 'tcx: 'a> {
remap: HashMap<Local, (Ty<'tcx>, usize)>,

// A map from a suspension point in a block to the locals which have live storage at that point
storage_liveness: HashMap<BasicBlock, liveness::LocalSet>,
storage_liveness: HashMap<BasicBlock, liveness::LiveVarSet<Local>>,

// A list of suspension points, generated during the transform
suspension_points: Vec<SuspensionPoint>,
Expand Down Expand Up @@ -317,7 +317,7 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
new_ret_local
}

struct StorageIgnored(liveness::LocalSet);
struct StorageIgnored(liveness::LiveVarSet<Local>);

impl<'tcx> Visitor<'tcx> for StorageIgnored {
fn visit_statement(&mut self,
Expand All @@ -332,7 +332,7 @@ impl<'tcx> Visitor<'tcx> for StorageIgnored {
}
}

struct BorrowedLocals(liveness::LocalSet);
struct BorrowedLocals(liveness::LiveVarSet<Local>);

fn mark_as_borrowed<'tcx>(place: &Place<'tcx>, locals: &mut BorrowedLocals) {
match *place {
Expand Down Expand Up @@ -361,12 +361,12 @@ impl<'tcx> Visitor<'tcx> for BorrowedLocals {
}
}

fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn locals_live_across_suspend_points<'a, 'tcx,>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
source: MirSource,
movable: bool) ->
(liveness::LocalSet,
HashMap<BasicBlock, liveness::LocalSet>) {
(liveness::LiveVarSet<Local>,
HashMap<BasicBlock, liveness::LiveVarSet<Local>>) {
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();

Expand Down Expand Up @@ -396,12 +396,23 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};

// Calculate the liveness of MIR locals ignoring borrows.
let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
let mut liveness = liveness::liveness_of_locals(mir, LivenessMode {
include_regular_use: true,
include_drops: true,
});
liveness::dump_mir(tcx, "generator_liveness", source, mir, &liveness);
let mut set = liveness::LiveVarSet::new_empty(mir.local_decls.len());
let mut liveness = liveness::liveness_of_locals(
mir,
LivenessMode {
include_regular_use: true,
include_drops: true,
},
&IdentityMap::new(mir),
);
liveness::dump_mir(
tcx,
"generator_liveness",
source,
mir,
&IdentityMap::new(mir),
&liveness,
);

let mut storage_liveness_map = HashMap::new();

Expand Down Expand Up @@ -468,7 +479,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &mut Mir<'tcx>)
-> (HashMap<Local, (Ty<'tcx>, usize)>,
GeneratorLayout<'tcx>,
HashMap<BasicBlock, liveness::LocalSet>)
HashMap<BasicBlock, liveness::LiveVarSet<Local>>)
{
// Use a liveness analysis to compute locals which are live across a suspension point
let (live_locals, storage_liveness) = locals_live_across_suspend_points(tcx,
Expand Down
Loading