add hook infrastructure for automatically dumping MIR on every pass

This commit is contained in:
Ariel Ben-Yehuda 2016-06-08 21:03:06 +03:00 committed by Ariel Ben-Yehuda
parent 798be90648
commit 2ee00e6d9d
12 changed files with 152 additions and 30 deletions

View File

@ -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<DefId> {
DepNode::MirPass(def_id)
}
fn name(&self) -> &str;
fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> { 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<for<'s> 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<for<'s> MirPassHook<'s>>])
{
for (&id, mir) in &mut map.map {
let def_id = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
let 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<Box<for<'tcx> MirMapPass<'tcx>>>,
pass_hooks: Vec<Box<for<'tcx> MirPassHook<'tcx>>>,
plugin_passes: Vec<Box<for<'tcx> 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<for<'b> MirMapPass<'b>>) {
self.passes.push(pass);
}
/// Pushes a pass hook.
pub fn push_hook(&mut self, hook: Box<for<'b> MirPassHook<'b>>) {
self.pass_hooks.push(hook);
}
}
/// Copies the plugin passes.

View File

@ -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<MovePathIndex>,

View File

@ -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);
});

View File

@ -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" }
}

View File

@ -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" }
}

View File

@ -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>,

View File

@ -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" }
}

View File

@ -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<for<'s> 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();

View File

@ -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<Box<fmt::Display+'a>> {
Some(Box::new(self.label))
}
}
fn merge_consecutive_blocks(mir: &mut Mir) {
let mut pred_count: IndexVec<_, _> =

View File

@ -717,4 +717,6 @@ impl Pass for TypeckMir {
fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
DepNode::MirTypeck(def_id)
}
fn name(&self) -> &str { "typeck-mir" }
}

View File

@ -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, &[]);

View File

@ -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>) {