augment MIR pretty printer to print scopes

This commit is contained in:
Niko Matsakis 2016-03-22 10:08:44 -04:00
parent caac0b969f
commit d32bde3311
3 changed files with 91 additions and 12 deletions

View file

@ -197,7 +197,7 @@ pub struct ArgDecl<'tcx> {
/// list of the `Mir`.
///
/// (We use a `u32` internally just to save memory.)
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct BasicBlock(u32);
impl BasicBlock {
@ -668,7 +668,7 @@ impl IndexMut<ScopeId> for ScopeDataVec {
}
}
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct ScopeId(u32);
impl ScopeId {

View file

@ -73,6 +73,7 @@ pub struct ScopeAuxiliary {
pub postdoms: Vec<Location>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Location {
/// the location is within this block
pub block: BasicBlock,

View file

@ -8,60 +8,138 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use build::Location;
use rustc::mir::repr::*;
use rustc::middle::ty;
use rustc::middle::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use std::io::{self, Write};
use syntax::ast::NodeId;
use syntax::codemap::Span;
const INDENT: &'static str = " ";
/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &ty::TyCtxt<'tcx>,
pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &TyCtxt<'tcx>,
iter: I,
w: &mut Write)
-> io::Result<()>
where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
{
let no_annotations = FnvHashMap();
for (&node_id, mir) in iter {
write_mir_fn(tcx, node_id, mir, w)?;
write_mir_fn(tcx, node_id, mir, w, &no_annotations)?;
}
Ok(())
}
pub fn write_mir_fn<'tcx>(tcx: &ty::TyCtxt<'tcx>,
pub enum Annotation {
EnterScope(ScopeId),
ExitScope(ScopeId),
}
pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
node_id: NodeId,
mir: &Mir<'tcx>,
w: &mut Write)
w: &mut Write,
annotations: &FnvHashMap<Location, Vec<Annotation>>)
-> io::Result<()> {
write_mir_intro(tcx, node_id, mir, w)?;
for block in mir.all_basic_blocks() {
write_basic_block(block, mir, w)?;
write_basic_block(tcx, block, mir, w, annotations)?;
}
// construct a scope tree
let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
for (index, scope_data) in mir.scopes.vec.iter().enumerate() {
scope_tree.entry(scope_data.parent_scope)
.or_insert(vec![])
.push(ScopeId::new(index));
}
write_scope_tree(tcx, mir, &scope_tree, w, None, 1)?;
writeln!(w, "}}")?;
Ok(())
}
/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(block: BasicBlock, mir: &Mir, w: &mut Write) -> io::Result<()> {
fn write_basic_block(tcx: &TyCtxt,
block: BasicBlock,
mir: &Mir,
w: &mut Write,
annotations: &FnvHashMap<Location, Vec<Annotation>>)
-> io::Result<()> {
let data = mir.basic_block_data(block);
// Basic block label at the top.
writeln!(w, "\n{}{:?}: {{", INDENT, block)?;
// List of statements in the middle.
let mut current_location = Location { block: block, statement_index: 0 };
for statement in &data.statements {
writeln!(w, "{0}{0}{1:?};", INDENT, statement)?;
if let Some(ref annotations) = annotations.get(&current_location) {
for annotation in annotations.iter() {
match *annotation {
Annotation::EnterScope(id) =>
writeln!(w, "{0}{0}// Enter Scope({1})",
INDENT, id.index())?,
Annotation::ExitScope(id) =>
writeln!(w, "{0}{0}// Exit Scope({1})",
INDENT, id.index())?,
}
}
}
writeln!(w, "{0}{0}{1:?}; // {2}",
INDENT,
statement,
comment(tcx, statement.scope, statement.span))?;
current_location.statement_index += 1;
}
// Terminator at the bottom.
writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator())?;
writeln!(w, "{0}{0}{1:?}; // {2}",
INDENT,
data.terminator(),
comment(tcx, data.terminator().scope, data.terminator().span))?;
writeln!(w, "{}}}", INDENT)
}
fn comment(tcx: &TyCtxt,
scope: ScopeId,
span: Span)
-> String {
format!("Scope({}) at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}
fn write_scope_tree(tcx: &TyCtxt,
mir: &Mir,
scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>,
w: &mut Write,
parent: Option<ScopeId>,
depth: usize)
-> io::Result<()> {
for &child in scope_tree.get(&parent).unwrap_or(&vec![]) {
let indent = depth * INDENT.len();
let data = &mir.scopes[child];
assert_eq!(data.parent_scope, parent);
writeln!(w, "{0:1$}Scope({2}) {{", "", indent, child.index())?;
let indent = indent + INDENT.len();
if let Some(parent) = parent {
writeln!(w, "{0:1$}Parent: Scope({2})", "", indent, parent.index())?;
}
writeln!(w, "{0:1$}Extent: {2:?}",
"", indent,
tcx.region_maps.code_extent_data(data.extent))?;
write_scope_tree(tcx, mir, scope_tree, w, Some(child), depth + 1)?;
}
Ok(())
}
/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
fn write_mir_intro(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
-> io::Result<()> {
write!(w, "fn {}(", tcx.map.path_to_string(nid))?;