]> git.lizzy.rs Git - rust.git/commitdiff
retool MIR passes completely
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 27 Apr 2017 20:48:48 +0000 (16:48 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 2 May 2017 18:01:01 +0000 (14:01 -0400)
The new setup is as follows. There is a pipeline of MIR passes that each
run **per def-id** to optimize a particular function. You are intended
to request MIR at whatever stage you need it. At the moment, there is
only one stage you can request:

- `optimized_mir(def_id)`

This yields the final product. Internally, it pulls the MIR for the
given def-id through a series of steps. Right now, these are still using
an "interned ref-cell" but they are intended to "steal" from one
another:

- `mir_build` -- performs the initial construction for local MIR
- `mir_pass_set` -- performs a suite of optimizations and transformations
- `mir_pass` -- an individual optimization within a suite

So, to construct the optimized MIR, we invoke:

    mir_pass_set((MIR_OPTIMIZED, def_id))

which will build up the final MIR.

13 files changed:
src/librustc/mir/transform.rs
src/librustc/ty/maps.rs
src/librustc/ty/mod.rs
src/librustc_driver/driver.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_mir/lib.rs
src/librustc_mir/mir_map.rs
src/librustc_mir/transform/dump_mir.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/util/mod.rs
src/librustc_mir/util/pretty.rs

index 8ecfbfdb5c3ef35ab8f41d62979b43d9c81fe679..9fab6564d9b002edfc893891bd6093a5a415d239 100644 (file)
@@ -9,13 +9,13 @@
 // 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;
 
@@ -90,12 +90,37 @@ pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
     }
 }
 
+/// 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
@@ -107,21 +132,7 @@ fn name<'a>(&'a self) -> Cow<'a, str> {
         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
@@ -138,29 +149,24 @@ fn run_pass<'a, 'tcx>(&self,
                           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
     }
 }
 
@@ -168,12 +174,7 @@ fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
 #[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:
@@ -184,52 +185,41 @@ struct PassSet {
 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
+    }
 }
index a9deb52efb68af0cf9ed188d1fcfc7c36c409aa8..dc70dcc81162f8a8a0ca0cbfac5e2c1f6c9370ff 100644 (file)
@@ -16,6 +16,7 @@
 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;
@@ -101,6 +102,24 @@ fn default_span(&self, tcx: TyCtxt) -> Span {
     }
 }
 
+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;
 }
@@ -318,6 +337,18 @@ fn describe(tcx: TyCtxt, def_id: DefId) -> String {
     }
 }
 
+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])*
@@ -542,15 +573,6 @@ fn default() -> Self {
     /// 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.
@@ -561,6 +583,26 @@ fn default() -> Self {
     /// 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,
@@ -658,3 +700,11 @@ fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
 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)
+}
index 5e5dbdf20c04c471d56b49c0baa1ce03303e2665..cf66c83800d367d908b4a57f7c8b0dcec065f42c 100644 (file)
@@ -2323,9 +2323,9 @@ pub fn item_name(self, id: DefId) -> ast::Name {
         }
     }
 
-    /// 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.
@@ -2333,8 +2333,16 @@ pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>)
                         -> 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()
+            }
         }
     }
 
index 4c984559428bfdd631482045989b53c39982fa51..9b11d168e007732d57261939e5fe10529693e541 100644 (file)
@@ -1005,11 +1005,6 @@ macro_rules! try_with_f {
             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));
@@ -1058,20 +1053,6 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, '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",
index f5a8accea2803200bcaf23447bafbdc97150d57d..4ecce3cc132fe72af74a63d779f24271fad41c80 100644 (file)
@@ -95,7 +95,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
             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)
         });
index 8b55cdf06d208fd1696b51747320d93cced8af56..cf6a50563a08c34ee84dd4e51d4ef60b00db4f78 100644 (file)
@@ -59,5 +59,5 @@
 pub fn provide(providers: &mut Providers) {
     mir_map::provide(providers);
     shim::provide(providers);
-    transform::qualify_consts::provide(providers);
+    transform::provide(providers);
 }
index 6aa7089e7a9069d37bbe11acef3ad16fa179f095..46f7c34c06e8d68b4c478e935fe52af2a865ef8b 100644 (file)
@@ -52,8 +52,11 @@ fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
 }
 
 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)
@@ -95,8 +98,7 @@ fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
     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);
@@ -192,7 +194,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
             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)
     })
@@ -251,7 +253,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 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)
         })
index 62b480494c3ecc2b3fc601ddf7425593ed2302c2..a76ba8a8b688ccfcc7e1ba147ba5b0feaa40e17e 100644 (file)
 //! 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);
@@ -28,8 +29,8 @@ fn name<'a>(&'a self) -> Cow<'a, 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()
     }
 }
 
@@ -47,30 +48,31 @@ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
 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);
         }
     }
 }
index b0a067063dd60c4e74d15cc77d8ca317e549a031..6eda2f5abb9d8b66dcff509af856f6bd15a3b9a0 100644 (file)
@@ -27,6 +27,7 @@
 
 use super::simplify::{remove_dead_blocks, CfgSimplifier};
 
+use std::cell::{Ref, RefCell};
 use syntax::{attr};
 use syntax::abi::Abi;
 
@@ -74,6 +75,14 @@ struct CallSite<'tcx> {
 }
 
 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();
@@ -146,7 +155,7 @@ fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeInd
                 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;
                         }
@@ -158,7 +167,7 @@ fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeInd
 
                 };
 
-                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();
 
@@ -210,7 +219,7 @@ fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeInd
             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();
index cbd054a72499b9adbdf5c044b7aa48f08a77f3b5..68070ded12d9899ba6ea17bc9f70356658f82767 100644 (file)
@@ -8,6 +8,14 @@
 // 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)
+        }
+    }
+}
index 80ec83fcaefb0b94fb8a50f730169d1f45ab8a49..cb002acf009d1256351e9508e721d5174d74cba0 100644 (file)
@@ -16,7 +16,6 @@
 
 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;
 
@@ -925,7 +925,7 @@ pub fn provide(providers: &mut Providers) {
 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();
     }
@@ -940,30 +940,32 @@ fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 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 {
index cafc5bca76acd8eeb2e638eee83cfef33fc35f90..4386bab38c0399650bb461a6a6d7cfc16cacedbe 100644 (file)
@@ -15,6 +15,6 @@
 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;
index 6c637f2b2a9d69541d0de242b1e235061fb0a011..e8fc70b74bcb77570d8038e246e9bb43dab0e805 100644 (file)
@@ -11,7 +11,7 @@
 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,
@@ -69,8 +58,26 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+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,
@@ -84,7 +91,10 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     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();