Skip to content

Commit 9000ecf

Browse files
committed
Rewrite MIR graphviz printing and improve MIR debug printing.
1 parent 27a1834 commit 9000ecf

File tree

5 files changed

+236
-200
lines changed

5 files changed

+236
-200
lines changed

src/librustc/mir/repr.rs

Lines changed: 112 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111
use middle::const_eval::ConstVal;
1212
use middle::def_id::DefId;
1313
use middle::subst::Substs;
14-
use middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty};
14+
use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
1515
use rustc_back::slice;
1616
use rustc_data_structures::tuple_slice::TupleSlice;
1717
use rustc_front::hir::InlineAsm;
1818
use syntax::ast::Name;
1919
use syntax::codemap::Span;
20-
use std::fmt::{Debug, Formatter, Error};
21-
use std::u32;
20+
use std::borrow::{Cow, IntoCow};
21+
use std::fmt::{Debug, Formatter, Error, Write};
22+
use std::{iter, u32};
2223

2324
/// Lowered representation of a single function.
2425
#[derive(RustcEncodable, RustcDecodable)]
@@ -317,31 +318,77 @@ impl<'tcx> BasicBlockData<'tcx> {
317318

318319
impl<'tcx> Debug for Terminator<'tcx> {
319320
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
321+
try!(self.fmt_head(fmt));
322+
let successors = self.successors();
323+
let labels = self.fmt_successor_labels();
324+
assert_eq!(successors.len(), labels.len());
325+
326+
match successors.len() {
327+
0 => Ok(()),
328+
329+
1 => write!(fmt, " -> {:?}", successors[0]),
330+
331+
_ => {
332+
try!(write!(fmt, " -> ["));
333+
for (i, target) in successors.iter().enumerate() {
334+
if i > 0 {
335+
try!(write!(fmt, ", "));
336+
}
337+
try!(write!(fmt, "{}: {:?}", labels[i], target));
338+
}
339+
write!(fmt, "]")
340+
}
341+
342+
}
343+
}
344+
}
345+
346+
impl<'tcx> Terminator<'tcx> {
347+
pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> Result<(), Error> {
320348
use self::Terminator::*;
321349
match *self {
322-
Goto { target } =>
323-
write!(fmt, "goto -> {:?}", target),
324-
Panic { target } =>
325-
write!(fmt, "panic -> {:?}", target),
326-
If { cond: ref lv, ref targets } =>
327-
write!(fmt, "if({:?}) -> {:?}", lv, targets),
328-
Switch { discr: ref lv, adt_def: _, ref targets } =>
329-
write!(fmt, "switch({:?}) -> {:?}", lv, targets),
330-
SwitchInt { discr: ref lv, switch_ty: _, ref values, ref targets } =>
331-
write!(fmt, "switchInt({:?}, {:?}) -> {:?}", lv, values, targets),
332-
Diverge =>
333-
write!(fmt, "diverge"),
334-
Return =>
335-
write!(fmt, "return"),
336-
Call { data: ref c, targets } => {
350+
Goto { .. } => write!(fmt, "goto"),
351+
Panic { .. } => write!(fmt, "panic"),
352+
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
353+
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
354+
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
355+
Diverge => write!(fmt, "diverge"),
356+
Return => write!(fmt, "return"),
357+
Call { data: ref c, .. } => {
337358
try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func));
338359
for (index, arg) in c.args.iter().enumerate() {
339360
if index > 0 {
340361
try!(write!(fmt, ", "));
341362
}
342363
try!(write!(fmt, "{:?}", arg));
343364
}
344-
write!(fmt, ") -> {:?}", targets)
365+
write!(fmt, ")")
366+
}
367+
}
368+
}
369+
370+
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
371+
use self::Terminator::*;
372+
match *self {
373+
Diverge | Return => vec![],
374+
Goto { .. } | Panic { .. } => vec!["".into_cow()],
375+
If { .. } => vec!["true".into_cow(), "false".into_cow()],
376+
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
377+
Switch { ref adt_def, .. } => {
378+
adt_def.variants
379+
.iter()
380+
.map(|variant| variant.name.to_string().into_cow())
381+
.collect()
382+
}
383+
SwitchInt { ref values, .. } => {
384+
values.iter()
385+
.map(|const_val| {
386+
let mut buf = String::new();
387+
fmt_const_val(&mut buf, const_val).unwrap();
388+
buf.into_cow()
389+
})
390+
.chain(iter::once(String::from("otherwise").into_cow()))
391+
.collect()
345392
}
346393
}
347394
}
@@ -495,19 +542,19 @@ impl<'tcx> Debug for Lvalue<'tcx> {
495542

496543
match *self {
497544
Var(id) =>
498-
write!(fmt,"Var({:?})", id),
545+
write!(fmt,"v{:?}", id),
499546
Arg(id) =>
500-
write!(fmt,"Arg({:?})", id),
547+
write!(fmt,"a{:?}", id),
501548
Temp(id) =>
502-
write!(fmt,"Temp({:?})", id),
549+
write!(fmt,"t{:?}", id),
503550
Static(id) =>
504551
write!(fmt,"Static({:?})", id),
505552
ReturnPointer =>
506553
write!(fmt,"ReturnPointer"),
507554
Projection(ref data) =>
508555
match data.elem {
509-
ProjectionElem::Downcast(_, variant_index) =>
510-
write!(fmt,"({:?} as {:?})", data.base, variant_index),
556+
ProjectionElem::Downcast(ref adt_def, index) =>
557+
write!(fmt,"({:?} as {})", data.base, adt_def.variants[index].name),
511558
ProjectionElem::Deref =>
512559
write!(fmt,"(*{:?})", data.base),
513560
ProjectionElem::Field(field) =>
@@ -671,12 +718,12 @@ impl<'tcx> Debug for Rvalue<'tcx> {
671718
Use(ref lvalue) => write!(fmt, "{:?}", lvalue),
672719
Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b),
673720
Ref(ref a, bk, ref b) => write!(fmt, "&{:?} {:?} {:?}", a, bk, b),
674-
Len(ref a) => write!(fmt, "LEN({:?})", a),
675-
Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?}", lv, ty, kind),
676-
BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?},{:?})", op, a, b),
721+
Len(ref a) => write!(fmt, "Len({:?})", a),
722+
Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?})", lv, ty, kind),
723+
BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b),
677724
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
678-
Box(ref t) => write!(fmt, "Box {:?}", t),
679-
Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>({:?})", kind, lvs),
725+
Box(ref t) => write!(fmt, "Box({:?})", t),
726+
Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>{:?}", kind, lvs),
680727
InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm),
681728
Slice { ref input, from_start, from_end } =>
682729
write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
@@ -691,7 +738,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
691738
// this does not necessarily mean that they are "==" in Rust -- in
692739
// particular one must be wary of `NaN`!
693740

694-
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
741+
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
695742
pub struct Constant<'tcx> {
696743
pub span: Span,
697744
pub ty: Ty<'tcx>,
@@ -707,7 +754,7 @@ pub enum ItemKind {
707754
Method,
708755
}
709756

710-
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
757+
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
711758
pub enum Literal<'tcx> {
712759
Item {
713760
def_id: DefId,
@@ -718,3 +765,37 @@ pub enum Literal<'tcx> {
718765
value: ConstVal,
719766
},
720767
}
768+
769+
impl<'tcx> Debug for Constant<'tcx> {
770+
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
771+
write!(fmt, "{:?}", self.literal)
772+
}
773+
}
774+
775+
impl<'tcx> Debug for Literal<'tcx> {
776+
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
777+
use self::Literal::*;
778+
match *self {
779+
Item { def_id, .. } =>
780+
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
781+
Value { ref value } => fmt_const_val(fmt, value),
782+
}
783+
}
784+
}
785+
786+
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> Result<(), Error> {
787+
use middle::const_eval::ConstVal::*;
788+
match *const_val {
789+
Float(f) => write!(fmt, "{:?}", f),
790+
Int(n) => write!(fmt, "{:?}", n),
791+
Uint(n) => write!(fmt, "{:?}", n),
792+
Str(ref s) => write!(fmt, "Str({:?})", s),
793+
ByteStr(ref bytes) => write!(fmt, "ByteStr{:?}", bytes),
794+
Bool(b) => write!(fmt, "{:?}", b),
795+
Struct(id) => write!(fmt, "Struct({:?})", id),
796+
Tuple(id) => write!(fmt, "Tuple({:?})", id),
797+
Function(def_id) => write!(fmt, "Function({:?})", def_id),
798+
Array(id, n) => write!(fmt, "Array({:?}, {:?})", id, n),
799+
Repeat(id, n) => write!(fmt, "Repeat({:?}, {:?})", id, n),
800+
}
801+
}

