Skip to content

Commit

Permalink
trans: Collect all accesses between trans-items, not just inlining ed…
Browse files Browse the repository at this point in the history
…ges.
  • Loading branch information
michaelwoerister committed Jul 12, 2017
1 parent 8bba5ad commit 1ebfab5
Showing 1 changed file with 105 additions and 29 deletions.
134 changes: 105 additions & 29 deletions src/librustc_trans/collector.rs
Expand Up @@ -208,6 +208,8 @@ use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};

use trans_item::{TransItem, DefPathBasedNames, InstantiationMode};

use rustc_data_structures::bitvec::BitVector;

#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum TransItemCollectionMode {
Eager,
Expand All @@ -217,12 +219,16 @@ pub enum TransItemCollectionMode {
/// Maps every translation item to all translation items it references in its
/// body.
pub struct InliningMap<'tcx> {
// Maps a source translation item to a range of target translation items
// that are potentially inlined by LLVM into the source.
// Maps a source translation item to the range of translation items
// accessed by it.
// The two numbers in the tuple are the start (inclusive) and
// end index (exclusive) within the `targets` vecs.
index: FxHashMap<TransItem<'tcx>, (usize, usize)>,
targets: Vec<TransItem<'tcx>>,

// Contains one bit per translation item in the `targets` field. That bit
// is true if that translation item needs to be inlined into every CGU.
inlines: BitVector,
}

impl<'tcx> InliningMap<'tcx> {
Expand All @@ -231,33 +237,61 @@ impl<'tcx> InliningMap<'tcx> {
InliningMap {
index: FxHashMap(),
targets: Vec::new(),
inlines: BitVector::new(1024),
}
}

fn record_inlining_canditates<I>(&mut self,
source: TransItem<'tcx>,
targets: I)
where I: Iterator<Item=TransItem<'tcx>>
fn record_accesses<I>(&mut self,
source: TransItem<'tcx>,
targets: I)
where I: Iterator<Item=(TransItem<'tcx>, bool)>
{
assert!(!self.index.contains_key(&source));

let start_index = self.targets.len();
self.targets.extend(targets);
let (targets_size_hint, targets_size_hint_max) = targets.size_hint();
debug_assert_eq!(targets_size_hint_max, Some(targets_size_hint));
let new_items_count = targets_size_hint;
let new_items_count_total = new_items_count + self.targets.len();

self.targets.reserve(new_items_count);
self.inlines.grow(new_items_count_total);

for (i, (target, inline)) in targets.enumerate() {
self.targets.push(target);
if inline {
self.inlines.insert(i + start_index);
}
}

let end_index = self.targets.len();
self.index.insert(source, (start_index, end_index));
}

// Internally iterate over all items referenced by `source` which will be
// made available for inlining.
pub fn with_inlining_candidates<F>(&self, source: TransItem<'tcx>, mut f: F)
where F: FnMut(TransItem<'tcx>) {
if let Some(&(start_index, end_index)) = self.index.get(&source)
{
for candidate in &self.targets[start_index .. end_index] {
f(*candidate)
where F: FnMut(TransItem<'tcx>)
{
if let Some(&(start_index, end_index)) = self.index.get(&source) {
for (i, candidate) in self.targets[start_index .. end_index]
.iter()
.enumerate() {
if self.inlines.contains(start_index + i) {
f(*candidate);
}
}
}
}

// Internally iterate over all items and the things each accesses.
pub fn iter_accesses<F>(&self, mut f: F)
where F: FnMut(TransItem<'tcx>, &[TransItem<'tcx>])
{
for (&accessor, &(start_index, end_index)) in &self.index {
f(accessor, &self.targets[start_index .. end_index])
}
}
}

pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
Expand Down Expand Up @@ -340,7 +374,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,

recursion_depth_reset = None;

collect_neighbours(scx, instance, &mut neighbors);
collect_neighbours(scx, instance, true, &mut neighbors);
}
TransItem::Fn(instance) => {
// Sanity check whether this ended up being collected accidentally
Expand All @@ -352,14 +386,14 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
recursion_depths));
check_type_length_limit(scx.tcx(), instance);

collect_neighbours(scx, instance, &mut neighbors);
collect_neighbours(scx, instance, false, &mut neighbors);
}
TransItem::GlobalAsm(..) => {
recursion_depth_reset = None;
}
}

record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map);
record_accesses(scx.tcx(), starting_point, &neighbors[..], inlining_map);

for neighbour in neighbors {
collect_items_rec(scx, neighbour, visited, recursion_depths, inlining_map);
Expand All @@ -372,19 +406,20 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx()));
}

fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
caller: TransItem<'tcx>,
callees: &[TransItem<'tcx>],
inlining_map: &mut InliningMap<'tcx>) {
let is_inlining_candidate = |trans_item: &TransItem<'tcx>| {
trans_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy
};

