Expand mir dump in order to handle NLL pass
Extend `dump_mir` and functions it calls in order to allow callers to add custom information. We do this by adding an enum `PassWhere` and an extra argument of type `FnMut(PassWhere, &mut Write) -> io::Result<()>`. This callback is responsible for printing the extra information when MIR is dumped at various stages. For the "nll" pass, use the new mechanism to dump the `Region` information after the header, but before the control flow graph for every function. In the interest of keeping the output somewhat concise, implement a custom Debug impl for `Region` Open Questions: * What should we call what has been called `PassWhere` so far?
This commit is contained in:
parent
271a492cb2
commit
54d63a0d33
7 changed files with 107 additions and 44 deletions
|
@ -149,7 +149,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
|
|||
mem::transmute::<Mir, Mir<'tcx>>(mir)
|
||||
};
|
||||
|
||||
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
|
||||
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) );
|
||||
|
||||
mir
|
||||
})
|
||||
|
@ -227,7 +227,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
mem::transmute::<Mir, Mir<'tcx>>(mir)
|
||||
};
|
||||
|
||||
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
|
||||
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) );
|
||||
|
||||
mir
|
||||
})
|
||||
|
|
|
@ -65,7 +65,18 @@ impl PassHook for DumpMir {
|
|||
pass_name,
|
||||
&Disambiguator { is_after },
|
||||
source,
|
||||
mir);
|
||||
mir,
|
||||
|_, _| Ok(()) );
|
||||
for (index, promoted_mir) in mir.promoted.iter_enumerated() {
|
||||
let promoted_source = MirSource::Promoted(source.item_id(), index);
|
||||
mir_util::dump_mir(tcx,
|
||||
Some((suite, pass_num)),
|
||||
pass_name,
|
||||
&Disambiguator { is_after },
|
||||
promoted_source,
|
||||
promoted_mir,
|
||||
|_, _| Ok(()) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -587,7 +587,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
|
|||
// unrelated code from the resume part of the function
|
||||
simplify::remove_dead_blocks(&mut mir);
|
||||
|
||||
dump_mir(tcx, None, "generator_drop", &0, source, &mut mir);
|
||||
dump_mir(tcx, None, "generator_drop", &0, source, &mut mir, |_, _| Ok(()) );
|
||||
|
||||
mir
|
||||
}
|
||||
|
@ -673,7 +673,7 @@ fn create_generator_resume_function<'a, 'tcx>(
|
|||
// unrelated code from the drop part of the function
|
||||
simplify::remove_dead_blocks(mir);
|
||||
|
||||
dump_mir(tcx, None, "generator_resume", &0, source, mir);
|
||||
dump_mir(tcx, None, "generator_resume", &0, source, mir, |_, _| Ok(()) );
|
||||
}
|
||||
|
||||
fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo {
|
||||
|
@ -816,14 +816,14 @@ impl MirPass for StateTransform {
|
|||
// This is expanded to a drop ladder in `elaborate_generator_drops`.
|
||||
let drop_clean = insert_clean_drop(mir);
|
||||
|
||||
dump_mir(tcx, None, "generator_pre-elab", &0, source, mir);
|
||||
dump_mir(tcx, None, "generator_pre-elab", &0, source, mir, |_, _| Ok(()) );
|
||||
|
||||
// Expand `drop(generator_struct)` to a drop ladder which destroys upvars.
|
||||
// If any upvars are moved out of, drop elaboration will handle upvar destruction.
|
||||
// However we need to also elaborate the code generated by `insert_clean_drop`.
|
||||
elaborate_generator_drops(tcx, def_id, mir);
|
||||
|
||||
dump_mir(tcx, None, "generator_post-transform", &0, source, mir);
|
||||
dump_mir(tcx, None, "generator_post-transform", &0, source, mir, |_, _| Ok(()) );
|
||||
|
||||
// Create a copy of our MIR and use it to create the drop shim for the generator
|
||||
let drop_shim = create_generator_drop_shim(tcx,
|
||||
|
|
|
@ -19,6 +19,10 @@ use rustc::util::nodemap::FxHashSet;
|
|||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
use util as mir_util;
|
||||
use self::mir_util::PassWhere;
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
|
@ -134,7 +138,7 @@ pub struct NLL;
|
|||
impl MirPass for NLL {
|
||||
fn run_pass<'a, 'tcx>(&self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
_: MirSource,
|
||||
source: MirSource,
|
||||
mir: &mut Mir<'tcx>) {
|
||||
if !tcx.sess.opts.debugging_opts.nll {
|
||||
return;
|
||||
|
@ -145,14 +149,30 @@ impl MirPass for NLL {
|
|||
let mut renumbered_mir = mir.clone();
|
||||
let mut visitor = NLLVisitor::new(infcx);
|
||||
visitor.visit_mir(&mut renumbered_mir);
|
||||
mir_util::dump_mir(tcx, None, "nll", &0, source, mir, |pass_where, out| {
|
||||
if let PassWhere::BeforeCFG = pass_where {
|
||||
for (index, value) in visitor.regions.iter_enumerated() {
|
||||
writeln!(out, "// R{:03}: {:?}", index.0, value)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
let _results = visitor.into_results();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
#[derive(Clone, Default, PartialEq, Eq)]
|
||||
struct Region {
|
||||
points: FxHashSet<Location>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Region {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(formatter, "{:?}", self.points)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
newtype_index!(RegionIndex);
|
||||
|
|
|
@ -232,7 +232,7 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
writeln!(w, "{} {{{}}}", prefix, live.join(", "))
|
||||
};
|
||||
print(w, " ", &result.ins)?;
|
||||
write_basic_block(tcx, block, mir, w)?;
|
||||
write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?;
|
||||
print(w, " ", &result.outs)?;
|
||||
if block.index() + 1 != mir.basic_blocks().len() {
|
||||
writeln!(w, "")?;
|
||||
|
|
|
@ -17,6 +17,6 @@ mod graphviz;
|
|||
mod pretty;
|
||||
pub mod liveness;
|
||||
|
||||
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty};
|
||||
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};
|
||||
pub use self::graphviz::{write_mir_graphviz};
|
||||
pub use self::graphviz::write_node_label as write_graphviz_node_label;
|
||||
|
|
|
@ -25,6 +25,22 @@ const INDENT: &'static str = " ";
|
|||
/// Alignment for lining up comments following MIR statements
|
||||
const ALIGN: usize = 40;
|
||||
|
||||
/// An indication of where we are in the control flow graph. Used for printing
|
||||
/// extra information in `dump_mir`
|
||||
pub enum PassWhere {
|
||||
/// We have not started dumping the control flow graph, but we are about to.
|
||||
BeforeCFG,
|
||||
|
||||
/// We just finished dumping the control flow graph. This is right before EOF
|
||||
AfterCFG,
|
||||
|
||||
/// We are about to start dumping the given basic block.
|
||||
BeforeBlock(BasicBlock),
|
||||
|
||||
/// We are just about to dumpt the given statement or terminator.
|
||||
InCFG(Location),
|
||||
}
|
||||
|
||||
/// If the session is properly configured, dumps a human-readable
|
||||
/// representation of the mir into:
|
||||
///
|
||||
|
@ -39,12 +55,16 @@ const ALIGN: usize = 40;
|
|||
/// - `substring1&substring2,...` -- `&`-separated list of substrings
|
||||
/// 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: Option<(MirSuite, MirPassIndex)>,
|
||||
pass_name: &str,
|
||||
disambiguator: &Display,
|
||||
source: MirSource,
|
||||
mir: &Mir<'tcx>) {
|
||||
pub fn dump_mir<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pass_num: Option<(MirSuite, MirPassIndex)>,
|
||||
pass_name: &str,
|
||||
disambiguator: &Display,
|
||||
source: MirSource,
|
||||
mir: &Mir<'tcx>,
|
||||
extra_data: F)
|
||||
where
|
||||
F: FnMut(PassWhere, &mut Write) -> io::Result<()>
|
||||
{
|
||||
if !dump_enabled(tcx, pass_name, source) {
|
||||
return;
|
||||
}
|
||||
|
@ -53,12 +73,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
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,
|
||||
promoted_source, promoted_mir);
|
||||
}
|
||||
disambiguator, source, mir, extra_data);
|
||||
}
|
||||
|
||||
pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
@ -85,13 +100,17 @@ pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
// `item_path_str()` would otherwise trigger `type_of`, and this can
|
||||
// run while we are already attempting to evaluate `type_of`.
|
||||
|
||||
fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pass_num: Option<(MirSuite, MirPassIndex)>,
|
||||
pass_name: &str,
|
||||
node_path: &str,
|
||||
disambiguator: &Display,
|
||||
source: MirSource,
|
||||
mir: &Mir<'tcx>) {
|
||||
fn dump_matched_mir_node<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pass_num: Option<(MirSuite, MirPassIndex)>,
|
||||
pass_name: &str,
|
||||
node_path: &str,
|
||||
disambiguator: &Display,
|
||||
source: MirSource,
|
||||
mir: &Mir<'tcx>,
|
||||
mut extra_data: F)
|
||||
where
|
||||
F: FnMut(PassWhere, &mut Write) -> io::Result<()>
|
||||
{
|
||||
let promotion_id = match source {
|
||||
MirSource::Promoted(_, id) => format!("-{:?}", id),
|
||||
MirSource::GeneratorDrop(_) => format!("-drop"),
|
||||
|
@ -125,7 +144,9 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
writeln!(file, "// generator_layout = {:?}", layout)?;
|
||||
}
|
||||
writeln!(file, "")?;
|
||||
write_mir_fn(tcx, source, mir, &mut file)?;
|
||||
extra_data(PassWhere::BeforeCFG, &mut file)?;
|
||||
write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?;
|
||||
extra_data(PassWhere::AfterCFG, &mut file)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
@ -152,24 +173,29 @@ pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
let id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
let src = MirSource::from_node(tcx, id);
|
||||
write_mir_fn(tcx, src, mir, w)?;
|
||||
write_mir_fn(tcx, src, mir, &mut |_, _| Ok(()), w)?;
|
||||
|
||||
for (i, mir) in mir.promoted.iter_enumerated() {
|
||||
writeln!(w, "")?;
|
||||
write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?;
|
||||
write_mir_fn(tcx, MirSource::Promoted(id, i), mir, &mut |_, _| Ok(()), w)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
src: MirSource,
|
||||
mir: &Mir<'tcx>,
|
||||
w: &mut Write)
|
||||
-> io::Result<()> {
|
||||
pub fn write_mir_fn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
src: MirSource,
|
||||
mir: &Mir<'tcx>,
|
||||
extra_data: &mut F,
|
||||
w: &mut Write)
|
||||
-> io::Result<()>
|
||||
where
|
||||
F: FnMut(PassWhere, &mut Write) -> io::Result<()>
|
||||
{
|
||||
write_mir_intro(tcx, src, mir, w)?;
|
||||
for block in mir.basic_blocks().indices() {
|
||||
write_basic_block(tcx, block, mir, w)?;
|
||||
extra_data(PassWhere::BeforeBlock(block), w)?;
|
||||
write_basic_block(tcx, block, mir, extra_data, w)?;
|
||||
if block.index() + 1 != mir.basic_blocks().len() {
|
||||
writeln!(w, "")?;
|
||||
}
|
||||
|
@ -180,11 +206,15 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
}
|
||||
|
||||
/// Write out a human-readable textual representation for the given basic block.
|
||||
pub fn write_basic_block(tcx: TyCtxt,
|
||||
block: BasicBlock,
|
||||
mir: &Mir,
|
||||
w: &mut Write)
|
||||
-> io::Result<()> {
|
||||
pub fn write_basic_block<F>(tcx: TyCtxt,
|
||||
block: BasicBlock,
|
||||
mir: &Mir,
|
||||
extra_data: &mut F,
|
||||
w: &mut Write)
|
||||
-> io::Result<()>
|
||||
where
|
||||
F: FnMut(PassWhere, &mut Write) -> io::Result<()>
|
||||
{
|
||||
let data = &mir[block];
|
||||
|
||||
// Basic block label at the top.
|
||||
|
@ -195,6 +225,7 @@ pub fn write_basic_block(tcx: TyCtxt,
|
|||
// List of statements in the middle.
|
||||
let mut current_location = Location { block: block, statement_index: 0 };
|
||||
for statement in &data.statements {
|
||||
extra_data(PassWhere::InCFG(current_location), w)?;
|
||||
let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
|
||||
writeln!(w, "{0:1$} // {2}",
|
||||
indented_mir,
|
||||
|
@ -205,6 +236,7 @@ pub fn write_basic_block(tcx: TyCtxt,
|
|||
}
|
||||
|
||||
// Terminator at the bottom.
|
||||
extra_data(PassWhere::InCFG(current_location), w)?;
|
||||
let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
|
||||
writeln!(w, "{0:1$} // {2}",
|
||||
indented_terminator,
|
||||
|
|
Loading…
Reference in a new issue