11
11
use dot;
12
12
use rustc:: mir:: repr:: * ;
13
13
use rustc:: middle:: ty;
14
+ use std:: fmt:: Debug ;
14
15
use std:: io:: { self , Write } ;
15
16
17
+ /// Write a graphviz DOT graph for the given MIR.
16
18
pub fn write_mir_graphviz < W : Write > ( mir : & Mir , w : & mut W ) -> io:: Result < ( ) > {
17
19
try!( writeln ! ( w, "digraph Mir {{" ) ) ;
18
20
19
21
// 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"];"# ) ) ;
22
+ try!( writeln ! ( w, r#" graph [fontname="monospace"];"# ) ) ;
23
+ try!( writeln ! ( w, r#" node [fontname="monospace"];"# ) ) ;
24
+ try!( writeln ! ( w, r#" edge [fontname="monospace"];"# ) ) ;
23
25
24
26
// Graph label
25
27
try!( write_graph_label ( mir, w) ) ;
@@ -37,84 +39,93 @@ pub fn write_mir_graphviz<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
37
39
writeln ! ( w, "}}" )
38
40
}
39
41
42
+ /// Write a graphviz DOT node for the given basic block.
40
43
fn write_node < W : Write > ( block : BasicBlock , mir : & Mir , w : & mut W ) -> io:: Result < ( ) > {
41
44
let data = mir. basic_block_data ( block) ;
42
45
43
- try!( write ! ( w, r#"bb{} [shape="none", label=<"# , block. index( ) ) ) ;
46
+ // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
47
+ try!( write ! ( w, r#" {} [shape="none", label=<"# , node( block) ) ) ;
44
48
try!( write ! ( w, r#"<table border="0" cellborder="1" cellspacing="0">"# ) ) ;
45
49
46
- try!( write ! ( w, r#"<tr><td bgcolor="gray" align="center">"# ) ) ;
47
- try!( write ! ( w, "{}" , block. index( ) ) ) ;
48
- try!( write ! ( w, "</td></tr>" ) ) ;
50
+ // Basic block number at the top.
51
+ try!( write ! ( w, r#"<tr><td bgcolor="gray" align="center">{}</td></tr>"# , block. index( ) ) ) ;
49
52
53
+ // List of statements in the middle.
50
54
if !data. statements . is_empty ( ) {
51
55
try!( write ! ( w, r#"<tr><td align="left" balign="left">"# ) ) ;
52
56
for statement in & data. statements {
53
- try!( write ! ( w, "{}" , dot:: escape_html( & format!( "{:?}" , statement) ) ) ) ;
54
- try!( write ! ( w, "<br/>" ) ) ;
57
+ try!( write ! ( w, "{}<br/>" , escape( statement) ) ) ;
55
58
}
56
59
try!( write ! ( w, "</td></tr>" ) ) ;
57
60
}
58
61
59
- try! ( write ! ( w , r#"<tr><td align="left">"# ) ) ;
60
-
62
+ // Terminator head at the bottom, not including the list of successor blocks. Those will be
63
+ // displayed as labels on the edges between blocks.
61
64
let mut terminator_head = String :: new ( ) ;
62
65
data. terminator . fmt_head ( & mut terminator_head) . unwrap ( ) ;
63
- try!( write ! ( w, "{}" , dot:: escape_html( & terminator_head) ) ) ;
64
- try!( write ! ( w, "</td></tr>" ) ) ;
66
+ try!( write ! ( w, r#"<tr><td align="left">{}</td></tr>"# , dot:: escape_html( & terminator_head) ) ) ;
65
67
66
- try! ( write ! ( w , "</ table>" ) ) ;
67
- writeln ! ( w, ">];" )
68
+ // Close the table, node label, and the node itself.
69
+ writeln ! ( w, "</table> >];" )
68
70
}
69
71
72
+ /// Write graphviz DOT edges with labels between the given basic block and all of its successors.
70
73
fn write_edges < W : Write > ( source : BasicBlock , mir : & Mir , w : & mut W ) -> io:: Result < ( ) > {
71
74
let terminator = & mir. basic_block_data ( source) . terminator ;
72
75
let labels = terminator. fmt_successor_labels ( ) ;
73
76
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
+ for ( & target, label) in terminator. successors ( ) . iter ( ) . zip ( labels) {
78
+ try!( writeln ! ( w, r#" {} -> {} [label="{}"];"# , node( source) , node( target) , label) ) ;
77
79
}
78
80
79
81
Ok ( ( ) )
80
82
}
81
83
84
+ /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
85
+ /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
86
+ /// all the variables and temporaries.
82
87
fn write_graph_label < W : Write > ( mir : & Mir , w : & mut W ) -> io:: Result < ( ) > {
83
- try!( write ! ( w, "label=<" ) ) ;
84
- try!( write ! ( w, "fn(" ) ) ;
88
+ try!( write ! ( w, " label=<fn(" ) ) ;
85
89
90
+ // fn argument types.
86
91
for ( i, arg) in mir. arg_decls . iter ( ) . enumerate ( ) {
87
92
if i > 0 {
88
93
try!( write ! ( w, ", " ) ) ;
89
94
}
90
- try!( write ! ( w, "{}" , dot :: escape_html ( & format! ( " a{}: {:? }", i, arg. ty) ) ) ) ;
95
+ try!( write ! ( w, "a{}: {}" , i, escape ( & arg. ty) ) ) ;
91
96
}
92
97
93
- try!( write ! ( w, "{}" , dot :: escape_html ( " ) -> " ) ) ) ;
98
+ try!( write ! ( w, ") -> " ) ) ;
94
99
100
+ // fn return type.
95
101
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( "!" ) ) ) ,
102
+ ty:: FnOutput :: FnConverging ( ty) => try!( write ! ( w, "{}" , escape( ty) ) ) ,
103
+ ty:: FnOutput :: FnDiverging => try!( write ! ( w, "!" ) ) ,
100
104
}
101
105
102
106
try!( write ! ( w, r#"<br align="left"/>"# ) ) ;
103
107
108
+ // User variable types (including the user's name in a comment).
104
109
for ( i, var) in mir. var_decls . iter ( ) . enumerate ( ) {
105
110
try!( write ! ( w, "let " ) ) ;
106
111
if var. mutability == Mutability :: Mut {
107
112
try!( write ! ( w, "mut " ) ) ;
108
113
}
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"/>"# ) ) ;
114
+ try!( write ! ( w, r#"v{}: {}; // {}<br align="left"/>"# , i, escape( & var. ty) , var. name) ) ;
112
115
}
113
116
117
+ // Compiler-introduced temporary types.
114
118
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"/>"# ) ) ;
119
+ try!( write ! ( w, r#"let t{}: {};<br align="left"/>"# , i, escape( & temp. ty) ) ) ;
117
120
}
118
121
119
122
writeln ! ( w, ">;" )
120
123
}
124
+
125
+ fn node ( block : BasicBlock ) -> String {
126
+ format ! ( "bb{}" , block. index( ) )
127
+ }
128
+
129
+ fn escape < T : Debug > ( t : & T ) -> String {
130
+ dot:: escape_html ( & format ! ( "{:?}" , t) )
131
+ }
0 commit comments