add hook infrastructure for automatically dumping MIR on every pass
This commit is contained in:
parent
798be90648
commit
2ee00e6d9d
@ -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.
|
||||
|
@ -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>,
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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" }
|
||||
}
|
||||
|
@ -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" }
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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" }
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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<_, _> =
|
||||
|
@ -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" }
|
||||
}
|
||||
|
@ -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, &[]);
|
||||
|
||||
|
@ -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>) {
|
||||
|
Loading…
Reference in New Issue
Block a user