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};
7 use std::io::{self, Write};
9 use super::generic_graph::mir_fn_to_generic_graph;
10 use super::pretty::dump_mir_def_ids;
12 /// Write a graphviz DOT graph of a list of MIRs.
13 pub fn write_mir_graphviz<W>(tcx: TyCtxt<'_>, single: Option<DefId>, w: &mut W) -> io::Result<()>
17 let def_ids = dump_mir_def_ids(tcx, single);
23 if tcx.is_const_fn_raw(*def_id) {
24 vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
26 vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
33 let use_subgraphs = mirs.len() > 1;
35 writeln!(w, "digraph __crate__ {{")?;
39 write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?;
49 /// Write a graphviz DOT graph of the MIR.
50 pub fn write_mir_fn_graphviz<'tcx, W>(
59 // Global graph properties
60 let font = format!(r#"fontname="{}""#, tcx.sess.opts.unstable_opts.graphviz_font);
61 let mut graph_attrs = vec![&font[..]];
62 let mut content_attrs = vec![&font[..]];
64 let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode;
66 graph_attrs.push(r#"bgcolor="black""#);
67 graph_attrs.push(r#"fontcolor="white""#);
68 content_attrs.push(r#"color="white""#);
69 content_attrs.push(r#"fontcolor="white""#);
73 let mut label = String::from("");
74 // FIXME: remove this unwrap
75 write_graph_label(tcx, body, &mut label).unwrap();
76 let g = mir_fn_to_generic_graph(tcx, body);
77 let settings = GraphvizSettings {
78 graph_attrs: Some(graph_attrs.join(" ")),
79 node_attrs: Some(content_attrs.join(" ")),
80 edge_attrs: Some(content_attrs.join(" ")),
81 graph_label: Some(label),
83 g.to_dot(w, &settings, subgraph)
86 /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
87 /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
88 /// all the variables and temporaries.
89 fn write_graph_label<'tcx, W: std::fmt::Write>(
93 ) -> std::fmt::Result {
94 let def_id = body.source.def_id();
96 write!(w, "fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;
99 for (i, arg) in body.args_iter().enumerate() {
103 write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?;
106 write!(w, ") -> {}", escape(&body.return_ty()))?;
107 write!(w, r#"<br align="left"/>"#)?;
109 for local in body.vars_and_temps_iter() {
110 let decl = &body.local_decls[local];
113 if decl.mutability == Mutability::Mut {
117 write!(w, r#"{:?}: {};<br align="left"/>"#, Place::from(local), escape(&decl.ty))?;
120 for var_debug_info in &body.var_debug_info {
123 r#"debug {} => {};<br align="left"/>"#,
125 escape(&var_debug_info.value),
132 fn escape<T: Debug>(t: &T) -> String {
133 dot::escape_html(&format!("{:?}", t))