]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_mir/src/util/generic_graph.rs
New upstream version 1.50.0+dfsg1
[rustc.git] / compiler / rustc_mir / src / util / generic_graph.rs
1 use gsgdt::{Edge, Graph, Node, NodeStyle};
2 use rustc_hir::def_id::DefId;
3 use rustc_index::vec::Idx;
4 use rustc_middle::mir::*;
5 use rustc_middle::ty::TyCtxt;
6
7 /// Convert an MIR function into a gsgdt Graph
8 pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph {
9 let def_id = body.source.def_id();
10 let def_name = graphviz_safe_def_name(def_id);
11 let graph_name = format!("Mir_{}", def_name);
12 let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode;
13
14 // Nodes
15 let nodes: Vec<Node> = body
16 .basic_blocks()
17 .iter_enumerated()
18 .map(|(block, _)| bb_to_graph_node(block, body, dark_mode))
19 .collect();
20
21 // Edges
22 let mut edges = Vec::new();
23 for (source, _) in body.basic_blocks().iter_enumerated() {
24 let def_id = body.source.def_id();
25 let terminator = body[source].terminator();
26 let labels = terminator.kind.fmt_successor_labels();
27
28 for (&target, label) in terminator.successors().zip(labels) {
29 let src = node(def_id, source);
30 let trg = node(def_id, target);
31 edges.push(Edge::new(src, trg, label.to_string()));
32 }
33 }
34
35 Graph::new(graph_name, nodes, edges)
36 }
37
38 fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node {
39 let def_id = body.source.def_id();
40 let data = &body[block];
41 let label = node(def_id, block);
42
43 let (title, bgcolor) = if data.is_cleanup {
44 let color = if dark_mode { "royalblue" } else { "lightblue" };
45 (format!("{} (cleanup)", block.index()), color)
46 } else {
47 let color = if dark_mode { "dimgray" } else { "gray" };
48 (format!("{}", block.index()), color)
49 };
50
51 let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() };
52 let mut stmts: Vec<String> = data.statements.iter().map(|x| format!("{:?}", x)).collect();
53
54 // add the terminator to the stmts, gsgdt can print it out seperately
55 let mut terminator_head = String::new();
56 data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
57 stmts.push(terminator_head);
58
59 Node::new(stmts, label, title, style)
60 }
61
62 // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
63 // it does not have to be user friendly.
64 pub fn graphviz_safe_def_name(def_id: DefId) -> String {
65 format!("{}_{}", def_id.krate.index(), def_id.index.index(),)
66 }
67
68 fn node(def_id: DefId, block: BasicBlock) -> String {
69 format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
70 }