let inlining_candidates = callees.into_iter()
.map(|x| *x)
.filter(is_inlining_candidate);
let accesses = callees.into_iter()
.map(|trans_item| {
(*trans_item, is_inlining_candidate(trans_item))
});

inlining_map.record_inlining_canditates(caller, inlining_candidates);
inlining_map.record_accesses(caller, accesses);
}

fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Expand Down Expand Up @@ -459,7 +494,8 @@ struct MirNeighborCollector<'a, 'tcx: 'a> {
scx: &'a SharedCrateContext<'a, 'tcx>,
mir: &'a mir::Mir<'tcx>,
output: &'a mut Vec<TransItem<'tcx>>,
param_substs: &'tcx Substs<'tcx>
param_substs: &'tcx Substs<'tcx>,
const_context: bool,
}

impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
Expand Down Expand Up @@ -540,7 +576,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs,
&substs);
let instance = monomorphize::resolve(self.scx, def_id, substs);
collect_neighbours(self.scx, instance, self.output);
collect_neighbours(self.scx, instance, true, self.output);
}

self.super_constant(constant, location);
Expand All @@ -556,8 +592,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
match *kind {
mir::TerminatorKind::Call { ref func, .. } => {
let callee_ty = func.ty(self.mir, tcx);
let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
visit_fn_use(self.scx, callee_ty, true, &mut self.output);

let skip_const = self.const_context && match callee_ty.sty {
ty::TyFnDef(def_id, _) => self.scx.tcx().is_const_fn(def_id),
_ => false
};

if !skip_const {
let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
visit_fn_use(self.scx, callee_ty, true, &mut self.output);
}
}
mir::TerminatorKind::Drop { ref location, .. } |
mir::TerminatorKind::DropAndReplace { ref location, .. } => {
Expand All @@ -576,6 +620,22 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {

self.super_terminator_kind(block, kind, location);
}

fn visit_static(&mut self,
static_: &mir::Static<'tcx>,
context: mir::visit::LvalueContext<'tcx>,
location: Location) {
debug!("visiting static {:?} @ {:?}", static_.def_id, location);

let tcx = self.scx.tcx();
let instance = Instance::mono(tcx, static_.def_id);
if should_trans_locally(tcx, &instance) {
let node_id = tcx.hir.as_local_node_id(static_.def_id).unwrap();
self.output.push(TransItem::Static(node_id));
}

self.super_static(static_, context, location);
}
}

fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
Expand Down Expand Up @@ -850,8 +910,14 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
// const items only generate translation items if they are
// actually used somewhere. Just declaring them is insufficient.
}
hir::ItemFn(.., ref generics, _) => {
if !generics.is_type_parameterized() {
hir::ItemFn(_, _, constness, _, ref generics, _) => {
let is_const = match constness {
hir::Constness::Const => true,
hir::Constness::NotConst => false,
};

if !generics.is_type_parameterized() &&
(!is_const || self.mode == TransItemCollectionMode::Eager) {
let def_id = self.scx.tcx().hir.local_def_id(item.id);

debug!("RootCollector: ItemFn({})",
Expand All @@ -872,12 +938,13 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Method(hir::MethodSig {
constness,
ref generics,
..
}, _) => {
let hir_map = &self.scx.tcx().hir;
let parent_node_id = hir_map.get_parent_node(ii.id);
let is_impl_generic = match hir_map.expect_item(parent_node_id) {
let is_impl_generic = || match hir_map.expect_item(parent_node_id) {
&hir::Item {
node: hir::ItemImpl(_, _, _, ref generics, ..),
..
Expand All @@ -889,7 +956,14 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
}
};

if !generics.is_type_parameterized() && !is_impl_generic {
let is_const = match constness {
hir::Constness::Const => true,
hir::Constness::NotConst => false,
};

if (!is_const || self.mode == TransItemCollectionMode::Eager) &&
!generics.is_type_parameterized() &&
!is_impl_generic() {
let def_id = self.scx.tcx().hir.local_def_id(ii.id);

debug!("RootCollector: MethodImplItem({})",
Expand Down Expand Up @@ -958,6 +1032,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
/// Scan the MIR in order to find function calls, closures, and drop-glue
fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
instance: Instance<'tcx>,
const_context: bool,
output: &mut Vec<TransItem<'tcx>>)
{
let mir = scx.tcx().instance_mir(instance.def);
Expand All @@ -966,7 +1041,8 @@ fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
scx: scx,
mir: &mir,
output: output,
param_substs: instance.substs
param_substs: instance.substs,
const_context,
};

visitor.visit_mir(&mir);
Expand Down

0 comments on commit 1ebfab5

Please sign in to comment.