]>
git.proxmox.com Git - rustc.git/blob - src/librustc_mir/util/graphviz.rs
1 use rustc
::hir
::def_id
::DefId
;
4 use rustc_data_structures
::indexed_vec
::Idx
;
6 use std
::io
::{self, Write}
;
8 use super::pretty
::dump_mir_def_ids
;
10 /// Write a graphviz DOT graph of a list of MIRs.
11 pub fn write_mir_graphviz
<W
>(
13 single
: Option
<DefId
>,
19 for def_id
in dump_mir_def_ids(tcx
, single
) {
20 let body
= &tcx
.optimized_mir(def_id
);
21 write_mir_fn_graphviz(tcx
, def_id
, body
, w
)?
;
26 // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
27 // it does not have to be user friendly.
28 pub fn graphviz_safe_def_name(def_id
: DefId
) -> String
{
36 /// Write a graphviz DOT graph of the MIR.
37 pub fn write_mir_fn_graphviz
<'tcx
, W
>(
46 writeln
!(w
, "digraph Mir_{} {{", graphviz_safe_def_name(def_id
))?
;
48 // Global graph properties
49 writeln
!(w
, r
#" graph [fontname="monospace"];"#)?;
50 writeln
!(w
, r
#" node [fontname="monospace"];"#)?;
51 writeln
!(w
, r
#" edge [fontname="monospace"];"#)?;
54 write_graph_label(tcx
, def_id
, body
, w
)?
;
57 for (block
, _
) in body
.basic_blocks().iter_enumerated() {
58 write_node(block
, body
, w
)?
;
62 for (source
, _
) in body
.basic_blocks().iter_enumerated() {
63 write_edges(source
, body
, w
)?
;
68 /// Write a graphviz HTML-styled label for the given basic block, with
69 /// all necessary escaping already performed. (This is suitable for
70 /// emitting directly, as is done in this module, or for use with the
71 /// LabelText::HtmlStr from libgraphviz.)
73 /// `init` and `fini` are callbacks for emitting additional rows of
74 /// data (using HTML enclosed with `<tr>` in the emitted text).
75 pub fn write_node_label
<W
: Write
, INIT
, FINI
>(block
: BasicBlock
,
80 fini
: FINI
) -> io
::Result
<()>
81 where INIT
: Fn(&mut W
) -> io
::Result
<()>,
82 FINI
: Fn(&mut W
) -> io
::Result
<()>
84 let data
= &body
[block
];
86 write
!(w
, r
#"<table border="0" cellborder="1" cellspacing="0">"#)?;
88 // Basic block number at the top.
89 write
!(w
, r
#"<tr><td {attrs} colspan="{colspan}">{blk}</td></tr>"#,
90 attrs
=r
#"bgcolor="gray" align="center""#,
96 // List of statements in the middle.
97 if !data
.statements
.is_empty() {
98 write
!(w
, r
#"<tr><td align="left" balign="left">"#)?;
99 for statement
in &data
.statements
{
100 write
!(w
, "{}<br/>", escape(statement
))?
;
102 write
!(w
, "</td></tr>")?
;
105 // Terminator head at the bottom, not including the list of successor blocks. Those will be
106 // displayed as labels on the edges between blocks.
107 let mut terminator_head
= String
::new();
108 data
.terminator().kind
.fmt_head(&mut terminator_head
).unwrap();
109 write
!(w
, r
#"<tr><td align="left">{}</td></tr>"#, dot::escape_html(&terminator_head))?;
114 writeln
!(w
, "</table>")
117 /// 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
<()> {
119 // 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))?;
121 write_node_label(block
, body
, w
, 1, |_
| Ok(()), |_
| Ok(()))?
;
122 // Close the node label and the node itself.
126 /// 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
<()> {
128 let terminator
= body
[source
].terminator();
129 let labels
= terminator
.kind
.fmt_successor_labels();
131 for (&target
, label
) in terminator
.successors().zip(labels
) {
132 writeln
!(w
, r
#" {} -> {} [label="{}"];"#, node(source), node(target), label)?;
138 /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
139 /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
140 /// all the variables and temporaries.
141 fn write_graph_label
<'tcx
, W
: Write
>(
146 ) -> io
::Result
<()> {
147 write
!(w
, " label=<fn {}(", dot
::escape_html(&tcx
.def_path_str(def_id
)))?
;
149 // fn argument types.
150 for (i
, arg
) in body
.args_iter().enumerate() {
157 escape(&body
.local_decls
[arg
].ty
)
161 write
!(w
, ") -> {}", escape(&body
.return_ty()))?
;
162 write
!(w
, r
#"<br align="left"/>"#)?;
164 for local
in body
.vars_and_temps_iter() {
165 let decl
= &body
.local_decls
[local
];
168 if decl
.mutability
== Mutability
::Mut
{
172 if let Some(name
) = decl
.name
{
173 write
!(w
, r
#"{:?}: {}; // {}<br align="left"/>"#,
174 Place
::from(local
), escape(&decl
.ty
), name
)?
;
176 write
!(w
, r
#"{:?}: {};<br align="left"/>"#,
177 Place
::from(local
), escape(&decl
.ty
))?
;
184 fn node(block
: BasicBlock
) -> String
{
185 format
!("bb{}", block
.index())
188 fn escape
<T
: Debug
>(t
: &T
) -> String
{
189 dot
::escape_html(&format
!("{:?}", t
))