From 2ee00e6d9d0deb562602fc78181267032517d279 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 8 Jun 2016 21:03:06 +0300 Subject: [PATCH] add hook infrastructure for automatically dumping MIR on every pass --- src/librustc/mir/transform.rs | 52 ++++++++++++++-- .../borrowck/mir/elaborate_drops.rs | 7 +-- src/librustc_driver/driver.rs | 4 +- src/librustc_mir/transform/add_call_guards.rs | 4 +- src/librustc_mir/transform/dump_mir.rs | 62 ++++++++++++++++--- src/librustc_mir/transform/erase_regions.rs | 4 +- src/librustc_mir/transform/no_landing_pads.rs | 4 +- src/librustc_mir/transform/qualify_consts.rs | 19 +++++- src/librustc_mir/transform/simplify_cfg.rs | 14 +++-- src/librustc_mir/transform/type_check.rs | 2 + src/librustc_trans/base.rs | 5 +- .../auxiliary/dummy_mir_pass.rs | 5 +- 12 files changed, 152 insertions(+), 30 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 828a48532a2..1480ecfc50e 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -17,6 +17,8 @@ use mir::repr::Mir; use ty::TyCtxt; use syntax::ast::NodeId; +use std::fmt; + /// Where a specific Mir comes from. #[derive(Debug, Copy, Clone)] pub enum MirSource { @@ -70,16 +72,32 @@ impl<'a, 'tcx> MirSource { /// Various information about pass. pub trait Pass { - // fn name() for printouts of various sorts? // fn should_run(Session) to check if pass should run? fn dep_node(&self, def_id: DefId) -> DepNode { DepNode::MirPass(def_id) } + fn name(&self) -> &str; + fn disambiguator<'a>(&'a self) -> Option> { None } } /// A pass which inspects the whole MirMap. pub trait MirMapPass<'tcx>: Pass { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>); + fn run_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + map: &mut MirMap<'tcx>, + hooks: &mut [Box MirPassHook<'s>>]); +} + +pub trait MirPassHook<'tcx>: Pass { + fn on_mir_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + pass: &Pass, + is_after: bool + ); } /// A pass which inspects Mir of functions in isolation. @@ -94,16 +112,33 @@ pub trait MirPass<'tcx>: Pass { } impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { + fn run_pass<'a>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + map: &mut MirMap<'tcx>, + hooks: &mut [Box 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 src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, false); + } MirPass::run_pass(self, tcx, src, mir); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, true); + } for (i, mir) in mir.promoted.iter_mut().enumerate() { + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, false); + } self.run_pass_on_promoted(tcx, id, i, mir); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, true); + } } } } @@ -112,6 +147,7 @@ impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { /// A manager for MIR passes. pub struct Passes { passes: Vec MirMapPass<'tcx>>>, + pass_hooks: Vec MirPassHook<'tcx>>>, plugin_passes: Vec MirMapPass<'tcx>>> } @@ -119,6 +155,7 @@ impl<'a, 'tcx> Passes { pub fn new() -> Passes { let passes = Passes { passes: Vec::new(), + pass_hooks: Vec::new(), plugin_passes: Vec::new() }; passes @@ -126,10 +163,10 @@ impl<'a, 'tcx> Passes { pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { for pass in &mut self.plugin_passes { - pass.run_pass(tcx, map); + pass.run_pass(tcx, map, &mut self.pass_hooks); } for pass in &mut self.passes { - pass.run_pass(tcx, map); + pass.run_pass(tcx, map, &mut self.pass_hooks); } } @@ -137,6 +174,11 @@ impl<'a, 'tcx> Passes { pub fn push_pass(&mut self, pass: Box MirMapPass<'b>>) { self.passes.push(pass); } + + /// Pushes a pass hook. + pub fn push_hook(&mut self, hook: Box MirPassHook<'b>>) { + self.pass_hooks.push(hook); + } } /// Copies the plugin passes. diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 6ecf4a66d62..593a997bed5 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -23,7 +23,6 @@ use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::util::nodemap::FnvHashMap; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::pretty; use syntax::codemap::Span; use std::fmt; @@ -66,13 +65,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { patch: MirPatch::new(mir), }.elaborate() }; - pretty::dump_mir(tcx, "elaborate_drops", &0, src, mir, None); elaborate_patch.apply(mir); - pretty::dump_mir(tcx, "elaborate_drops", &1, src, mir, None); } } -impl Pass for ElaborateDrops {} +impl Pass for ElaborateDrops { + fn name(&self) -> &str { "elaborate-drops" } +} struct InitializationData { live: IdxSetBuf, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 67eb2479994..60a4da68f03 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -976,6 +976,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "MIR passes", || { let mut passes = sess.mir_passes.borrow_mut(); // Push all the built-in passes. + passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("initial")); passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass(box mir::transform::type_check::TypeckMir); @@ -1045,6 +1046,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // to LLVM code. time(time_passes, "Prepare MIR codegen passes", || { let mut passes = ::rustc::mir::transform::Passes::new(); + passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads")); @@ -1056,7 +1058,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); - passes.push_pass(box mir::transform::dump_mir::DumpMir("pre_trans")); + passes.push_pass(box mir::transform::dump_mir::Marker("pre-trans")); passes.run_passes(tcx, &mut mir_map); }); diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 63e975128c7..15cfa8046ed 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -82,4 +82,6 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards { } } -impl Pass for AddCallGuards {} +impl Pass for AddCallGuards { + fn name(&self) -> &str { "add-call-guards" } +} diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index fb49f951ecd..941229d2c02 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -10,18 +10,66 @@ //! This pass just dumps MIR at a specified point. +use std::fmt; + use rustc::ty::TyCtxt; use rustc::mir::repr::*; -use rustc::mir::transform::{Pass, MirPass, MirSource}; +use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource}; use pretty; -pub struct DumpMir<'a>(pub &'a str); +pub struct Marker<'a>(pub &'a str); -impl<'b, 'tcx> MirPass<'tcx> for DumpMir<'b> { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>) { - pretty::dump_mir(tcx, self.0, &0, src, mir, None); +impl<'b, 'tcx> MirPass<'tcx> for Marker<'b> { + fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _src: MirSource, _mir: &mut Mir<'tcx>) + {} +} + +impl<'b> Pass for Marker<'b> { + fn name(&self) -> &str { self.0 } +} + +pub struct Disambiguator<'a> { + pass: &'a Pass, + is_after: bool +} + +impl<'a> fmt::Display for Disambiguator<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let title = if self.is_after { "after" } else { "before" }; + if let Some(fmt) = self.pass.disambiguator() { + write!(formatter, "{}-{}", fmt, title) + } else { + write!(formatter, "{}", title) + } } } -impl<'b> Pass for DumpMir<'b> {} +pub struct DumpMir; + +impl<'tcx> MirPassHook<'tcx> for DumpMir { + fn on_mir_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + pass: &Pass, + is_after: bool) + { + pretty::dump_mir( + tcx, + pass.name(), + &Disambiguator { + pass: pass, + is_after: is_after + }, + src, + mir, + None + ); + } +} + +impl<'b> Pass for DumpMir { + fn name(&self) -> &str { "dump-mir" } +} diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 485ca3ea84a..4c71fe98ec2 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -43,7 +43,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { pub struct EraseRegions; -impl Pass for EraseRegions {} +impl Pass for EraseRegions { + fn name(&self) -> &str { "erase-regions" } +} impl<'tcx> MirPass<'tcx> for EraseRegions { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 818f060ed44..610208de19a 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -50,4 +50,6 @@ impl<'tcx> MirPass<'tcx> for NoLandingPads { } } -impl Pass for NoLandingPads {} +impl Pass for NoLandingPads { + fn name(&self) -> &str { "no-landing-pads" } +} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 5ea5949e107..9f95342a68b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -25,8 +25,8 @@ use rustc::ty::{self, TyCtxt, Ty}; use rustc::ty::cast::CastTy; use rustc::mir::repr::*; use rustc::mir::mir_map::MirMap; -use rustc::mir::transform::{Pass, MirMapPass, MirSource}; use rustc::mir::traversal::{self, ReversePostorder}; +use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::util::nodemap::DefIdMap; use syntax::abi::Abi; @@ -906,10 +906,15 @@ fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct QualifyAndPromoteConstants; -impl Pass for QualifyAndPromoteConstants {} +impl Pass for QualifyAndPromoteConstants { + fn name(&self) -> &str { "qualify-consts" } +} impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { + fn run_pass<'a>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + map: &mut MirMap<'tcx>, + hooks: &mut [Box MirPassHook<'s>>]) { let mut qualif_map = DefIdMap(); // First, visit `const` items, potentially recursing, to get @@ -945,6 +950,10 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { }; let param_env = ty::ParameterEnvironment::for_item(tcx, id); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, false); + } + if mode == Mode::Fn || mode == Mode::ConstFn { // This is ugly because Qualifier holds onto mir, // which can't be mutated until its scope ends. @@ -972,6 +981,10 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { qualifier.qualify_const(); } + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, true); + } + // Statics must be Sync. if mode == Mode::Static { let ty = mir.return_ty.unwrap(); diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 9cee6b11c07..8c267581980 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -39,7 +39,8 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::traversal; -use pretty; + +use std::fmt; use std::mem; pub struct SimplifyCfg<'a> { label: &'a str } @@ -51,20 +52,23 @@ impl<'a> SimplifyCfg<'a> { } impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { - pretty::dump_mir(tcx, "simplify_cfg", &format!("{}-before", self.label), src, mir, None); + fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { simplify_branches(mir); remove_dead_blocks(mir); merge_consecutive_blocks(mir); remove_dead_blocks(mir); - pretty::dump_mir(tcx, "simplify_cfg", &format!("{}-after", self.label), src, mir, None); // FIXME: Should probably be moved into some kind of pass manager mir.basic_blocks_mut().raw.shrink_to_fit(); } } -impl<'l> Pass for SimplifyCfg<'l> {} +impl<'l> Pass for SimplifyCfg<'l> { + fn name(&self) -> &str { "simplify-cfg" } + fn disambiguator<'a>(&'a self) -> Option> { + Some(Box::new(self.label)) + } +} fn merge_consecutive_blocks(mir: &mut Mir) { let mut pred_count: IndexVec<_, _> = diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index e4398fcab31..60698a184da 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -717,4 +717,6 @@ impl Pass for TypeckMir { fn dep_node(&self, def_id: DefId) -> DepNode { DepNode::MirTypeck(def_id) } + + fn name(&self) -> &str { "typeck-mir" } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index b7e8e618abb..381bd24d9a4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1844,7 +1844,10 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::emit_uwtable(llfndecl, true); } - debug!("trans_closure(..., {})", instance); + // this is an info! to allow collecting monomorphization statistics + // and to allow finding the last function before LLVM aborts from + // release builds. + info!("trans_closure(..., {})", instance); let fn_ty = FnType::new(ccx, abi, sig, &[]); diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs index 0abf71ba444..b7d49dbb83c 100644 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs @@ -28,7 +28,10 @@ use rustc_plugin::Registry; struct Pass; -impl transform::Pass for Pass {} +impl transform::Pass for Pass { + fn name(&self) -> &str { "dummy-mir-pass" } +} + impl<'tcx> MirPass<'tcx> for Pass { fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {