Skip to content

Commit 661976c

Browse files
committed
Add a human-readable textual form for MIR.
This can be dumped for a particular `fn` with the attribute `#![rustc_mir(pretty = "filename.mir"]`.
1 parent badc23b commit 661976c

File tree

3 files changed

+103
-17
lines changed

3 files changed

+103
-17
lines changed

src/librustc_mir/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ extern crate rustc_back;
2929
extern crate syntax;
3030

3131
pub mod build;
32-
pub mod mir_map;
32+
pub mod graphviz;
3333
mod hair;
34-
mod graphviz;
34+
pub mod mir_map;
35+
pub mod pretty;
3536
pub mod transform;
36-

src/librustc_mir/mir_map.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern crate rustc_front;
2222

2323
use build;
2424
use graphviz;
25+
use pretty;
2526
use transform::*;
2627
use rustc::mir::repr::Mir;
2728
use hair::cx::Cx;
@@ -152,29 +153,29 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
152153
.flat_map(|a| a.meta_item_list())
153154
.flat_map(|l| l.iter());
154155
for item in meta_item_list {
155-
if item.check_name("graphviz") {
156+
if item.check_name("graphviz") || item.check_name("pretty") {
156157
match item.value_str() {
157158
Some(s) => {
158-
match
159-
File::create(format!("{}{}", prefix, s))
160-
.and_then(|ref mut output| {
159+
let filename = format!("{}{}", prefix, s);
160+
let result = File::create(&filename).and_then(|ref mut output| {
161+
if item.check_name("graphviz") {
161162
graphviz::write_mir_graphviz(&mir, output)
162-
})
163-
{
164-
Ok(()) => { }
165-
Err(e) => {
166-
self.tcx.sess.span_fatal(
167-
item.span,
168-
&format!("Error writing graphviz \
169-
results to `{}`: {}",
170-
s, e));
163+
} else {
164+
pretty::write_mir_pretty(&mir, output)
171165
}
166+
});
167+
168+
if let Err(e) = result {
169+
self.tcx.sess.span_fatal(
170+
item.span,
171+
&format!("Error writing MIR {} results to `{}`: {}",
172+
item.name(), filename, e));
172173
}
173174
}
174175
None => {
175176
self.tcx.sess.span_err(
176177
item.span,
177-
"graphviz attribute requires a path");
178+
&format!("{} attribute requires a path", item.name()));
178179
}
179180
}
180181
}

src/librustc_mir/pretty.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::mir::repr::*;
12+
use rustc::middle::ty;
13+
use std::io::{self, Write};
14+
15+
const INDENT: &'static str = " ";
16+
17+
/// Write out a human-readable textual representation for the given MIR.
18+
pub fn write_mir_pretty<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
19+
try!(write_mir_intro(mir, w));
20+
21+
// Nodes
22+
for block in mir.all_basic_blocks() {
23+
try!(write_basic_block(block, mir, w));
24+
}
25+
26+
writeln!(w, "}}")
27+
}
28+
29+
/// Write out a human-readable textual representation for the given basic block.
30+
fn write_basic_block<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
31+
let data = mir.basic_block_data(block);
32+
33+
// Basic block label at the top.
34+
try!(writeln!(w, "\n{}{:?}: {{", INDENT, block));
35+
36+
// List of statements in the middle.
37+
for statement in &data.statements {
38+
try!(writeln!(w, "{0}{0}{1:?};", INDENT, statement));
39+
}
40+
41+
// Terminator at the bottom.
42+
try!(writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator));
43+
44+
writeln!(w, "{}}}", INDENT)
45+
}
46+
47+
/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
48+
/// local variables (both user-defined bindings and compiler temporaries).
49+
fn write_mir_intro<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
50+
try!(write!(w, "fn("));
51+
52+
// fn argument types.
53+
for (i, arg) in mir.arg_decls.iter().enumerate() {
54+
if i > 0 {
55+
try!(write!(w, ", "));
56+
}
57+
try!(write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty));
58+
}
59+
60+
try!(write!(w, ") -> "));
61+
62+
// fn return type.
63+
match mir.return_ty {
64+
ty::FnOutput::FnConverging(ty) => try!(write!(w, "{}", ty)),
65+
ty::FnOutput::FnDiverging => try!(write!(w, "!")),
66+
}
67+
68+
try!(writeln!(w, " {{"));
69+
70+
// User variable types (including the user's name in a comment).
71+
for (i, var) in mir.var_decls.iter().enumerate() {
72+
try!(write!(w, "{}let ", INDENT));
73+
if var.mutability == Mutability::Mut {
74+
try!(write!(w, "mut "));
75+
}
76+
try!(writeln!(w, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name));
77+
}
78+
79+
// Compiler-introduced temporary types.
80+
for (i, temp) in mir.temp_decls.iter().enumerate() {
81+
try!(writeln!(w, "{}let {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty));
82+
}
83+
84+
Ok(())
85+
}

0 commit comments

Comments
 (0)