Skip to content

Commit

Permalink
add hook infrastructure for automatically dumping MIR on every pass
Browse files Browse the repository at this point in the history
  • Loading branch information
arielb1 authored and Ariel Ben-Yehuda committed Jun 9, 2016
1 parent 798be90 commit 2ee00e6
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 30 deletions.
52 changes: 47 additions & 5 deletions src/librustc/mir/transform.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
}
}
}
Expand All @@ -112,31 +147,38 @@ 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>>>
}

impl<'a, 'tcx> Passes {
pub fn new() -> Passes {
let passes = Passes {
passes: Vec::new(),
pass_hooks: Vec::new(),
plugin_passes: Vec::new()
};
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);
}
}

/// Pushes a built-in pass.
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.
Expand Down
7 changes: 3 additions & 4 deletions src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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>,
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_driver/driver.rs
Expand Up @@ -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);
Expand Down Expand Up @@ -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"));

Expand All @@ -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);
});
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_mir/transform/add_call_guards.rs
Expand Up @@ -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" }
}
62 changes: 55 additions & 7 deletions src/librustc_mir/transform/dump_mir.rs
Expand Up @@ -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 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)
}
}
}

pub struct DumpMir;

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<'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<'b> {}
impl<'b> Pass for DumpMir {
fn name(&self) -> &str { "dump-mir" }
}
4 changes: 3 additions & 1 deletion src/librustc_mir/transform/erase_regions.rs
Expand Up @@ -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>,
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_mir/transform/no_landing_pads.rs
Expand Up @@ -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" }
}
19 changes: 16 additions & 3 deletions src/librustc_mir/transform/qualify_consts.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down
14 changes: 9 additions & 5 deletions src/librustc_mir/transform/simplify_cfg.rs
Expand Up @@ -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 }
Expand All @@ -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<_, _> =
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/transform/type_check.rs
Expand Up @@ -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" }
}
5 changes: 4 additions & 1 deletion src/librustc_trans/base.rs
Expand Up @@ -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, &[]);

Expand Down
5 changes: 4 additions & 1 deletion src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
Expand Up @@ -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>) {
Expand Down

0 comments on commit 2ee00e6

Please sign in to comment.