Skip to content

Commit e2d6494

Browse files
committed
Auto merge of #30707 - tsion:mir-text, r=nikomatsakis
r? @nikomatsakis Textual MIR can be dumped for a particular `fn` with `#![rustc_mir(pretty = "filename.mir")]`. Below is an example of the text output. ```rust struct Point { x: i32, y: i32, } fn example() -> Point { let mut e = Point { x: 1, y: 2 }; let num = 5; let plus_num = |x: i32| x + num; e.y = plus_num(e.x); e } ``` ```rust fn() -> Point { let mut var0: Point; // e let var1: i32; // num let var2: [[email protected]:84:20: 84:36 num:&i32]; // plus_num let mut tmp0: (); let mut tmp1: &i32; let mut tmp2: (); let mut tmp3: i32; let mut tmp4: &[[email protected]:84:20: 84:36 num:&i32]; let mut tmp5: i32; let mut tmp6: Point; bb0: { var0 = Point { x: 1, y: 2 }; var1 = 5; tmp1 = &var1; var2 = [[email protected]:84:20: 84:36] { num: tmp1 }; tmp4 = &var2; tmp5 = var0.0; tmp3 = tmp4(tmp5) -> [return: bb3, unwind: bb4]; } bb1: { return; } bb2: { diverge; } bb3: { drop var0.1; var0.1 = tmp3; drop tmp2; drop var2; drop var0; tmp6 = var0; return = tmp6; drop tmp6; goto -> bb1; } bb4: { drop var2; goto -> bb5; } bb5: { drop var0; goto -> bb2; } } ``` ```rust fn(arg0: &[[email protected]:84:20: 84:36 num:&i32], arg1: i32) -> i32 { let var0: i32; // x let mut tmp0: (); let mut tmp1: i32; let mut tmp2: i32; bb0: { var0 = arg1; tmp1 = var0; tmp2 = (*(*arg0).0); return = Add(tmp1, tmp2); goto -> bb1; } bb1: { return; } bb2: { diverge; } } ```
2 parents d5e2290 + 080994a commit e2d6494

File tree

4 files changed

+191
-40
lines changed

4 files changed

+191
-40
lines changed

src/librustc/mir/repr.rs

+88-23
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_front::hir::InlineAsm;
1818
use syntax::ast::Name;
1919
use syntax::codemap::Span;
2020
use std::borrow::{Cow, IntoCow};
21-
use std::fmt::{Debug, Formatter, Error, Write};
21+
use std::fmt::{self, Debug, Formatter, Write};
2222
use std::{iter, u32};
2323

2424
/// Lowered representation of a single function.
@@ -183,8 +183,8 @@ impl BasicBlock {
183183
}
184184

185185
impl Debug for BasicBlock {
186-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
187-
write!(fmt, "BB({})", self.0)
186+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
187+
write!(fmt, "bb{}", self.0)
188188
}
189189
}
190190

@@ -317,7 +317,7 @@ impl<'tcx> BasicBlockData<'tcx> {
317317
}
318318

319319
impl<'tcx> Debug for Terminator<'tcx> {
320-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
320+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
321321
try!(self.fmt_head(fmt));
322322
let successors = self.successors();
323323
let labels = self.fmt_successor_labels();
@@ -347,7 +347,7 @@ impl<'tcx> Terminator<'tcx> {
347347
/// Write the "head" part of the terminator; that is, its name and the data it uses to pick the
348348
/// successor basic block, if any. The only information not inlcuded is the list of possible
349349
/// successors, which may be rendered differently between the text and the graphviz format.
350-
pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> Result<(), Error> {
350+
pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
351351
use self::Terminator::*;
352352
match *self {
353353
Goto { .. } => write!(fmt, "goto"),
@@ -421,7 +421,7 @@ pub enum DropKind {
421421
}
422422

423423
impl<'tcx> Debug for Statement<'tcx> {
424-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
424+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
425425
use self::StatementKind::*;
426426
match self.kind {
427427
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
@@ -541,7 +541,7 @@ impl<'tcx> Lvalue<'tcx> {
541541
}
542542

543543
impl<'tcx> Debug for Lvalue<'tcx> {
544-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
544+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
545545
use self::Lvalue::*;
546546

547547
match *self {
@@ -551,24 +551,24 @@ impl<'tcx> Debug for Lvalue<'tcx> {
551551
write!(fmt,"arg{:?}", id),
552552
Temp(id) =>
553553
write!(fmt,"tmp{:?}", id),
554-
Static(id) =>
555-
write!(fmt,"Static({:?})", id),
554+
Static(def_id) =>
555+
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
556556
ReturnPointer =>
557-
write!(fmt,"ReturnPointer"),
557+
write!(fmt, "return"),
558558
Projection(ref data) =>
559559
match data.elem {
560560
ProjectionElem::Downcast(ref adt_def, index) =>
561-
write!(fmt,"({:?} as {})", data.base, adt_def.variants[index].name),
561+
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name),
562562
ProjectionElem::Deref =>
563-
write!(fmt,"(*{:?})", data.base),
563+
write!(fmt, "(*{:?})", data.base),
564564
ProjectionElem::Field(field) =>
565-
write!(fmt,"{:?}.{:?}", data.base, field.index()),
565+
write!(fmt, "{:?}.{:?}", data.base, field.index()),
566566
ProjectionElem::Index(ref index) =>
567-
write!(fmt,"{:?}[{:?}]", data.base, index),
567+
write!(fmt, "{:?}[{:?}]", data.base, index),
568568
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
569-
write!(fmt,"{:?}[{:?} of {:?}]", data.base, offset, min_length),
569+
write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length),
570570
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
571-
write!(fmt,"{:?}[-{:?} of {:?}]", data.base, offset, min_length),
571+
write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length),
572572
},
573573
}
574574
}
@@ -588,7 +588,7 @@ pub enum Operand<'tcx> {
588588
}
589589

590590
impl<'tcx> Debug for Operand<'tcx> {
591-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
591+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
592592
use self::Operand::*;
593593
match *self {
594594
Constant(ref a) => write!(fmt, "{:?}", a),
@@ -715,22 +715,87 @@ pub enum UnOp {
715715
}
716716

717717
impl<'tcx> Debug for Rvalue<'tcx> {
718-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
718+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
719719
use self::Rvalue::*;
720720

721721
match *self {
722722
Use(ref lvalue) => write!(fmt, "{:?}", lvalue),
723723
Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b),
724-
Ref(ref a, bk, ref b) => write!(fmt, "&{:?} {:?} {:?}", a, bk, b),
725724
Len(ref a) => write!(fmt, "Len({:?})", a),
726725
Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?})", lv, ty, kind),
727726
BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b),
728727
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
729728
Box(ref t) => write!(fmt, "Box({:?})", t),
730-
Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>{:?}", kind, lvs),
731729
InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm),
732730
Slice { ref input, from_start, from_end } =>
733731
write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
732+
733+
Ref(_, borrow_kind, ref lv) => {
734+
let kind_str = match borrow_kind {
735+
BorrowKind::Shared => "",
736+
BorrowKind::Mut | BorrowKind::Unique => "mut ",
737+
};
738+
write!(fmt, "&{}{:?}", kind_str, lv)
739+
}
740+
741+
Aggregate(ref kind, ref lvs) => {
742+
use self::AggregateKind::*;
743+
744+
fn fmt_tuple(fmt: &mut Formatter, name: &str, lvs: &[Operand]) -> fmt::Result {
745+
let mut tuple_fmt = fmt.debug_tuple(name);
746+
for lv in lvs {
747+
tuple_fmt.field(lv);
748+
}
749+
tuple_fmt.finish()
750+
}
751+
752+
match *kind {
753+
Vec => write!(fmt, "{:?}", lvs),
754+
755+
Tuple => {
756+
if lvs.len() == 1 {
757+
write!(fmt, "({:?},)", lvs[0])
758+
} else {
759+
fmt_tuple(fmt, "", lvs)
760+
}
761+
}
762+
763+
Adt(adt_def, variant, _) => {
764+
let variant_def = &adt_def.variants[variant];
765+
let name = ty::tls::with(|tcx| tcx.item_path_str(variant_def.did));
766+
767+
match variant_def.kind() {
768+
ty::VariantKind::Unit => write!(fmt, "{}", name),
769+
ty::VariantKind::Tuple => fmt_tuple(fmt, &name, lvs),
770+
ty::VariantKind::Struct => {
771+
let mut struct_fmt = fmt.debug_struct(&name);
772+
for (field, lv) in variant_def.fields.iter().zip(lvs) {
773+
struct_fmt.field(&field.name.as_str(), lv);
774+
}
775+
struct_fmt.finish()
776+
}
777+
}
778+
}
779+
780+
Closure(def_id, _) => ty::tls::with(|tcx| {
781+
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
782+
let name = format!("[closure@{:?}]", tcx.map.span(node_id));
783+
let mut struct_fmt = fmt.debug_struct(&name);
784+
785+
tcx.with_freevars(node_id, |freevars| {
786+
for (freevar, lv) in freevars.iter().zip(lvs) {
787+
let var_name = tcx.local_var_name_str(freevar.def.var_id());
788+
struct_fmt.field(&var_name, lv);
789+
}
790+
});
791+
792+
struct_fmt.finish()
793+
} else {
794+
write!(fmt, "[closure]")
795+
}
796+
}),
797+
}
798+
}
734799
}
735800
}
736801
}
@@ -771,13 +836,13 @@ pub enum Literal<'tcx> {
771836
}
772837

773838
impl<'tcx> Debug for Constant<'tcx> {
774-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
839+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
775840
write!(fmt, "{:?}", self.literal)
776841
}
777842
}
778843

779844
impl<'tcx> Debug for Literal<'tcx> {
780-
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
845+
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
781846
use self::Literal::*;
782847
match *self {
783848
Item { def_id, .. } =>
@@ -788,7 +853,7 @@ impl<'tcx> Debug for Literal<'tcx> {
788853
}
789854

790855
/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
791-
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> Result<(), Error> {
856+
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
792857
use middle::const_eval::ConstVal::*;
793858
match *const_val {
794859
Float(f) => write!(fmt, "{:?}", f),

src/librustc_mir/lib.rs

+3-3
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

+15-14
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

+85
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 mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty));
82+
}
83+
84+
Ok(())
85+
}

0 commit comments

Comments
 (0)