retool MIR passes completely
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.
This commit is contained in:
parent
f23a7bc98a
commit
2b32cb90c7
13 changed files with 344 additions and 184 deletions
|
|
@ -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 @@ pub trait DefIdPass {
|
|||
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 @@ pub trait MirPass: DepGraphSafe {
|
|||
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 @@ impl<T: MirPass> DefIdPass for T {
|
|||
#[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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use middle::const_val;
|
|||
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 @@ impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ define_maps! { <'tcx>
|
|||
/// 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 @@ define_maps! { <'tcx>
|
|||
/// 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2323,9 +2323,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
-> 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1005,11 +1005,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
|||
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",
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ provide! { <'tcx> tcx, def_id, cdata
|
|||
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)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -59,5 +59,5 @@ use rustc::ty::maps::Providers;
|
|||
pub fn provide(providers: &mut Providers) {
|
||||
mir_map::provide(providers);
|
||||
shim::provide(providers);
|
||||
transform::qualify_consts::provide(providers);
|
||||
transform::provide(providers);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,11 @@ pub fn build_mir_for_crate<'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 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);
|
||||
|
|
@ -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)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,14 +11,15 @@
|
|||
//! 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 @@ impl DefIdPass for Marker {
|
|||
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 @@ impl fmt::Display for Disambiguator {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use rustc::util::nodemap::{DefIdSet};
|
|||
|
||||
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 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
|
||||
};
|
||||
|
||||
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 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -21,3 +29,101 @@ pub mod deaggregator;
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -27,13 +26,14 @@ use rustc::ty::cast::CastTy;
|
|||
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);
|
||||
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()
|
||||
}
|
||||
|
||||
if let MirSource::Const(_) = src {
|
||||
tcx.mir_const_qualif(def_id);
|
||||
return;
|
||||
src => {
|
||||
let mir = mir_cx.steal_previous_mir();
|
||||
self.run_pass(tcx, src, &mut mir.borrow_mut());
|
||||
mir
|
||||
}
|
||||
}
|
||||
|
||||
let mir = &mut tcx.mir(def_id).borrow_mut();
|
||||
tcx.dep_graph.write(DepNode::Mir(def_id));
|
||||
|
||||
self.run_pass(tcx, src, 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 {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ pub mod patch;
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -39,29 +39,18 @@ const ALIGN: usize = 40;
|
|||
/// 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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue