Skip to content

Commit 472e678

Browse files
committedNov 1, 2019
Auto merge of #65459 - ecstatic-morse:graphviz-subgraph, r=estebank
Fix `-Zunpretty=mir-cfg` to render multiple items `-Zunpretty=mir-cfg` outputs DOT to stdout for all items being compiled. However, it puts all of these items in separate `digraph`s, which means the result of redirecting that output to a file is not valid. Most dot renderers (I have tried `dot` and `xdot`) cannot render the output. This PR checks to see if `write_mir_graphviz` will process multiple items, and writes them each as a `subgraph` in a single, top-level `digraph`. As a result, DOT can be viewed without manually editing the output file. The output is unchanged when printing a single item (e.g.`-Zunpretty=mir-cfg=item_name`). Here's the output of `xdot` for a rust file containing three items: ![three-items](https://user-images.githubusercontent.com/29463364/66889712-4bf62200-ef98-11e9-83b5-60faa2a300dd.png) The borders are a result of the nonstandard–but well-supported–[`cluster` prefix](https://graphviz.gitlab.io/_pages/doc/info/lang.html) (search for "Subgraphs and Clusters"). They will not appear if your renderer does not support this extension, but the graph will still render properly.
2 parents aa4e57c + cd3e9c4 commit 472e678

File tree

3 files changed

+45
-20
lines changed

3 files changed

+45
-20
lines changed
 

‎src/librustc_mir/util/graphviz.rs

+40-12
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,22 @@ pub fn write_mir_graphviz<W>(
1616
where
1717
W: Write,
1818
{
19-
for def_id in dump_mir_def_ids(tcx, single) {
19+
let def_ids = dump_mir_def_ids(tcx, single);
20+
21+
let use_subgraphs = def_ids.len() > 1;
22+
if use_subgraphs {
23+
writeln!(w, "digraph __crate__ {{")?;
24+
}
25+
26+
for def_id in def_ids {
2027
let body = &tcx.optimized_mir(def_id);
21-
write_mir_fn_graphviz(tcx, def_id, body, w)?;
28+
write_mir_fn_graphviz(tcx, def_id, body, use_subgraphs, w)?;
2229
}
30+
31+
if use_subgraphs {
32+
writeln!(w, "}}")?;
33+
}
34+
2335
Ok(())
2436
}
2537

@@ -38,12 +50,16 @@ pub fn write_mir_fn_graphviz<'tcx, W>(
3850
tcx: TyCtxt<'tcx>,
3951
def_id: DefId,
4052
body: &Body<'_>,
53+
subgraph: bool,
4154
w: &mut W,
4255
) -> io::Result<()>
4356
where
4457
W: Write,
4558
{
46-
writeln!(w, "digraph Mir_{} {{", graphviz_safe_def_name(def_id))?;
59+
let kind = if subgraph { "subgraph" } else { "digraph" };
60+
let cluster = if subgraph { "cluster_" } else { "" }; // Prints a border around MIR
61+
let def_name = graphviz_safe_def_name(def_id);
62+
writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?;
4763

4864
// Global graph properties
4965
writeln!(w, r#" graph [fontname="monospace"];"#)?;
@@ -55,12 +71,12 @@ where
5571

5672
// Nodes
5773
for (block, _) in body.basic_blocks().iter_enumerated() {
58-
write_node(block, body, w)?;
74+
write_node(def_id, block, body, w)?;
5975
}
6076

6177
// Edges
6278
for (source, _) in body.basic_blocks().iter_enumerated() {
63-
write_edges(source, body, w)?;
79+
write_edges(def_id, source, body, w)?;
6480
}
6581
writeln!(w, "}}")
6682
}
@@ -111,25 +127,37 @@ pub fn write_node_label<W: Write, INIT, FINI>(block: BasicBlock,
111127
fini(w)?;
112128

113129
// Close the table
114-
writeln!(w, "</table>")
130+
write!(w, "</table>")
115131
}
116132

117133
/// Write a graphviz DOT node for the given basic block.
118-
fn write_node<W: Write>(block: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> {
134+
fn write_node<W: Write>(
135+
def_id: DefId,
136+
block: BasicBlock,
137+
body: &Body<'_>,
138+
w: &mut W,
139+
) -> io::Result<()> {
119140
// Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
120-
write!(w, r#" {} [shape="none", label=<"#, node(block))?;
141+
write!(w, r#" {} [shape="none", label=<"#, node(def_id, block))?;
121142
write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?;
122143
// Close the node label and the node itself.
123144
writeln!(w, ">];")
124145
}
125146

126147
/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
127-
fn write_edges<W: Write>(source: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> {
148+
fn write_edges<W: Write>(
149+
def_id: DefId,
150+
source: BasicBlock,
151+
body: &Body<'_>,
152+
w: &mut W,
153+
) -> io::Result<()> {
128154
let terminator = body[source].terminator();
129155
let labels = terminator.kind.fmt_successor_labels();
130156

131157
for (&target, label) in terminator.successors().zip(labels) {
132-
writeln!(w, r#" {} -> {} [label="{}"];"#, node(source), node(target), label)?;
158+
let src = node(def_id, source);
159+
let trg = node(def_id, target);
160+
writeln!(w, r#" {} -> {} [label="{}"];"#, src, trg, label)?;
133161
}
134162

135163
Ok(())
@@ -181,8 +209,8 @@ fn write_graph_label<'tcx, W: Write>(
181209
writeln!(w, ">;")
182210
}
183211

184-
fn node(block: BasicBlock) -> String {
185-
format!("bb{}", block.index())
212+
fn node(def_id: DefId, block: BasicBlock) -> String {
213+
format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
186214
}
187215

188216
fn escape<T: Debug>(t: &T) -> String {

‎src/librustc_mir/util/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ fn dump_matched_mir_node<'tcx, F>(
145145
let _: io::Result<()> = try {
146146
let mut file =
147147
create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
148-
write_mir_fn_graphviz(tcx, source.def_id(), body, &mut file)?;
148+
write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?;
149149
};
150150
}
151151
}

‎src/test/mir-opt/graphviz.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@ fn main() {}
1212
// node [fontname="monospace"];
1313
// edge [fontname="monospace"];
1414
// label=<fn main() -&gt; ()<br align="left"/>>;
15-
// bb0 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = ()<br/></td></tr><tr><td align="left">goto</td></tr></table>
16-
// >];
17-
// bb1 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>
18-
// >];
19-
// bb2 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">2</td></tr><tr><td align="left">return</td></tr></table>
20-
// >];
21-
// bb0 -> bb2 [label=""];
15+
// bb0__0_12 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = ()<br/></td></tr><tr><td align="left">goto</td></tr></table>>];
16+
// bb1__0_12 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>>];
17+
// bb2__0_12 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">2</td></tr><tr><td align="left">return</td></tr></table>>];
18+
// bb0__0_12 -> bb2__0_12 [label=""];
2219
// }
2320
// END rustc.main.mir_map.0.dot

0 commit comments

Comments
 (0)
Please sign in to comment.