|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
| 11 | +use build::Location; |
11 | 12 | use rustc::mir::repr::*;
|
12 |
| -use rustc::middle::ty; |
| 13 | +use rustc::middle::ty::{self, TyCtxt}; |
| 14 | +use rustc_data_structures::fnv::FnvHashMap; |
13 | 15 | use std::io::{self, Write};
|
14 | 16 | use syntax::ast::NodeId;
|
| 17 | +use syntax::codemap::Span; |
15 | 18 |
|
16 | 19 | const INDENT: &'static str = " ";
|
17 | 20 |
|
18 | 21 | /// Write out a human-readable textual representation for the given MIR.
|
19 |
| -pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &ty::TyCtxt<'tcx>, |
| 22 | +pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &TyCtxt<'tcx>, |
20 | 23 | iter: I,
|
21 | 24 | w: &mut Write)
|
22 | 25 | -> io::Result<()>
|
23 | 26 | where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
|
24 | 27 | {
|
| 28 | + let no_annotations = FnvHashMap(); |
25 | 29 | for (&node_id, mir) in iter {
|
26 |
| - write_mir_fn(tcx, node_id, mir, w)?; |
| 30 | + write_mir_fn(tcx, node_id, mir, w, &no_annotations)?; |
27 | 31 | }
|
28 | 32 | Ok(())
|
29 | 33 | }
|
30 | 34 |
|
31 |
| -pub fn write_mir_fn<'tcx>(tcx: &ty::TyCtxt<'tcx>, |
| 35 | +pub enum Annotation { |
| 36 | + EnterScope(ScopeId), |
| 37 | + ExitScope(ScopeId), |
| 38 | +} |
| 39 | + |
| 40 | +pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>, |
32 | 41 | node_id: NodeId,
|
33 | 42 | mir: &Mir<'tcx>,
|
34 |
| - w: &mut Write) |
| 43 | + w: &mut Write, |
| 44 | + annotations: &FnvHashMap<Location, Vec<Annotation>>) |
35 | 45 | -> io::Result<()> {
|
36 | 46 | write_mir_intro(tcx, node_id, mir, w)?;
|
37 | 47 | for block in mir.all_basic_blocks() {
|
38 |
| - write_basic_block(block, mir, w)?; |
| 48 | + write_basic_block(tcx, block, mir, w, annotations)?; |
| 49 | + } |
| 50 | + |
| 51 | + // construct a scope tree |
| 52 | + let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap(); |
| 53 | + for (index, scope_data) in mir.scopes.vec.iter().enumerate() { |
| 54 | + scope_tree.entry(scope_data.parent_scope) |
| 55 | + .or_insert(vec![]) |
| 56 | + .push(ScopeId::new(index)); |
39 | 57 | }
|
| 58 | + write_scope_tree(tcx, mir, &scope_tree, w, None, 1)?; |
| 59 | + |
40 | 60 | writeln!(w, "}}")?;
|
41 | 61 | Ok(())
|
42 | 62 | }
|
43 | 63 |
|
44 | 64 | /// Write out a human-readable textual representation for the given basic block.
|
45 |
| -fn write_basic_block(block: BasicBlock, mir: &Mir, w: &mut Write) -> io::Result<()> { |
| 65 | +fn write_basic_block(tcx: &TyCtxt, |
| 66 | + block: BasicBlock, |
| 67 | + mir: &Mir, |
| 68 | + w: &mut Write, |
| 69 | + annotations: &FnvHashMap<Location, Vec<Annotation>>) |
| 70 | + -> io::Result<()> { |
46 | 71 | let data = mir.basic_block_data(block);
|
47 | 72 |
|
48 | 73 | // Basic block label at the top.
|
49 | 74 | writeln!(w, "\n{}{:?}: {{", INDENT, block)?;
|
50 | 75 |
|
51 | 76 | // List of statements in the middle.
|
| 77 | + let mut current_location = Location { block: block, statement_index: 0 }; |
52 | 78 | for statement in &data.statements {
|
53 |
| - writeln!(w, "{0}{0}{1:?};", INDENT, statement)?; |
| 79 | + if let Some(ref annotations) = annotations.get(¤t_location) { |
| 80 | + for annotation in annotations.iter() { |
| 81 | + match *annotation { |
| 82 | + Annotation::EnterScope(id) => |
| 83 | + writeln!(w, "{0}{0}// Enter Scope({1})", |
| 84 | + INDENT, id.index())?, |
| 85 | + Annotation::ExitScope(id) => |
| 86 | + writeln!(w, "{0}{0}// Exit Scope({1})", |
| 87 | + INDENT, id.index())?, |
| 88 | + } |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + writeln!(w, "{0}{0}{1:?}; // {2}", |
| 93 | + INDENT, |
| 94 | + statement, |
| 95 | + comment(tcx, statement.scope, statement.span))?; |
| 96 | + |
| 97 | + current_location.statement_index += 1; |
54 | 98 | }
|
55 | 99 |
|
56 | 100 | // Terminator at the bottom.
|
57 |
| - writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator())?; |
| 101 | + writeln!(w, "{0}{0}{1:?}; // {2}", |
| 102 | + INDENT, |
| 103 | + data.terminator(), |
| 104 | + comment(tcx, data.terminator().scope, data.terminator().span))?; |
58 | 105 |
|
59 | 106 | writeln!(w, "{}}}", INDENT)
|
60 | 107 | }
|
61 | 108 |
|
| 109 | +fn comment(tcx: &TyCtxt, |
| 110 | + scope: ScopeId, |
| 111 | + span: Span) |
| 112 | + -> String { |
| 113 | + format!("Scope({}) at {}", scope.index(), tcx.sess.codemap().span_to_string(span)) |
| 114 | +} |
| 115 | + |
| 116 | +fn write_scope_tree(tcx: &TyCtxt, |
| 117 | + mir: &Mir, |
| 118 | + scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>, |
| 119 | + w: &mut Write, |
| 120 | + parent: Option<ScopeId>, |
| 121 | + depth: usize) |
| 122 | + -> io::Result<()> { |
| 123 | + for &child in scope_tree.get(&parent).unwrap_or(&vec![]) { |
| 124 | + let indent = depth * INDENT.len(); |
| 125 | + let data = &mir.scopes[child]; |
| 126 | + assert_eq!(data.parent_scope, parent); |
| 127 | + writeln!(w, "{0:1$}Scope({2}) {{", "", indent, child.index())?; |
| 128 | + let indent = indent + INDENT.len(); |
| 129 | + if let Some(parent) = parent { |
| 130 | + writeln!(w, "{0:1$}Parent: Scope({2})", "", indent, parent.index())?; |
| 131 | + } |
| 132 | + writeln!(w, "{0:1$}Extent: {2:?}", |
| 133 | + "", indent, |
| 134 | + tcx.region_maps.code_extent_data(data.extent))?; |
| 135 | + write_scope_tree(tcx, mir, scope_tree, w, Some(child), depth + 1)?; |
| 136 | + } |
| 137 | + Ok(()) |
| 138 | +} |
| 139 | + |
62 | 140 | /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
|
63 | 141 | /// local variables (both user-defined bindings and compiler temporaries).
|
64 |
| -fn write_mir_intro(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write) |
| 142 | +fn write_mir_intro(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write) |
65 | 143 | -> io::Result<()> {
|
66 | 144 | write!(w, "fn {}(", tcx.map.path_to_string(nid))?;
|
67 | 145 |
|
|
0 commit comments