Skip to content

Commit

Permalink
Auto merge of #52115 - Dylan-DPC:feature/nll-liveness-regions, r=niko…
Browse files Browse the repository at this point in the history
…matsakis

only compute liveness for variables whose types include regions

Closes #52034

r? @nikomatsakis
  • Loading branch information
bors committed Jul 21, 2018
2 parents d941658 + 0770ff0 commit 874dec2
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 357 deletions.
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.

//! 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

0 comments on commit 874dec2

Please sign in to comment.