1111use dot;
1212use rustc:: mir:: repr:: * ;
1313use rustc:: middle:: ty;
14+ use std:: fmt:: Debug ;
1415use std:: io:: { self , Write } ;
1516
17+ /// Write a graphviz DOT graph for the given MIR.
1618pub fn write_mir_graphviz < W : Write > ( mir : & Mir , w : & mut W ) -> io:: Result < ( ) > {
1719 try!( writeln ! ( w, "digraph Mir {{" ) ) ;
1820
1921 // 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"];"# ) ) ;
2325
2426 // Graph label
2527 try!( write_graph_label ( mir, w) ) ;
@@ -37,84 +39,93 @@ pub fn write_mir_graphviz<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
3739 writeln ! ( w, "}}" )
3840}
3941
42+ /// Write a graphviz DOT node for the given basic block.
4043fn write_node < W : Write > ( block : BasicBlock , mir : & Mir , w : & mut W ) -> io:: Result < ( ) > {
4144 let data = mir. basic_block_data ( block) ;
4245
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) ) ) ;
4448 try!( write ! ( w, r#"<table border="0" cellborder="1" cellspacing="0">"# ) ) ;
4549
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( ) ) ) ;
4952
53+ // List of statements in the middle.
5054 if !data. statements . is_empty ( ) {
5155 try!( write ! ( w, r#"<tr><td align="left" balign="left">"# ) ) ;
5256 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) ) ) ;
5558 }
5659 try!( write ! ( w, "</td></tr>" ) ) ;
5760 }
5861
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.
6164 let mut terminator_head = String :: new ( ) ;
6265 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) ) ) ;
6567
66- try! ( write ! ( w , "</ table>" ) ) ;
67- writeln ! ( w, ">];" )
68+ // Close the table, node label, and the node itself.
69+ writeln ! ( w, "</table> >];" )
6870}
6971
72+ /// Write graphviz DOT edges with labels between the given basic block and all of its successors.
7073fn write_edges < W : Write > ( source : BasicBlock , mir : & Mir , w : & mut W ) -> io:: Result < ( ) > {
7174 let terminator = & mir. basic_block_data ( source) . terminator ;
7275 let labels = terminator. fmt_successor_labels ( ) ;
7376
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) ) ;
7779 }
7880
7981 Ok ( ( ) )
8082}
8183
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.
8287fn 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(" ) ) ;
8589
90+ // fn argument types.
8691 for ( i, arg) in mir. arg_decls . iter ( ) . enumerate ( ) {
8792 if i > 0 {
8893 try!( write ! ( w, ", " ) ) ;
8994 }
90- try!( write ! ( w, "{}" , dot :: escape_html ( & format! ( " a{}: {:? }", i, arg. ty) ) ) ) ;
95+ try!( write ! ( w, "a{}: {}" , i, escape ( & arg. ty) ) ) ;
9196 }
9297
93- try!( write ! ( w, "{}" , dot :: escape_html ( " ) -> " ) ) ) ;
98+ try!( write ! ( w, ") -> " ) ) ;
9499
100+ // fn return type.
95101 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, "!" ) ) ,
100104 }
101105
102106 try!( write ! ( w, r#"<br align="left"/>"# ) ) ;
103107
108+ // User variable types (including the user's name in a comment).
104109 for ( i, var) in mir. var_decls . iter ( ) . enumerate ( ) {
105110 try!( write ! ( w, "let " ) ) ;
106111 if var. mutability == Mutability :: Mut {
107112 try!( write ! ( w, "mut " ) ) ;
108113 }
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) ) ;
112115 }
113116
117+ // Compiler-introduced temporary types.
114118 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) ) ) ;
117120 }
118121
119122 writeln ! ( w, ">;" )
120123}
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