• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use gsgdt::GraphvizSettings;
2 use rustc_graphviz as dot;
3 use rustc_hir::def_id::DefId;
4 use rustc_middle::mir::*;
5 use rustc_middle::ty::{self, TyCtxt};
6 use std::fmt::Debug;
7 use std::io::{self, Write};
8 
9 use super::generic_graph::mir_fn_to_generic_graph;
10 use super::pretty::dump_mir_def_ids;
11 
12 /// Write a graphviz DOT graph of a list of MIRs.
write_mir_graphviz<W>(tcx: TyCtxt<'_>, single: Option<DefId>, w: &mut W) -> io::Result<()> where W: Write,13 pub fn write_mir_graphviz<W>(tcx: TyCtxt<'_>, single: Option<DefId>, w: &mut W) -> io::Result<()>
14 where
15     W: Write,
16 {
17     let def_ids = dump_mir_def_ids(tcx, single);
18 
19     let mirs = def_ids
20         .iter()
21         .flat_map(|def_id| {
22             if tcx.is_const_fn_raw(*def_id) {
23                 vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
24             } else {
25                 vec![tcx.instance_mir(ty::InstanceDef::Item(*def_id))]
26             }
27         })
28         .collect::<Vec<_>>();
29 
30     let use_subgraphs = mirs.len() > 1;
31     if use_subgraphs {
32         writeln!(w, "digraph __crate__ {{")?;
33     }
34 
35     for mir in mirs {
36         write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?;
37     }
38 
39     if use_subgraphs {
40         writeln!(w, "}}")?;
41     }
42 
43     Ok(())
44 }
45 
46 /// Write a graphviz DOT graph of the MIR.
write_mir_fn_graphviz<'tcx, W>( tcx: TyCtxt<'tcx>, body: &Body<'_>, subgraph: bool, w: &mut W, ) -> io::Result<()> where W: Write,47 pub fn write_mir_fn_graphviz<'tcx, W>(
48     tcx: TyCtxt<'tcx>,
49     body: &Body<'_>,
50     subgraph: bool,
51     w: &mut W,
52 ) -> io::Result<()>
53 where
54     W: Write,
55 {
56     // Global graph properties
57     let font = format!(r#"fontname="{}""#, tcx.sess.opts.unstable_opts.graphviz_font);
58     let mut graph_attrs = vec![&font[..]];
59     let mut content_attrs = vec![&font[..]];
60 
61     let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode;
62     if dark_mode {
63         graph_attrs.push(r#"bgcolor="black""#);
64         graph_attrs.push(r#"fontcolor="white""#);
65         content_attrs.push(r#"color="white""#);
66         content_attrs.push(r#"fontcolor="white""#);
67     }
68 
69     // Graph label
70     let mut label = String::from("");
71     // FIXME: remove this unwrap
72     write_graph_label(tcx, body, &mut label).unwrap();
73     let g = mir_fn_to_generic_graph(tcx, body);
74     let settings = GraphvizSettings {
75         graph_attrs: Some(graph_attrs.join(" ")),
76         node_attrs: Some(content_attrs.join(" ")),
77         edge_attrs: Some(content_attrs.join(" ")),
78         graph_label: Some(label),
79     };
80     g.to_dot(w, &settings, subgraph)
81 }
82 
83 /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
84 /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
85 /// all the variables and temporaries.
write_graph_label<'tcx, W: std::fmt::Write>( tcx: TyCtxt<'tcx>, body: &Body<'_>, w: &mut W, ) -> std::fmt::Result86 fn write_graph_label<'tcx, W: std::fmt::Write>(
87     tcx: TyCtxt<'tcx>,
88     body: &Body<'_>,
89     w: &mut W,
90 ) -> std::fmt::Result {
91     let def_id = body.source.def_id();
92 
93     write!(w, "fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;
94 
95     // fn argument types.
96     for (i, arg) in body.args_iter().enumerate() {
97         if i > 0 {
98             write!(w, ", ")?;
99         }
100         write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?;
101     }
102 
103     write!(w, ") -&gt; {}", escape(&body.return_ty()))?;
104     write!(w, r#"<br align="left"/>"#)?;
105 
106     for local in body.vars_and_temps_iter() {
107         let decl = &body.local_decls[local];
108 
109         write!(w, "let ")?;
110         if decl.mutability.is_mut() {
111             write!(w, "mut ")?;
112         }
113 
114         write!(w, r#"{:?}: {};<br align="left"/>"#, Place::from(local), escape(&decl.ty))?;
115     }
116 
117     for var_debug_info in &body.var_debug_info {
118         write!(
119             w,
120             r#"debug {} =&gt; {};<br align="left"/>"#,
121             var_debug_info.name,
122             escape(&var_debug_info.value),
123         )?;
124     }
125 
126     Ok(())
127 }
128 
escape<T: Debug>(t: &T) -> String129 fn escape<T: Debug>(t: &T) -> String {
130     dot::escape_html(&format!("{:?}", t))
131 }
132