track MIR through the dep-graph

Per the discussion on #34765, we make one `DepNode::Mir` variant and use
it to represent both the MIR tracking map as well as passes that operate
on MIR. We also track loads of cached MIR (which naturally comes from
metadata).

Note that the "HAIR" pass adds a read of TypeckItemBody because it uses
a myriad of tables that are not individually tracked.
This commit is contained in:
Niko Matsakis 2016-08-08 18:42:06 -04:00
parent 88b2e9a66d
commit 8fdc72f830
14 changed files with 127 additions and 56 deletions

View File

@ -82,9 +82,11 @@ pub enum DepNode<D: Clone + Debug> {
Privacy,
IntrinsicCheck(D),
MatchCheck(D),
MirMapConstruction(D),
MirPass(D),
MirTypeck(D),
// Represents the MIR for a fn; also used as the task node for
// things read/modify that MIR.
Mir(D),
BorrowCheck(D),
RvalueCheck(D),
Reachability,
@ -214,9 +216,7 @@ impl<D: Clone + Debug> DepNode<D> {
CheckConst(ref d) => op(d).map(CheckConst),
IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
MatchCheck(ref d) => op(d).map(MatchCheck),
MirMapConstruction(ref d) => op(d).map(MirMapConstruction),
MirPass(ref d) => op(d).map(MirPass),
MirTypeck(ref d) => op(d).map(MirTypeck),
Mir(ref d) => op(d).map(Mir),
BorrowCheck(ref d) => op(d).map(BorrowCheck),
RvalueCheck(ref d) => op(d).map(RvalueCheck),
TransCrateItem(ref d) => op(d).map(TransCrateItem),

View File

@ -61,6 +61,12 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
self.map.get(k)
}
pub fn get_mut(&mut self, k: &M::Key) -> Option<&mut M::Value> {
self.read(k);
self.write(k);
self.map.get_mut(k)
}
pub fn insert(&mut self, k: M::Key, v: M::Value) -> Option<M::Value> {
self.write(&k);
self.map.insert(k, v)
@ -70,6 +76,10 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
self.read(k);
self.map.contains_key(k)
}
pub fn keys(&self) -> Vec<M::Key> {
self.map.keys().cloned().collect()
}
}
impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {

View File

@ -8,9 +8,31 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use util::nodemap::NodeMap;
use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
use hir::def_id::DefId;
use mir::repr::Mir;
use std::marker::PhantomData;
pub struct MirMap<'tcx> {
pub map: NodeMap<Mir<'tcx>>,
pub map: DepTrackingMap<MirMapConfig<'tcx>>,
}
impl<'tcx> MirMap<'tcx> {
pub fn new(graph: DepGraph) -> Self {
MirMap {
map: DepTrackingMap::new(graph)
}
}
}
pub struct MirMapConfig<'tcx> {
data: PhantomData<&'tcx ()>
}
impl<'tcx> DepTrackingMapConfig for MirMapConfig<'tcx> {
type Key = DefId;
type Value = Mir<'tcx>;
fn to_dep_node(key: &DefId) -> DepNode<DefId> {
DepNode::Mir(*key)
}
}

View File

