2020-10-26 14:34:29 +01:00
|
|
|
use gsgdt::GraphvizSettings;
|
2020-06-02 19:19:49 +02:00
|
|
|
use rustc_graphviz as dot;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir::def_id::DefId;
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_middle::mir::*;
|
|
|
|
use rustc_middle::ty::TyCtxt;
|
2015-12-19 04:52:55 +01:00
|
|
|
use std::fmt::Debug;
|
2015-12-19 02:29:03 +01:00
|
|
|
use std::io::{self, Write};
|
|
|
|
|
2020-10-26 14:34:29 +01:00
|
|
|
use super::generic_graph::mir_fn_to_generic_graph;
|
2017-04-25 21:56:02 +02:00
|
|
|
use super::pretty::dump_mir_def_ids;
|
|
|
|
|
2016-03-12 18:07:00 +01:00
|
|
|
/// Write a graphviz DOT graph of a list of MIRs.
|
2019-12-22 23:42:04 +01:00
|
|
|
pub fn write_mir_graphviz<W>(tcx: TyCtxt<'_>, single: Option<DefId>, w: &mut W) -> io::Result<()>
|
2019-06-11 23:11:55 +02:00
|
|
|
where
|
|
|
|
W: Write,
|
2016-08-09 00:42:06 +02:00
|
|
|
{
|
2019-10-16 06:54:08 +02:00
|
|
|
let def_ids = dump_mir_def_ids(tcx, single);
|
|
|
|
|
|
|
|
let use_subgraphs = def_ids.len() > 1;
|
|
|
|
if use_subgraphs {
|
|
|
|
writeln!(w, "digraph __crate__ {{")?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for def_id in def_ids {
|
2019-06-04 00:26:48 +02:00
|
|
|
let body = &tcx.optimized_mir(def_id);
|
2020-10-04 20:01:38 +02:00
|
|
|
write_mir_fn_graphviz(tcx, body, use_subgraphs, w)?;
|
2017-10-24 13:48:39 +02:00
|
|
|
}
|
2019-10-16 06:54:08 +02:00
|
|
|
|
|
|
|
if use_subgraphs {
|
|
|
|
writeln!(w, "}}")?;
|
|
|
|
}
|
|
|
|
|
2017-10-24 13:48:39 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
2016-08-09 00:42:06 +02:00
|
|
|
|
2017-10-24 13:48:39 +02:00
|
|
|
/// Write a graphviz DOT graph of the MIR.
|
2019-06-11 23:11:55 +02:00
|
|
|
pub fn write_mir_fn_graphviz<'tcx, W>(
|
2019-06-13 23:48:52 +02:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-11 23:11:55 +02:00
|
|
|
body: &Body<'_>,
|
2019-10-16 06:54:08 +02:00
|
|
|
subgraph: bool,
|
2019-06-11 23:11:55 +02:00
|
|
|
w: &mut W,
|
|
|
|
) -> io::Result<()>
|
|
|
|
where
|
|
|
|
W: Write,
|
2017-10-24 13:48:39 +02:00
|
|
|
{
|
|
|
|
// Global graph properties
|
2020-09-16 17:10:06 +02:00
|
|
|
let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font);
|
|
|
|
let mut graph_attrs = vec![&font[..]];
|
|
|
|
let mut content_attrs = vec![&font[..]];
|
2020-09-09 01:08:35 +02:00
|
|
|
|
|
|
|
let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode;
|
|
|
|
if dark_mode {
|
|
|
|
graph_attrs.push(r#"bgcolor="black""#);
|
2020-10-06 01:36:10 +02:00
|
|
|
graph_attrs.push(r#"fontcolor="white""#);
|
2020-09-09 01:08:35 +02:00
|
|
|
content_attrs.push(r#"color="white""#);
|
|
|
|
content_attrs.push(r#"fontcolor="white""#);
|
|
|
|
}
|
|
|
|
|
2017-10-24 13:48:39 +02:00
|
|
|
// Graph label
|
2020-10-26 14:34:29 +01:00
|
|
|
let label = get_graph_label(tcx, body);
|
|
|
|
let g = mir_fn_to_generic_graph(tcx, body, subgraph);
|
|
|
|
let settings = GraphvizSettings {
|
|
|
|
graph_attrs: Some(graph_attrs.join(" ")),
|
|
|
|
node_attrs: Some(content_attrs.join(" ")),
|
|
|
|
edge_attrs: Some(content_attrs.join(" ")),
|
|
|
|
graph_label: Some(label),
|
2019-11-16 14:23:31 +01:00
|
|
|
};
|
2020-10-26 14:34:29 +01:00
|
|
|
g.to_dot(w, &settings)
|
2015-12-19 02:29:03 +01:00
|
|
|
}
|
|
|
|
|
2015-12-19 04:52:55 +01:00
|
|
|
/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
|
|
|
|
/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
|
|
|
|
/// all the variables and temporaries.
|
2020-10-26 14:34:29 +01:00
|
|
|
fn get_graph_label<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> String {
|
2020-10-05 00:22:23 +02:00
|
|
|
let def_id = body.source.def_id();
|
2020-10-26 14:34:29 +01:00
|
|
|
let mut label: Vec<String> = Vec::new();
|
2020-10-05 00:22:23 +02:00
|
|
|
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push(format!("fn {}(", dot::escape_html(&tcx.def_path_str(def_id))));
|
2015-12-19 02:29:03 +01:00
|
|
|
|
2015-12-19 04:52:55 +01:00
|
|
|
// fn argument types.
|
2019-06-04 00:26:48 +02:00
|
|
|
for (i, arg) in body.args_iter().enumerate() {
|
2015-12-19 02:29:03 +01:00
|
|
|
if i > 0 {
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push(", ".to_owned());
|
2015-12-19 02:29:03 +01:00
|
|
|
}
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push(format!("{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty)));
|
2015-12-19 02:29:03 +01:00
|
|
|
}
|
|
|
|
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push(format!(") -> {}", escape(&body.return_ty())));
|
|
|
|
label.push(r#"<br align="left"/>"#.to_owned());
|
2015-12-19 02:29:03 +01:00
|
|
|
|
2019-06-04 00:26:48 +02:00
|
|
|
for local in body.vars_and_temps_iter() {
|
|
|
|
let decl = &body.local_decls[local];
|
2016-09-25 01:38:27 +02:00
|
|
|
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push("let ".to_owned());
|
2016-09-25 01:38:27 +02:00
|
|
|
if decl.mutability == Mutability::Mut {
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push("mut ".to_owned());
|
2015-12-19 02:29:03 +01:00
|
|
|
}
|
|
|
|
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push(format!(r#"{:?}: {};<br align="left"/>"#, Place::from(local), escape(&decl.ty)));
|
2018-05-16 17:58:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for var_debug_info in &body.var_debug_info {
|
2020-10-26 14:34:29 +01:00
|
|
|
label.push(format!(
|
2019-12-22 23:42:04 +01:00
|
|
|
r#"debug {} => {};<br align="left"/>"#,
|
|
|
|
var_debug_info.name,
|
|
|
|
escape(&var_debug_info.place)
|
2020-10-26 14:34:29 +01:00
|
|
|
));
|
2015-12-19 02:29:03 +01:00
|
|
|
}
|
2020-10-26 14:34:29 +01:00
|
|
|
label.join("")
|
2015-12-19 04:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn escape<T: Debug>(t: &T) -> String {
|
|
|
|
dot::escape_html(&format!("{:?}", t))
|
|
|
|
}
|