Add caching of external MIR in trans::collector

This commit is contained in:
Michael Woerister 2016-01-26 08:36:34 -05:00
parent 862911df9a
commit 9e969808e2
5 changed files with 87 additions and 46 deletions

View File

@ -25,7 +25,7 @@ use std::{iter, u32};
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
/// Lowered representation of a single function. /// Lowered representation of a single function.
#[derive(RustcEncodable, RustcDecodable)] #[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Mir<'tcx> { pub struct Mir<'tcx> {
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
/// that indexes into this vector. /// that indexes into this vector.
@ -146,7 +146,7 @@ pub enum BorrowKind {
// A "variable" is a binding declared by the user as part of the fn // A "variable" is a binding declared by the user as part of the fn
// decl, a let, etc. // decl, a let, etc.
#[derive(RustcEncodable, RustcDecodable)] #[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct VarDecl<'tcx> { pub struct VarDecl<'tcx> {
pub mutability: Mutability, pub mutability: Mutability,
pub name: Name, pub name: Name,
@ -155,7 +155,7 @@ pub struct VarDecl<'tcx> {
// A "temp" is a temporary that we place on the stack. They are // A "temp" is a temporary that we place on the stack. They are
// anonymous, always mutable, and have only a type. // anonymous, always mutable, and have only a type.
#[derive(RustcEncodable, RustcDecodable)] #[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct TempDecl<'tcx> { pub struct TempDecl<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
} }
@ -171,7 +171,7 @@ pub struct TempDecl<'tcx> {
// //
// there is only one argument, of type `(i32, u32)`, but two bindings // there is only one argument, of type `(i32, u32)`, but two bindings
// (`x` and `y`). // (`x` and `y`).
#[derive(RustcEncodable, RustcDecodable)] #[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct ArgDecl<'tcx> { pub struct ArgDecl<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
} }
@ -207,14 +207,14 @@ impl Debug for BasicBlock {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// BasicBlock and Terminator // BasicBlock and Terminator
#[derive(Debug, RustcEncodable, RustcDecodable)] #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> { pub struct BasicBlockData<'tcx> {
pub statements: Vec<Statement<'tcx>>, pub statements: Vec<Statement<'tcx>>,
pub terminator: Option<Terminator<'tcx>>, pub terminator: Option<Terminator<'tcx>>,
pub is_cleanup: bool, pub is_cleanup: bool,
} }
#[derive(RustcEncodable, RustcDecodable)] #[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum Terminator<'tcx> { pub enum Terminator<'tcx> {
/// block should have one successor in the graph; we jump there /// block should have one successor in the graph; we jump there
Goto { Goto {
@ -481,13 +481,13 @@ impl<'tcx> Terminator<'tcx> {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Statements // Statements
#[derive(RustcEncodable, RustcDecodable)] #[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Statement<'tcx> { pub struct Statement<'tcx> {
pub span: Span, pub span: Span,
pub kind: StatementKind<'tcx>, pub kind: StatementKind<'tcx>,
} }
#[derive(Debug, RustcEncodable, RustcDecodable)] #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum StatementKind<'tcx> { pub enum StatementKind<'tcx> {
Assign(Lvalue<'tcx>, Rvalue<'tcx>), Assign(Lvalue<'tcx>, Rvalue<'tcx>),
Drop(DropKind, Lvalue<'tcx>), Drop(DropKind, Lvalue<'tcx>),

View File

@ -2110,6 +2110,10 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn record_translation_item_as_generated<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn record_translation_item_as_generated<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
node_id: ast::NodeId, node_id: ast::NodeId,
param_substs: &'tcx Substs<'tcx>) { param_substs: &'tcx Substs<'tcx>) {
if !collector::collecting_debug_information(ccx) {
return;
}
let def_id = match ccx.tcx().node_id_to_type(node_id).sty { let def_id = match ccx.tcx().node_id_to_type(node_id).sty {
ty::TyClosure(def_id, _) => def_id, ty::TyClosure(def_id, _) => def_id,
_ => ccx.external_srcs() _ => ccx.external_srcs()

View File

@ -217,6 +217,7 @@ use trans::monomorphize;
use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap}; use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::rc::Rc;
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum TransItemCollectionMode { pub enum TransItemCollectionMode {
@ -281,9 +282,14 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("Building translation item graph, beginning at roots"); debug!("Building translation item graph, beginning at roots");
let mut visited = FnvHashSet(); let mut visited = FnvHashSet();
let mut recursion_depths = DefIdMap(); let mut recursion_depths = DefIdMap();
let mut mir_cache = DefIdMap();
for root in roots { for root in roots {
collect_items_rec(ccx, root, &mut visited, &mut recursion_depths); collect_items_rec(ccx,
root,
&mut visited,
&mut recursion_depths,
&mut mir_cache);
} }
visited visited
@ -313,11 +319,27 @@ fn collect_roots<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
roots roots
} }
#[derive(Clone)]
enum CachedMir<'mir, 'tcx: 'mir> {
Ref(&'mir mir::Mir<'tcx>),
Owned(Rc<mir::Mir<'tcx>>)
}
impl<'mir, 'tcx: 'mir> CachedMir<'mir, 'tcx> {
fn get_ref<'a>(&'a self) -> &'a mir::Mir<'tcx> {
match *self {
CachedMir::Ref(r) => r,
CachedMir::Owned(ref rc) => &**rc,
}
}
}
// Collect all monomorphized translation items reachable from `starting_point` // Collect all monomorphized translation items reachable from `starting_point`
fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
starting_point: TransItem<'tcx>, starting_point: TransItem<'tcx>,
visited: &mut FnvHashSet<TransItem<'tcx>>, visited: &mut FnvHashSet<TransItem<'tcx>>,
recursion_depths: &mut DefIdMap<usize>) { recursion_depths: &mut DefIdMap<usize>,
mir_cache: &mut DefIdMap<CachedMir<'a, 'tcx>>) {
if !visited.insert(starting_point.clone()) { if !visited.insert(starting_point.clone()) {
// We've been here already, no need to search again. // We've been here already, no need to search again.
return; return;
@ -343,42 +365,21 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
// Scan the MIR in order to find function calls, closures, and // Scan the MIR in order to find function calls, closures, and
// drop-glue // drop-glue
let mir_not_found_error_message = || { let mir = load_mir(ccx, def_id, mir_cache);
format!("Could not find MIR for function: {}",
ccx.tcx().item_path_str(def_id))
};
let external_mir = if !def_id.is_local() {
ccx.sess().cstore.maybe_get_item_mir(ccx.tcx(), def_id)
} else {
None
};
let mir_opt = match external_mir {
Some(ref mir) => Some(mir),
None => {
let node_id = ccx.tcx().map.as_local_node_id(def_id).unwrap();
ccx.mir_map().get(&node_id)
}
};
let mir = errors::expect(ccx.sess().diagnostic(),
mir_opt,
mir_not_found_error_message);
let mut visitor = MirNeighborCollector { let mut visitor = MirNeighborCollector {
ccx: ccx, ccx: ccx,
mir: mir, mir: mir.get_ref(),
output: &mut neighbors, output: &mut neighbors,
param_substs: param_substs param_substs: param_substs
}; };
visitor.visit_mir(mir); visitor.visit_mir(mir.get_ref());
} }
} }
for neighbour in neighbors { for neighbour in neighbors {
collect_items_rec(ccx, neighbour, visited, recursion_depths); collect_items_rec(ccx, neighbour, visited, recursion_depths, mir_cache);
} }
if let Some((def_id, depth)) = recursion_depth_reset { if let Some((def_id, depth)) = recursion_depth_reset {
@ -388,6 +389,37 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
debug!("END collect_items_rec({})", starting_point.to_string(ccx)); debug!("END collect_items_rec({})", starting_point.to_string(ccx));
} }
fn load_mir<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
def_id: DefId,
mir_cache: &mut DefIdMap<CachedMir<'a, 'tcx>>)
-> CachedMir<'a, 'tcx> {
let mir_not_found_error_message = || {
format!("Could not find MIR for function: {}",
ccx.tcx().item_path_str(def_id))
};
if def_id.is_local() {
let node_id = ccx.tcx().map.as_local_node_id(def_id).unwrap();
let mir_opt = ccx.mir_map().get(&node_id);
let mir = errors::expect(ccx.sess().diagnostic(),
mir_opt,
mir_not_found_error_message);
CachedMir::Ref(mir)
} else {
if let Some(mir) = mir_cache.get(&def_id) {
return mir.clone();
}
let mir_opt = ccx.sess().cstore.maybe_get_item_mir(ccx.tcx(), def_id);
let mir = errors::expect(ccx.sess().diagnostic(),
mir_opt,
mir_not_found_error_message);
let cached = CachedMir::Owned(Rc::new(mir));
mir_cache.insert(def_id, cached.clone());
cached
}
}
fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
def_id: DefId, def_id: DefId,
recursion_depths: &mut DefIdMap<usize>) recursion_depths: &mut DefIdMap<usize>)
@ -1488,14 +1520,15 @@ pub enum TransItemState {
NotPredictedButGenerated, NotPredictedButGenerated,
} }
pub fn collecting_debug_information(ccx: &CrateContext) -> bool {
return cfg!(debug_assertions) &&
ccx.sess().opts.debugging_opts.print_trans_items.is_some();
}
pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
use std::hash::{Hash, SipHasher, Hasher}; use std::hash::{Hash, SipHasher, Hasher};
if !cfg!(debug_assertions) { if !collecting_debug_information(ccx) {
return;
}
if ccx.sess().opts.debugging_opts.print_trans_items.is_none() {
return; return;
} }