src/librustc_mir/graphviz.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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 dot;
12+
use rustc::mir::repr::*;
13+
use rustc::middle::ty;
14+
use std::io::{self, Write};
15+
16+
pub fn write_mir_graphviz<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
17+
try!(writeln!(w, "digraph Mir {{"));
18+
19+
// Global graph properties
20+
try!(writeln!(w, r#"graph [fontname="monospace"];"#));
21+
try!(writeln!(w, r#"node [fontname="monospace"];"#));
22+
try!(writeln!(w, r#"edge [fontname="monospace"];"#));
23+
24+
// Graph label
25+
try!(write_graph_label(mir, w));
26+
27+
// Nodes
28+
for block in mir.all_basic_blocks() {
29+
try!(write_node(block, mir, w));
30+
}
31+
32+
// Edges
33+
for source in mir.all_basic_blocks() {
34+
try!(write_edges(source, mir, w));
35+
}
36+
37+
writeln!(w, "}}")
38+
}
39+
40+
fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
41+
let data = mir.basic_block_data(block);
42+
43+
try!(write!(w, r#"bb{} [shape="none", label=<"#, block.index()));
44+
try!(write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#));
45+
46+
try!(write!(w, r#"<tr><td bgcolor="gray" align="center">"#));
47+
try!(write!(w, "{}", block.index()));
48+
try!(write!(w, "</td></tr>"));
49+
50+
if !data.statements.is_empty() {
51+
try!(write!(w, r#"<tr><td align="left" balign="left">"#));
52+
for statement in &data.statements {
53+
try!(write!(w, "{}", dot::escape_html(&format!("{:?}", statement))));
54+
try!(write!(w, "<br/>"));
55+
}
56+
try!(write!(w, "</td></tr>"));
57+
}
58+
59+
try!(write!(w, r#"<tr><td align="left">"#));
60+
61+
let mut terminator_head = String::new();
62+
data.terminator.fmt_head(&mut terminator_head).unwrap();
63+
try!(write!(w, "{}", dot::escape_html(&terminator_head)));
64+
try!(write!(w, "</td></tr>"));
65+
66+
try!(write!(w, "</table>"));
67+
writeln!(w, ">];")
68+
}
69+
70+
fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
71+
let terminator = &mir.basic_block_data(source).terminator;
72+
let labels = terminator.fmt_successor_labels();
73+
74+
for (i, target) in terminator.successors().into_iter().enumerate() {
75+
try!(write!(w, "bb{} -> bb{}", source.index(), target.index()));
76+
try!(writeln!(w, r#" [label="{}"];"#, labels[i]));
77+
}
78+
79+
Ok(())
80+
}
81+
82+
fn write_graph_label<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
83+
try!(write!(w, "label=<"));
84+
try!(write!(w, "fn("));
85+
86+
for (i, arg) in mir.arg_decls.iter().enumerate() {
87+
if i > 0 {
88+
try!(write!(w, ", "));
89+
}
90+
try!(write!(w, "{}", dot::escape_html(&format!("a{}: {:?}", i, arg.ty))));
91+
}
92+
93+
try!(write!(w, "{}", dot::escape_html(") -> ")));
94+
95+
match mir.return_ty {
96+
ty::FnOutput::FnConverging(ty) =>
97+
try!(write!(w, "{}", dot::escape_html(&format!("{:?}", ty)))),
98+
ty::FnOutput::FnDiverging =>
99+
try!(write!(w, "{}", dot::escape_html("!"))),
100+
}
101+
102+
try!(write!(w, r#"<br align="left"/>"#));
103+
104+
for (i, var) in mir.var_decls.iter().enumerate() {
105+
try!(write!(w, "let "));
106+
if var.mutability == Mutability::Mut {
107+
try!(write!(w, "mut "));
108+
}
109+
let text = format!("v{}: {:?}; // {}", i, var.ty, var.name);
110+
try!(write!(w, "{}", dot::escape_html(&text)));
111+
try!(write!(w, r#"<br align="left"/>"#));
112+
}
113+
114+
for (i, temp) in mir.temp_decls.iter().enumerate() {
115+
try!(write!(w, "{}", dot::escape_html(&format!("let t{}: {:?};", i, temp.ty))));
116+
try!(write!(w, r#"<br align="left"/>"#));
117+
}
118+
119+
writeln!(w, ">;")
120+
}

0 commit comments

Comments
 (0)