// except according to those terms.
use hir;
-use hir::def_id::{DefId, LOCAL_CRATE};
+use hir::def_id::DefId;
use hir::map::DefPathData;
use mir::{Mir, Promoted};
use ty::TyCtxt;
+use std::cell::{Ref, RefCell};
use std::rc::Rc;
use syntax::ast::NodeId;
-use util::common::time;
use std::borrow::Cow;
}
}
+/// Gives you access to various bits of state during your MIR pass.
+pub trait MirCtxt<'a, 'tcx: 'a> {
+ fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
+ fn def_id(&self) -> DefId;
+ fn pass_set(&self) -> MirPassSet;
+ fn pass_num(&self) -> MirPassIndex;
+ fn source(&self) -> MirSource;
+ fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>;
+ fn steal_previous_mir(&self) -> &'tcx RefCell<Mir<'tcx>>;
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct MirPassSet(pub usize);
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct MirPassIndex(pub usize);
+
+/// A pass hook is invoked both before and after each pass executes.
+/// This is primarily used to dump MIR for debugging.
+///
+/// You can tell whether this is before or after by inspecting the
+/// `mir` parameter -- before the pass executes, it will be `None` (in
+/// which case you can inspect the MIR from previous pass by executing
+/// `mir_cx.read_previous_mir()`); after the pass executes, it will be
+/// `Some()` with the result of the pass (in which case the output
+/// from the previous pass is most likely stolen, so you would not
+/// want to try and access it).
pub trait PassHook {
- fn on_mir_pass<'a, 'tcx>(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- pass_name: &str,
- pass_num: usize,
- is_after: bool);
+ fn on_mir_pass<'a, 'tcx: 'a>(&self,
+ mir_cx: &MirCtxt<'a, 'tcx>,
+ mir: Option<&Mir<'tcx>>);
}
/// A streamlined trait that you can implement to create a pass; the
default_name::<Self>()
}
- fn run_pass<'a, 'tcx>(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId);
-}
-
-impl<T: DefIdPass> Pass for T {
- fn name<'a>(&'a self) -> Cow<'a, str> {
- DefIdPass::name(self)
- }
-
- fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
- DefIdPass::run_pass(self, tcx, def_id);
- }
- }
+ fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>>;
}
/// A streamlined trait that you can implement to create a pass; the
mir: &mut Mir<'tcx>);
}
-fn for_each_assoc_mir<'a, 'tcx, OP>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId,
- mut op: OP)
- where OP: FnMut(MirSource, &mut Mir<'tcx>)
-{
- let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id");
- let source = MirSource::from_node(tcx, id);
- let mir = &mut tcx.mir(def_id).borrow_mut();
- op(source, mir);
-
- for (promoted_index, promoted_mir) in mir.promoted.iter_enumerated_mut() {
- let promoted_source = MirSource::Promoted(id, promoted_index);
- op(promoted_source, promoted_mir);
- }
-}
-
impl<T: MirPass> DefIdPass for T {
fn name<'a>(&'a self) -> Cow<'a, str> {
MirPass::name(self)
}
- fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
- for_each_assoc_mir(tcx, def_id, |src, mir| MirPass::run_pass(self, tcx, src, mir));
+ fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>> {
+ let tcx = mir_cx.tcx();
+ let source = mir_cx.source();
+ let mir = mir_cx.steal_previous_mir();
+ MirPass::run_pass(self, tcx, source, &mut mir.borrow_mut());
+
+ let item_id = source.item_id();
+ for (promoted_index, promoted_mir) in mir.borrow_mut().promoted.iter_enumerated_mut() {
+ let promoted_source = MirSource::Promoted(item_id, promoted_index);
+ MirPass::run_pass(self, tcx, promoted_source, promoted_mir);
+ }
+
+ mir
}
}
#[derive(Clone)]
pub struct Passes {
pass_hooks: Vec<Rc<PassHook>>,
- sets: Vec<PassSet>,
-}
-
-#[derive(Clone)]
-struct PassSet {
- passes: Vec<Rc<DefIdPass>>,
+ sets: Vec<Vec<Rc<DefIdPass>>>,
}
/// The number of "pass sets" that we have:
pub const MIR_PASS_SETS: usize = 3;
/// Run the passes we need to do constant qualification and evaluation.
-pub const MIR_CONST: usize = 0;
+pub const MIR_CONST: MirPassSet = MirPassSet(0);
/// Run the passes we need to consider the MIR validated and ready for borrowck etc.
-pub const MIR_VALIDATED: usize = 1;
+pub const MIR_VALIDATED: MirPassSet = MirPassSet(1);
/// Run the passes we need to consider the MIR *optimized*.
-pub const MIR_OPTIMIZED: usize = 2;
+pub const MIR_OPTIMIZED: MirPassSet = MirPassSet(2);
impl<'a, 'tcx> Passes {
pub fn new() -> Passes {
Passes {
pass_hooks: Vec::new(),
- sets: (0..MIR_PASS_SETS).map(|_| PassSet { passes: Vec::new() }).collect(),
- }
- }
-
- pub fn run_passes(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, set_index: usize) {
- let set = &self.sets[set_index];
-
- let start_num: usize = self.sets[..set_index].iter().map(|s| s.passes.len()).sum();
-
- // NB: passes are numbered from 1, since "construction" is zero.
- for (pass, pass_num) in set.passes.iter().zip(start_num + 1..) {
- for hook in &self.pass_hooks {
- hook.on_mir_pass(tcx, &pass.name(), pass_num, false);
- }
-
- time(tcx.sess.time_passes(), &*pass.name(), || {
- for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
- pass.run_pass(tcx, def_id);
- }
- });
-
- for hook in &self.pass_hooks {
- hook.on_mir_pass(tcx, &pass.name(), pass_num, true);
- }
+ sets: (0..MIR_PASS_SETS).map(|_| Vec::new()).collect(),
}
}
/// Pushes a built-in pass.
- pub fn push_pass<T: DefIdPass + 'static>(&mut self, set: usize, pass: T) {
- self.sets[set].passes.push(Rc::new(pass));
+ pub fn push_pass<T: DefIdPass + 'static>(&mut self, set: MirPassSet, pass: T) {
+ self.sets[set.0].push(Rc::new(pass));
}
/// Pushes a pass hook.
pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
self.pass_hooks.push(Rc::new(hook));
}
+
+ pub fn len_passes(&self, set: MirPassSet) -> usize {
+ self.sets[set.0].len()
+ }
+
+ pub fn pass(&self, set: MirPassSet, pass: MirPassIndex) -> &DefIdPass {
+ &*self.sets[set.0][pass.0]
+ }
+
+ pub fn hooks(&self) -> &[Rc<PassHook>] {
+ &self.pass_hooks
+ }
}
use middle::privacy::AccessLevels;
use middle::region::RegionMaps;
use mir;
+use mir::transform::{MirPassSet, MirPassIndex};
use session::CompileResult;
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use ty::item_path;
}
}
+impl Key for (MirPassSet, DefId) {
+ fn map_crate(&self) -> CrateNum {
+ self.1.map_crate()
+ }
+ fn default_span(&self, tcx: TyCtxt) -> Span {
+ self.1.default_span(tcx)
+ }
+}
+
+impl Key for (MirPassSet, MirPassIndex, DefId) {
+ fn map_crate(&self) -> CrateNum {
+ self.2.map_crate()
+ }
+ fn default_span(&self, tcx: TyCtxt) -> Span {
+ self.2.default_span(tcx)
+ }
+}
+
trait Value<'tcx>: Sized {
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
}
}
}
+impl<'tcx> QueryDescription for queries::mir_pass_set<'tcx> {
+ fn describe(_: TyCtxt, (pass_set, _): (MirPassSet, DefId)) -> String {
+ format!("MIR passes #{}.*", pass_set.0)
+ }
+}
+
+impl<'tcx> QueryDescription for queries::mir_pass<'tcx> {
+ fn describe(_: TyCtxt, (pass_set, pass_num, _): (MirPassSet, MirPassIndex, DefId)) -> String {
+ format!("MIR pass #{}.{}", pass_set.0, pass_num.0)
+ }
+}
+
macro_rules! define_maps {
(<$tcx:tt>
$($(#[$attr:meta])*
/// Methods in these implementations don't need to be exported.
[] inherent_impls: InherentImpls(DefId) -> Rc<Vec<DefId>>,
- /// Maps from the def-id of a function/method or const/static
- /// to its MIR. Mutation is done at an item granularity to
- /// allow MIR optimization passes to function and still
- /// access cross-crate MIR (e.g. inlining or const eval).
- ///
- /// Note that cross-crate MIR appears to be always borrowed
- /// (in the `RefCell` sense) to prevent accidental mutation.
- [] mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
-
/// Set of all the def-ids in this crate that have MIR associated with
/// them. This includes all the body owners, but also things like struct
/// constructors.
/// the value isn't known except to the pass itself.
[] mir_const_qualif: Mir(DefId) -> u8,
+ /// Performs the initial MIR construction. You almost certainly do not
+ /// want to use this query, because its output is intended to be stolen
+ /// immediately by the MIR passes below. Consider `optimized_mir` instead.
+ [] mir_build: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
+
+ /// Fetch the MIR for a given def-id after the given set of passes has ben
+ /// applied to it. This is mostly an "intermediate" query. Normally, you would
+ /// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all
+ /// optimizations and so forth.
+ [] mir_pass_set: mir_pass_set((MirPassSet, DefId)) -> &'tcx RefCell<mir::Mir<'tcx>>,
+
+ /// Fetch the MIR for a given def-id after a given pass has been executed. This is
+ /// **only** intended to be used by the `mir_pass_set` provider -- if you are using it
+ /// manually, you're doing it wrong.
+ [] mir_pass: mir_pass((MirPassSet, MirPassIndex, DefId)) -> &'tcx RefCell<mir::Mir<'tcx>>,
+
+ /// MIR after our optimization passes have run. This is MIR that is ready
+ /// for trans. This is also the only query that can fetch non-local MIR, at present.
+ [] optimized_mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
+
/// Records the type of each closure. The def ID is the ID of the
/// expression defining the closure.
[] closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
fn mir_keys(_: CrateNum) -> DepNode<DefId> {
DepNode::MirKeys
}
+
+fn mir_pass_set((_pass_set, def_id): (MirPassSet, DefId)) -> DepNode<DefId> {
+ DepNode::Mir(def_id)
+}
+
+fn mir_pass((_pass_set, _pass_num, def_id): (MirPassSet, MirPassIndex, DefId)) -> DepNode<DefId> {
+ DepNode::Mir(def_id)
+}
}
}
- /// Given the did of an item, returns its MIR, borrowed immutably.
+ /// Given the did of an item, returns its (optimized) MIR, borrowed immutably.
pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
- self.mir(did).borrow()
+ self.optimized_mir(did).borrow()
}
/// Return the possibly-auto-generated MIR of a (DefId, Subst) pair.
-> Ref<'gcx, Mir<'gcx>>
{
match instance {
- ty::InstanceDef::Item(did) if true => self.item_mir(did),
- _ => self.mir_shims(instance).borrow(),
+ ty::InstanceDef::Item(did) => {
+ self.item_mir(did)
+ }
+ ty::InstanceDef::Intrinsic(..) |
+ ty::InstanceDef::FnPtrShim(..) |
+ ty::InstanceDef::Virtual(..) |
+ ty::InstanceDef::ClosureOnceShim { .. } |
+ ty::InstanceDef::DropGlue(..) => {
+ self.mir_shims(instance).borrow()
+ }
}
}
mir_stats::print_mir_stats(tcx, "PRE CLEANUP MIR STATS");
}
- time(time_passes, "MIR cleanup and validation", || {
- tcx.mir_passes.run_passes(tcx, MIR_CONST);
- tcx.mir_passes.run_passes(tcx, MIR_VALIDATED);
- });
-
time(time_passes,
"borrow checking",
|| borrowck::check_crate(tcx));
"resolving dependency formats",
|| dependency_format::calculate(&tcx.sess));
- if tcx.sess.opts.debugging_opts.mir_stats {
- mir_stats::print_mir_stats(tcx, "PRE OPTIMISATION MIR STATS");
- }
-
- // Run the passes that transform the MIR into a more suitable form for translation to LLVM
- // code.
- time(time_passes, "MIR optimisations", || {
- tcx.mir_passes.run_passes(tcx, MIR_OPTIMIZED);
- });
-
- if tcx.sess.opts.debugging_opts.mir_stats {
- mir_stats::print_mir_stats(tcx, "POST OPTIMISATION MIR STATS");
- }
-
let translation =
time(time_passes,
"translation",
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
})
}
- mir => {
+ optimized_mir => {
let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| {
bug!("get_item_mir: missing MIR for `{:?}`", def_id)
});
pub fn provide(providers: &mut Providers) {
mir_map::provide(providers);
shim::provide(providers);
- transform::qualify_consts::provide(providers);
+ transform::provide(providers);
}
}
pub fn provide(providers: &mut Providers) {
- providers.mir = build_mir;
- providers.mir_keys = mir_keys;
+ *providers = Providers {
+ mir_build,
+ mir_keys,
+ ..*providers
+ };
}
fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
Rc::new(set)
}
-fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> &'tcx RefCell<Mir<'tcx>> {
+fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell<Mir<'tcx>> {
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let unsupported = || {
span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
mem::transmute::<Mir, Mir<'tcx>>(mir)
};
- mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
+ mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
tcx.alloc_mir(mir)
})
mem::transmute::<Mir, Mir<'tcx>>(mir)
};
- mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
+ mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
tcx.alloc_mir(mir)
})
//! This pass just dumps MIR at a specified point.
use std::borrow::Cow;
+use std::cell::RefCell;
use std::fmt;
use std::fs::File;
use std::io;
-use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::session::config::{OutputFilenames, OutputType};
use rustc::ty::TyCtxt;
-use rustc::mir::transform::{DefIdPass, Pass, PassHook, MirSource};
+use rustc::mir::Mir;
+use rustc::mir::transform::{DefIdPass, PassHook, MirCtxt};
use util as mir_util;
pub struct Marker(pub &'static str);
Cow::Borrowed(self.0)
}
- fn run_pass<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>, _: DefId) {
- // no-op
+ fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>> {
+ mir_cx.steal_previous_mir()
}
}
pub struct DumpMir;
impl PassHook for DumpMir {
- fn on_mir_pass<'a, 'tcx>(
- &self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- pass_name: &str,
- pass_num: usize,
- is_after: bool)
+ fn on_mir_pass<'a, 'tcx: 'a>(&self,
+ mir_cx: &MirCtxt<'a, 'tcx>,
+ mir: Option<&Mir<'tcx>>)
{
- // No dump filters enabled.
- if tcx.sess.opts.debugging_opts.dump_mir.is_none() {
- return;
- }
-
- for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
- let id = tcx.hir.as_local_node_id(def_id).unwrap();
- let source = MirSource::from_node(tcx, id);
- let mir = tcx.item_mir(def_id);
- mir_util::dump_mir(
- tcx,
- pass_num,
- &pass_name,
- &Disambiguator { is_after },
- source,
- &mir
- );
+ let tcx = mir_cx.tcx();
+ let pass_set = mir_cx.pass_set();
+ let pass_num = mir_cx.pass_num();
+ let pass = tcx.mir_passes.pass(pass_set, pass_num);
+ let name = &pass.name();
+ let source = mir_cx.source();
+ if mir_util::dump_enabled(tcx, name, source) {
+ let previous_mir;
+ let mir_to_dump = match mir {
+ Some(m) => m,
+ None => {
+ previous_mir = mir_cx.read_previous_mir();
+ &*previous_mir
+ }
+ };
+ mir_util::dump_mir(tcx,
+ Some((pass_set, pass_num)),
+ name,
+ &Disambiguator { is_after: mir.is_some() },
+ source,
+ mir_to_dump);
}
}
}
use super::simplify::{remove_dead_blocks, CfgSimplifier};
+use std::cell::{Ref, RefCell};
use syntax::{attr};
use syntax::abi::Abi;
}
impl<'a, 'tcx> Inliner<'a, 'tcx> {
+ fn maybe_item_mir(&mut self, _def_id: DefId) -> Option<Ref<'tcx, Mir<'tcx>>> {
+ panic!() // TODO -- hook up inline into the system
+ }
+
+ fn mir(&mut self, _def_id: DefId) -> &'tcx RefCell<Mir<'tcx>> {
+ panic!() // TODO -- hook up inline into the system
+ }
+
fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool {
let mut callsites = Vec::new();
let mut in_scc = DefIdSet();
self.tcx.dep_graph.write(DepNode::Mir(callsite.caller));
let callee_mir = {
- if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) {
+ if let Some(callee_mir) = self.maybe_item_mir(callsite.callee) {
if !self.should_inline(callsite, &callee_mir) {
continue;
}
};
- let mut caller_mir = self.tcx.mir(callsite.caller).borrow_mut();
+ let mut caller_mir = self.mir(callsite.caller).borrow_mut();
let start = caller_mir.basic_blocks().len();
let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id));
self.tcx.dep_graph.write(DepNode::Mir(def_id));
- let mut caller_mir = self.tcx.mir(def_id).borrow_mut();
+ let mut caller_mir = self.mir(def_id).borrow_mut();
debug!("Running simplify cfg on {:?}", def_id);
CfgSimplifier::new(&mut caller_mir).simplify();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc::hir::def_id::DefId;
+use rustc::mir::Mir;
+use rustc::mir::transform::{MirCtxt, MirPassIndex, MirPassSet, MirSource, MIR_OPTIMIZED};
+use rustc::ty::TyCtxt;
+use rustc::ty::maps::Providers;
+use std::cell::{Ref, RefCell};
+use std::mem;
+
pub mod simplify_branches;
pub mod simplify;
pub mod erase_regions;
pub mod instcombine;
pub mod copy_prop;
pub mod inline;
+
+pub fn provide(providers: &mut Providers) {
+ self::qualify_consts::provide(providers);
+ *providers = Providers {
+ optimized_mir,
+ mir_pass_set,
+ mir_pass,
+ ..*providers
+ };
+}
+
+fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell<Mir<'tcx>> {
+ let mir = tcx.mir_pass_set((MIR_OPTIMIZED, def_id));
+
+ // "lock" the ref cell into read mode; after this point,
+ // there ought to be no more changes to the MIR.
+ mem::drop(mir.borrow());
+
+ mir
+}
+
+fn mir_pass_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ (pass_set, def_id): (MirPassSet, DefId))
+ -> &'tcx RefCell<Mir<'tcx>>
+{
+ let passes = &tcx.mir_passes;
+ let len = passes.len_passes(pass_set);
+ assert!(len > 0, "no passes in {:?}", pass_set);
+ tcx.mir_pass((pass_set, MirPassIndex(len - 1), def_id))
+}
+
+fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ (pass_set, pass_num, def_id): (MirPassSet, MirPassIndex, DefId))
+ -> &'tcx RefCell<Mir<'tcx>>
+{
+ let passes = &tcx.mir_passes;
+ let pass = passes.pass(pass_set, pass_num);
+ let mir_ctxt = MirCtxtImpl { tcx, pass_num, pass_set, def_id };
+
+ for hook in passes.hooks() {
+ hook.on_mir_pass(&mir_ctxt, None);
+ }
+
+ let mir = pass.run_pass(&mir_ctxt);
+
+ for hook in passes.hooks() {
+ hook.on_mir_pass(&mir_ctxt, Some(&mir.borrow()));
+ }
+
+ mir
+}
+
+struct MirCtxtImpl<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ pass_num: MirPassIndex,
+ pass_set: MirPassSet,
+ def_id: DefId
+}
+
+impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+ self.tcx
+ }
+
+ fn pass_set(&self) -> MirPassSet {
+ self.pass_set
+ }
+
+ fn pass_num(&self) -> MirPassIndex {
+ self.pass_num
+ }
+
+ fn def_id(&self) -> DefId {
+ self.def_id
+ }
+
+ fn source(&self) -> MirSource {
+ let id = self.tcx.hir.as_local_node_id(self.def_id)
+ .expect("mir source requires local def-id");
+ MirSource::from_node(self.tcx, id)
+ }
+
+ fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>> {
+ self.steal_previous_mir().borrow()
+ }
+
+ fn steal_previous_mir(&self) -> &'tcx RefCell<Mir<'tcx>> {
+ let MirPassSet(pass_set) = self.pass_set;
+ let MirPassIndex(pass_num) = self.pass_num;
+ if pass_num > 0 {
+ self.tcx.mir_pass((MirPassSet(pass_set), MirPassIndex(pass_num - 1), self.def_id))
+ } else if pass_set > 0 {
+ self.tcx.mir_pass_set((MirPassSet(pass_set - 1), self.def_id))
+ } else {
+ self.tcx.mir_build(self.def_id)
+ }
+ }
+}
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::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::ty::maps::Providers;
use rustc::mir::*;
use rustc::mir::traversal::ReversePostorder;
-use rustc::mir::transform::{DefIdPass, MirSource};
+use rustc::mir::transform::{DefIdPass, MirCtxt, MirSource, MIR_CONST};
use rustc::mir::visit::{LvalueContext, Visitor};
use rustc::middle::lang_items;
use syntax::abi::Abi;
use syntax::feature_gate::UnstableFeatures;
use syntax_pos::{Span, DUMMY_SP};
+use std::cell::RefCell;
use std::fmt;
use std::usize;
fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> u8 {
- let mir = &tcx.item_mir(def_id);
+ let mir = &tcx.mir_pass_set((MIR_CONST, def_id)).borrow();
if mir.return_ty.references_error() {
return Qualif::NOT_CONST.bits();
}
pub struct QualifyAndPromoteConstants;
impl DefIdPass for QualifyAndPromoteConstants {
- fn run_pass<'a, 'tcx>(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId)
- {
- let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
- let id = tcx.hir.as_local_node_id(def_id).unwrap();
- let src = MirSource::from_node(tcx, id);
-
- if let MirSource::Const(_) = src {
- tcx.mir_const_qualif(def_id);
- return;
- }
-
- let mir = &mut tcx.mir(def_id).borrow_mut();
- tcx.dep_graph.write(DepNode::Mir(def_id));
+ fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>> {
+ let tcx = mir_cx.tcx();
+ match mir_cx.source() {
+ MirSource::Const(_) => {
+ // Ensure that we compute the `mir_const_qualif` for
+ // constants at this point, before we do any further
+ // optimization (and before we steal the previous
+ // MIR).
+ tcx.mir_const_qualif(mir_cx.def_id());
+ mir_cx.steal_previous_mir()
+ }
- self.run_pass(tcx, src, mir);
+ src => {
+ let mir = mir_cx.steal_previous_mir();
+ self.run_pass(tcx, src, &mut mir.borrow_mut());
+ mir
+ }
+ }
}
}
impl<'a, 'tcx> QualifyAndPromoteConstants {
fn run_pass(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- src: MirSource, mir: &mut Mir<'tcx>) {
+ src: MirSource,
+ mir: &mut Mir<'tcx>) {
let id = src.item_id();
let def_id = tcx.hir.local_def_id(id);
let mode = match src {
mod graphviz;
mod pretty;
-pub use self::pretty::{dump_mir, write_mir_pretty};
+pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty};
pub use self::graphviz::{write_mir_graphviz};
pub use self::graphviz::write_node_label as write_graphviz_node_label;
use rustc::hir;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::*;
-use rustc::mir::transform::MirSource;
+use rustc::mir::transform::{MirPassSet, MirPassIndex, MirSource};
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx};
/// that can appear in the pass-name or the `item_path_str` for the given
/// node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- pass_num: usize,
+ pass_num: Option<(MirPassSet, MirPassIndex)>,
pass_name: &str,
disambiguator: &Display,
source: MirSource,
mir: &Mir<'tcx>) {
- let filters = match tcx.sess.opts.debugging_opts.dump_mir {
- None => return,
- Some(ref filters) => filters,
- };
- let node_id = source.item_id();
- let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
- let is_matched =
- filters.split("&")
- .any(|filter| {
- filter == "all" ||
- pass_name.contains(filter) ||
- node_path.contains(filter)
- });
- if !is_matched {
+ if !dump_enabled(tcx, pass_name, source) {
return;
}
- dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator, source, mir);
+ let node_path = tcx.item_path_str(tcx.hir.local_def_id(source.item_id()));
+ dump_matched_mir_node(tcx, pass_num, pass_name, &node_path,
+ disambiguator, source, mir);
for (index, promoted_mir) in mir.promoted.iter_enumerated() {
let promoted_source = MirSource::Promoted(source.item_id(), index);
dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator,
}
}
+pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ pass_name: &str,
+ source: MirSource)
+ -> bool {
+ let filters = match tcx.sess.opts.debugging_opts.dump_mir {
+ None => return false,
+ Some(ref filters) => filters,
+ };
+ let node_id = source.item_id();
+ let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
+ filters.split("&")
+ .any(|filter| {
+ filter == "all" ||
+ pass_name.contains(filter) ||
+ node_path.contains(filter)
+ })
+}
+
fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- pass_num: usize,
+ pass_num: Option<(MirPassSet, MirPassIndex)>,
pass_name: &str,
node_path: &str,
disambiguator: &Display,
let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number {
format!("")
} else {
- format!(".{:03}", pass_num)
+ match pass_num {
+ None => format!(".-------"),
+ Some((pass_set, pass_num)) => format!(".{:03}-{:03}", pass_set.0, pass_num.0),
+ }
};
let mut file_path = PathBuf::new();