@ -11,7 +11,6 @@
use dep_graph::DepNode;
use hir;
use hir::map::DefPathData;
use hir::def_id::DefId;
use mir::mir_map::MirMap;
use mir::repr::{Mir, Promoted};
use ty::TyCtxt;
@ -73,9 +72,6 @@ impl<'a, 'tcx> MirSource {
/// Various information about pass.
pub trait Pass {
// fn should_run(Session) to check if pass should run?
fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
DepNode::MirPass(def_id)
}
fn name(&self) -> &str {
let name = unsafe { ::std::intrinsics::type_name::<Self>() };
if let Some(tail) = name.rfind(":") {
@ -119,10 +115,11 @@ impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
map: &mut MirMap<'tcx>,
hooks: &mut [Box<for<'s> MirPassHook<'s>>])
{
for (&id, mir) in &mut map.map {
let def_id = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
let def_ids = map.map.keys();
for def_id in def_ids {
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
let mir = map.map.get_mut(&def_id).unwrap();
let id = tcx.map.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
for hook in &mut *hooks {

View File

@ -168,8 +168,10 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
attributes: &[ast::Attribute]) {
debug!("borrowck_fn(id={})", id);
let def_id = this.tcx.map.local_def_id(id);
if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
let mir = this.mir_map.unwrap().map.get(&id).unwrap();
let mir = this.mir_map.unwrap().map.get(&def_id).unwrap();
this.with_temp_region_map(id, |this| {
mir::borrowck_mir(this, fk, decl, mir, body, sp, id, attributes)
});

View File

@ -956,20 +956,24 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
PpmMir | PpmMirCFG => {
if let Some(mir_map) = mir_map {
if let Some(nodeid) = nodeid {
let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| {
sess.fatal(&format!("no MIR map entry for node {}", nodeid))
});
let def_id = tcx.map.local_def_id(nodeid);
match ppm {
PpmMir => write_mir_pretty(tcx, iter::once((&nodeid, mir)), &mut out),
PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mir_map, &mut out),
PpmMirCFG => {
write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out)
write_mir_graphviz(tcx, iter::once(def_id), &mir_map, &mut out)
}
_ => unreachable!(),
}?;
} else {
match ppm {
PpmMir => write_mir_pretty(tcx, mir_map.map.iter(), &mut out),
PpmMirCFG => write_mir_graphviz(tcx, mir_map.map.iter(), &mut out),
PpmMir => write_mir_pretty(tcx,
mir_map.map.keys().into_iter(),
&mir_map,
&mut out),
PpmMirCFG => write_mir_graphviz(tcx,
mir_map.map.keys().into_iter(),
&mir_map,
&mut out),
_ => unreachable!(),
}?;
}

View File

@ -743,7 +743,8 @@ fn encode_repr_attrs(rbml_w: &mut Encoder,
}
fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, node_id: NodeId) {
if let Some(mir) = ecx.mir_map.map.get(&node_id) {
let def_id = ecx.tcx.map.local_def_id(node_id);
if let Some(mir) = ecx.mir_map.map.get(&def_id) {
rbml_w.start_tag(tag_mir as usize);
rbml_w.emit_opaque(|opaque_encoder| {
tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
@ -1361,7 +1362,7 @@ fn my_visit_expr(expr: &hir::Expr,
ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap();
rbml_w.end_tag();
assert!(ecx.mir_map.map.contains_key(&expr.id));
assert!(ecx.mir_map.map.contains_key(&def_id));
encode_mir(ecx, rbml_w, expr.id);
rbml_w.end_tag();

View File

@ -9,7 +9,9 @@
// except according to those terms.
use dot;
use rustc::hir::def_id::DefId;
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;
use rustc::ty::{self, TyCtxt};
use std::fmt::Debug;
use std::io::{self, Write};
@ -19,10 +21,16 @@ use rustc_data_structures::indexed_vec::Idx;
/// Write a graphviz DOT graph of a list of MIRs.
pub fn write_mir_graphviz<'a, 'b, 'tcx, W, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
iter: I, w: &mut W)
iter: I,
mir_map: &MirMap<'tcx>,
w: &mut W)
-> io::Result<()>
where W: Write, I: Iterator<Item=(&'a NodeId, &'a Mir<'a>)> {
for (&nodeid, mir) in iter {
where W: Write, I: Iterator<Item=DefId>
{
for def_id in iter {
let nodeid = tcx.map.as_local_node_id(def_id).unwrap();
let mir = &mir_map.map[&def_id];
writeln!(w, "digraph Mir_{} {{", nodeid)?;
// Global graph properties

View File

@ -22,6 +22,7 @@ use rustc::mir::transform::MirSource;
use rustc::middle::const_val::ConstVal;
use rustc_const_eval as const_eval;
use rustc_data_structures::indexed_vec::Idx;
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::FnKind;
use rustc::hir::map::blocks::FnLikeNode;
@ -61,7 +62,17 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
MirSource::Promoted(..) => bug!()
};
let attrs = infcx.tcx.map.attrs(src.item_id());
let src_node_id = src.item_id();
// We are going to be accessing various tables
// generated by TypeckItemBody; we also assume
// that the body passes type check. These tables
// are not individually tracked, so just register
// a read here.
let src_def_id = infcx.tcx.map.local_def_id(src_node_id);
infcx.tcx.dep_graph.read(DepNode::TypeckItemBody(src_def_id));
let attrs = infcx.tcx.map.attrs(src_node_id);
// Some functions always have overflow checks enabled,
// however, they may not get codegen'd, depending on

View File

@ -18,6 +18,7 @@
use build;
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::mir::repr::Mir;
use rustc::mir::transform::MirSource;
use rustc::mir::visit::MutVisitor;
@ -29,7 +30,6 @@ use rustc::infer::InferCtxtBuilder;
use rustc::traits::ProjectionMode;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc::util::nodemap::NodeMap;
use rustc::hir;
use rustc::hir::intravisit::{self, FnKind, Visitor};
use syntax::ast;
@ -38,15 +38,13 @@ use syntax_pos::Span;
use std::mem;
pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MirMap<'tcx> {
let mut map = MirMap {
map: NodeMap(),
};
let mut map = MirMap::new(tcx.dep_graph.clone());
{
let mut dump = BuildMir {
tcx: tcx,
map: &mut map,
};
tcx.visit_all_items_in_krate(DepNode::MirMapConstruction, &mut dump);
tcx.visit_all_items_in_krate(DepNode::Mir, &mut dump);
}
map
}
@ -94,6 +92,7 @@ struct BuildMir<'a, 'tcx: 'a> {
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Cx<'b, 'gcx, 'tcx>).
struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
src: MirSource,
def_id: DefId,
infcx: InferCtxtBuilder<'a, 'gcx, 'tcx>,
map: &'a mut MirMap<'gcx>,
}
@ -101,9 +100,11 @@ struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> {
fn cx<'b>(&'b mut self, src: MirSource) -> CxBuilder<'b, 'gcx, 'tcx> {
let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
let def_id = self.tcx.map.local_def_id(src.item_id());
CxBuilder {
src: src,
infcx: self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal),
def_id: def_id,
map: self.map
}
}
@ -133,7 +134,7 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
mir
});
assert!(self.map.map.insert(src.item_id(), mir).is_none())
assert!(self.map.map.insert(self.def_id, mir).is_none())
}
}

View File

@ -10,7 +10,9 @@
use build::{Location, ScopeAuxiliaryVec, ScopeId};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
@ -18,7 +20,6 @@ use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use syntax::ast::NodeId;
use std::path::{PathBuf, Path};
const INDENT: &'static str = " ";
@ -89,12 +90,15 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
iter: I,
mir_map: &MirMap<'tcx>,
w: &mut Write)
-> io::Result<()>
where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
where I: Iterator<Item=DefId>, 'tcx: 'a
{
let mut first = true;
for (&id, mir) in iter {
for def_id in iter {
let mir = &mir_map.map[&def_id];
if first {
first = false;
} else {
@ -102,6 +106,7 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
writeln!(w, "")?;
}
let id = tcx.map.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
write_mir_fn(tcx, src, mir, w, None)?;

View File

@ -16,6 +16,7 @@
use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::FnKind;
@ -881,8 +882,8 @@ fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let extern_mir;
let param_env_and_mir = if def_id.is_local() {
let node_id = tcx.map.as_local_node_id(def_id).unwrap();
mir_map.and_then(|map| map.map.get(&node_id)).map(|mir| {
mir_map.and_then(|map| map.map.get(&def_id)).map(|mir| {
let node_id = tcx.map.as_local_node_id(def_id).unwrap();
(ty::ParameterEnvironment::for_item(tcx, node_id), mir)
})
} else if let Some(mir) = tcx.sess.cstore.maybe_get_item_mir(tcx, def_id) {
@ -917,9 +918,10 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
// First, visit `const` items, potentially recursing, to get
// accurate MUTABLE_INTERIOR and NEEDS_DROP qualifications.
for &id in map.map.keys() {
let def_id = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
let keys = map.map.keys();
for &def_id in &keys {
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
let id = tcx.map.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
if let MirSource::Const(_) = src {
qualify_const_item_cached(tcx, &mut qualif_map, Some(map), def_id);
@ -929,9 +931,9 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
// Then, handle everything else, without recursing,
// as the MIR map is not shared, since promotion
// in functions (including `const fn`) mutates it.
for (&id, mir) in &mut map.map {
let def_id = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
for &def_id in &keys {
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
let id = tcx.map.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
let mode = match src {
MirSource::Fn(_) => {
@ -948,6 +950,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
};
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let mir = map.map.get_mut(&def_id).unwrap();
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, mir, self, false);
}

View File

@ -11,8 +11,6 @@
//! This pass type-checks the MIR to ensure it is not broken.
#![allow(unreachable_code)]
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::infer::{self, InferCtxt, InferOk};
use rustc::traits::{self, ProjectionMode};
use rustc::ty::fold::TypeFoldable;
@ -714,7 +712,4 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
}
impl Pass for TypeckMir {
fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
DepNode::MirTypeck(def_id)
}
}

View File

@ -81,7 +81,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
check_overflow: bool,
check_drop_flag_for_sanity: bool,
mir_map: &'a MirMap<'tcx>,
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
mir_cache: RefCell<DepTrackingMap<MirCache<'tcx>>>,
use_dll_storage_attrs: bool,
@ -186,6 +186,19 @@ impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
}
}
// Cache for mir loaded from metadata
struct MirCache<'tcx> {
data: PhantomData<&'tcx ()>
}
impl<'tcx> DepTrackingMapConfig for MirCache<'tcx> {
type Key = DefId;
type Value = Rc<mir::Mir<'tcx>>;
fn to_dep_node(key: &DefId) -> DepNode<DefId> {
DepNode::Mir(*key)
}
}
/// This list owns a number of LocalCrateContexts and binds them to their common
/// SharedCrateContext. This type just exists as a convenience, something to
/// pass around all LocalCrateContexts with and get an iterator over them.
@ -474,7 +487,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
symbol_hasher: RefCell::new(symbol_hasher),
tcx: tcx,
mir_map: mir_map,
mir_cache: RefCell::new(DefIdMap()),
mir_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
stats: Stats {
n_glues_created: Cell::new(0),
n_null_glues: Cell::new(0),
@ -538,8 +551,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
pub fn get_mir(&self, def_id: DefId) -> Option<CachedMir<'b, 'tcx>> {
if def_id.is_local() {
let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
self.mir_map.map.get(&node_id).map(CachedMir::Ref)
self.mir_map.map.get(&def_id).map(CachedMir::Ref)
} else {
if let Some(mir) = self.mir_cache.borrow().get(&def_id).cloned() {
return Some(CachedMir::Owned(mir));