rustc_middle/mir/
graphviz.rs1use std::io::{self, Write};
2
3use gsgdt::GraphvizSettings;
4use rustc_graphviz as dot;
5
6use super::generic_graph::mir_fn_to_generic_graph;
7use super::pretty::dump_mir_def_ids;
8use crate::mir::*;
9
10pub fn write_mir_graphviz<W>(tcx: TyCtxt<'_>, single: Option<DefId>, w: &mut W) -> io::Result<()>
12where
13 W: Write,
14{
15 let def_ids = dump_mir_def_ids(tcx, single);
16
17 let mirs = def_ids
18 .iter()
19 .filter(|def_id| !tcx.is_trivial_const(*def_id))
20 .flat_map(|def_id| {
21 if tcx.is_const_fn(*def_id) {
22 vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
23 } else {
24 vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))]
25 }
26 })
27 .collect::<Vec<_>>();
28
29 let use_subgraphs = mirs.len() > 1;
30 if use_subgraphs {
31 writeln!(w, "digraph __crate__ {{")?;
32 }
33
34 for mir in mirs {
35 write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?;
36 }
37
38 if use_subgraphs {
39 writeln!(w, "}}")?;
40 }
41
42 Ok(())
43}
44
45pub fn write_mir_fn_graphviz<'tcx, W>(
47 tcx: TyCtxt<'tcx>,
48 body: &Body<'_>,
49 subgraph: bool,
50 w: &mut W,
51) -> io::Result<()>
52where
53 W: Write,
54{
55 let font = format!(r#"fontname="{}""#, tcx.sess.opts.unstable_opts.graphviz_font);
57 let mut graph_attrs = vec![&font[..]];
58 let mut content_attrs = vec![&font[..]];
59
60 let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode;
61 if dark_mode {
62 graph_attrs.push(r#"bgcolor="black""#);
63 graph_attrs.push(r#"fontcolor="white""#);
64 content_attrs.push(r#"color="white""#);
65 content_attrs.push(r#"fontcolor="white""#);
66 }
67
68 let mut label = String::from("");
70 write_graph_label(tcx, body, &mut label).unwrap();
72 let g = mir_fn_to_generic_graph(tcx, body);
73 let settings = GraphvizSettings {
74 graph_attrs: Some(graph_attrs.join(" ")),
75 node_attrs: Some(content_attrs.join(" ")),
76 edge_attrs: Some(content_attrs.join(" ")),
77 graph_label: Some(label),
78 };
79 g.to_dot(w, &settings, subgraph)
80}
81
82fn write_graph_label<'tcx, W: std::fmt::Write>(
86 tcx: TyCtxt<'tcx>,
87 body: &Body<'_>,
88 w: &mut W,
89) -> std::fmt::Result {
90 let def_id = body.source.def_id();
91
92 write!(w, "fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;
93
94 for (i, arg) in body.args_iter().enumerate() {
96 if i > 0 {
97 write!(w, ", ")?;
98 }
99 write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?;
100 }
101
102 write!(w, ") -> {}", escape(&body.return_ty()))?;
103 write!(w, r#"<br align="left"/>"#)?;
104
105 for local in body.vars_and_temps_iter() {
106 let decl = &body.local_decls[local];
107
108 write!(w, "let ")?;
109 if decl.mutability.is_mut() {
110 write!(w, "mut ")?;
111 }
112
113 write!(w, r#"{:?}: {};<br align="left"/>"#, Place::from(local), escape(&decl.ty))?;
114 }
115
116 for var_debug_info in &body.var_debug_info {
117 write!(
118 w,
119 r#"debug {} => {};<br align="left"/>"#,
120 var_debug_info.name,
121 escape(&var_debug_info.value),
122 )?;
123 }
124
125 Ok(())
126}
127
128fn escape<T: Debug>(t: &T) -> String {
129 dot::escape_html(&format!("{t:?}"))
130}