1 //! Hook into libgraphviz for rendering dataflow graphs for MIR.
3 use rustc::hir::def_id::DefId;
4 use rustc::mir::{BasicBlock, Body};
8 use std::marker::PhantomData;
11 use crate::util::graphviz_safe_def_name;
13 use super::{BitDenotation, DataflowState};
14 use super::DataflowBuilder;
15 use super::DebugFormatted;
17 pub trait MirWithFlowState<'tcx> {
18 type BD: BitDenotation<'tcx>;
19 fn def_id(&self) -> DefId;
20 fn mir(&self) -> &Body<'tcx>;
21 fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>;
24 impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
25 where BD: BitDenotation<'tcx>
28 fn def_id(&self) -> DefId { self.def_id }
29 fn mir(&self) -> &Body<'tcx> { self.flow_state.mir() }
30 fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state }
33 struct Graph<'a, 'tcx, MWF:'a, P> where
34 MWF: MirWithFlowState<'tcx>
37 phantom: PhantomData<&'tcx ()>,
41 pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
42 mbcx: &DataflowBuilder<'a, 'tcx, BD>,
46 where BD: BitDenotation<'tcx>,
47 P: Fn(&BD, BD::Idx) -> DebugFormatted,
49 let g = Graph { mbcx, phantom: PhantomData, render_idx };
50 let mut v = Vec::new();
51 dot::render(&g, &mut v)?;
52 debug!("print_borrowck_graph_to path: {} def_id: {:?}",
53 path.display(), mbcx.def_id);
57 pub type Node = BasicBlock;
59 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
60 pub struct Edge { source: BasicBlock, index: usize }
62 fn outgoing(mir: &Body<'_>, bb: BasicBlock) -> Vec<Edge> {
63 (0..mir[bb].terminator().successors().count())
64 .map(|index| Edge { source: bb, index: index}).collect()
67 impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
68 where MWF: MirWithFlowState<'tcx>,
69 P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
73 fn graph_id(&self) -> dot::Id<'_> {
74 let name = graphviz_safe_def_name(self.mbcx.def_id());
75 dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
78 fn node_id(&self, n: &Node) -> dot::Id<'_> {
79 dot::Id::new(format!("bb_{}", n.index()))
83 fn node_label(&self, n: &Node) -> dot::LabelText<'_> {
84 // Node label is something like this:
85 // +---------+----------------------------------+------------------+------------------+
86 // | ENTRY | MIR | GEN | KILL |
87 // +---------+----------------------------------+------------------+------------------+
88 // | | 0: StorageLive(_7) | bb3[2]: reserved | bb2[0]: reserved |
89 // | | 1: StorageLive(_8) | bb3[2]: active | bb2[0]: active |
90 // | | 2: _8 = &mut _1 | | bb4[2]: reserved |
91 // | | | | bb4[2]: active |
92 // | | | | bb9[0]: reserved |
93 // | | | | bb9[0]: active |
94 // | | | | bb10[0]: reserved|
95 // | | | | bb10[0]: active |
96 // | | | | bb11[0]: reserved|
97 // | | | | bb11[0]: active |
98 // +---------+----------------------------------+------------------+------------------+
99 // | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00] | [f3-0f] |
100 // +---------+----------------------------------+------------------+------------------+
101 let mut v = Vec::new();
102 self.node_label_internal(n, &mut v, *n, self.mbcx.mir()).unwrap();
103 dot::LabelText::html(String::from_utf8(v).unwrap())
107 fn node_shape(&self, _n: &Node) -> Option<dot::LabelText<'_>> {
108 Some(dot::LabelText::label("none"))
111 fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> {
112 let term = self.mbcx.mir()[e.source].terminator();
113 let label = &term.kind.fmt_successor_labels()[e.index];
114 dot::LabelText::label(label.clone())
118 impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
119 where MWF: MirWithFlowState<'tcx>,
120 P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
122 /// Generate the node label
123 fn node_label_internal<W: io::Write>(&self,
127 mir: &Body<'_>) -> io::Result<()> {
129 const HDRS: [&str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"];
130 const HDR_FMT: &str = "bgcolor=\"grey\"";
131 write!(w, "<table><tr><td rowspan=\"{}\">", HDRS.len())?;
132 write!(w, "{:?}", block.index())?;
133 write!(w, "</td></tr><tr>")?;
135 write!(w, "<td {}>{}</td>", HDR_FMT, hdr)?;
140 self.node_label_verbose_row(n, w, block, mir)?;
141 self.node_label_final_row(n, w, block, mir)?;
142 write!(w, "</table>")?;
147 /// Builds the verbose row: full MIR data, and detailed gen/kill/entry sets.
148 fn node_label_verbose_row<W: io::Write>(&self,
156 macro_rules! dump_set_for {
157 ($set:ident, $interpret:ident) => {
160 let flow = self.mbcx.flow_state();
161 let entry_interp = flow.$interpret(&flow.operator,
164 for e in &entry_interp {
165 write!(w, "{:?}<br/>", e)?;
173 dump_set_for!(on_entry_set_for, interpret_set);
178 let data = &mir[block];
179 for (i, statement) in data.statements.iter().enumerate() {
180 write!(w, "{}<br align=\"left\"/>",
181 dot::escape_html(&format!("{:3}: {:?}", i, statement)))?;
187 dump_set_for!(gen_set_for, interpret_hybrid_set);
190 dump_set_for!(kill_set_for, interpret_hybrid_set);
197 /// Builds the summary row: terminator, gen/kill/entry bit sets.
198 fn node_label_final_row<W: io::Write>(&self,
206 let flow = self.mbcx.flow_state();
211 let set = flow.sets.on_entry_set_for(i);
212 write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?;
217 let data = &mir[block];
218 let mut terminator_head = String::new();
219 data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
220 write!(w, "{}", dot::escape_html(&terminator_head))?;
225 let set = flow.sets.gen_set_for(i);
226 write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
229 let set = flow.sets.kill_set_for(i);
230 write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
238 impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
239 where MWF: MirWithFlowState<'tcx>
243 fn nodes(&self) -> dot::Nodes<'_, Node> {
251 fn edges(&self) -> dot::Edges<'_, Edge> {
252 let mir = self.mbcx.mir();
256 .flat_map(|bb| outgoing(mir, bb))
261 fn source(&self, edge: &Edge) -> Node {
265 fn target(&self, edge: &Edge) -> Node {
266 let mir = self.mbcx.mir();
267 *mir[edge.source].terminator().successors().nth(edge.index).unwrap()