View File

@ -30,7 +30,7 @@ use middle::def::Def;
use middle::def_id::DefId; use middle::def_id::DefId;
use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt}; use trans::base::{self, push_ctxt};
use trans::collector::TransItem; use trans::collector::{self, TransItem};
use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt}; use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}; use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
use trans::common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint}; use trans::common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint};
@ -1018,7 +1018,9 @@ pub fn trans_static(ccx: &CrateContext,
attrs: &[ast::Attribute]) attrs: &[ast::Attribute])
-> Result<ValueRef, ConstEvalErr> { -> Result<ValueRef, ConstEvalErr> {
ccx.record_translation_item_as_generated(TransItem::Static(id)); if collector::collecting_debug_information(ccx) {
ccx.record_translation_item_as_generated(TransItem::Static(id));
}
unsafe { unsafe {
let _icx = push_ctxt("trans_static"); let _icx = push_ctxt("trans_static");

View File

@ -28,7 +28,7 @@ use trans::build::*;
use trans::callee; use trans::callee;
use trans::cleanup; use trans::cleanup;
use trans::cleanup::CleanupMethods; use trans::cleanup::CleanupMethods;
use trans::collector::TransItem; use trans::collector::{self, TransItem};
use trans::common::*; use trans::common::*;
use trans::debuginfo::DebugLoc; use trans::debuginfo::DebugLoc;
use trans::declare; use trans::declare;
@ -498,9 +498,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
-> Block<'blk, 'tcx> { -> Block<'blk, 'tcx> {
let t = g.ty(); let t = g.ty();
bcx.ccx() if collector::collecting_debug_information(bcx.ccx()) {
.record_translation_item_as_generated(TransItem::DropGlue(bcx.tcx() bcx.ccx()
.erase_regions(&t))); .record_translation_item_as_generated(TransItem::DropGlue(bcx.tcx()
.erase_regions(&t)));
}
let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true }; let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true };
// NB: v0 is an *alias* of type t here, not a direct value. // NB: v0 is an *alias* of type t here, not a direct value.