]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/graphviz.rs
4965f1a585d482aad4e9d6f2b0569d047879ae39
[rust.git] / src / librustc_mir / dataflow / graphviz.rs
1 //! Hook into libgraphviz for rendering dataflow graphs for MIR.
2
3 use rustc::hir::def_id::DefId;
4 use rustc::mir::{BasicBlock, Body};
5
6 use std::fs;
7 use std::io;
8 use std::marker::PhantomData;
9 use std::path::Path;
10
11 use crate::util::graphviz_safe_def_name;
12
13 use super::{BitDenotation, DataflowState};
14 use super::DataflowBuilder;
15 use super::DebugFormatted;
16
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>;
22 }
23
24 impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
25     where BD: BitDenotation<'tcx>
26 {
27     type BD = BD;
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 }
31 }
32
33 struct Graph<'a, 'tcx, MWF:'a, P> where
34     MWF: MirWithFlowState<'tcx>
35 {
36     mbcx: &'a MWF,
37     phantom: PhantomData<&'tcx ()>,
38     render_idx: P,
39 }
40
41 pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
42     mbcx: &DataflowBuilder<'a, 'tcx, BD>,
43     path: &Path,
44     render_idx: P)
45     -> io::Result<()>
46     where BD: BitDenotation<'tcx>,
47           P: Fn(&BD, BD::Idx) -> DebugFormatted,
48 {
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);
54     fs::write(path, v)
55 }
56
57 pub type Node = BasicBlock;
58
59 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
60 pub struct Edge { source: BasicBlock, index: usize }
61
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()
65 }
66
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,
70 {
71     type Node = Node;
72     type Edge = Edge;
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()
76     }
77
78     fn node_id(&self, n: &Node) -> dot::Id<'_> {
79         dot::Id::new(format!("bb_{}", n.index()))
80             .unwrap()
81     }
82
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())
104     }
105
106
107     fn node_shape(&self, _n: &Node) -> Option<dot::LabelText<'_>> {
108         Some(dot::LabelText::label("none"))
109     }
110
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())
115     }
116 }
117
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,
121 {
122     /// Generate the node label
123     fn node_label_internal<W: io::Write>(&self,
124                                          n: &Node,
125                                          w: &mut W,
126                                          block: BasicBlock,
127                                          mir: &Body<'_>) -> io::Result<()> {
128         // Header rows
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>")?;
134         for hdr in &HDRS {
135             write!(w, "<td {}>{}</td>", HDR_FMT, hdr)?;
136         }
137         write!(w, "</tr>")?;
138
139         // Data row
140         self.node_label_verbose_row(n, w, block, mir)?;
141         self.node_label_final_row(n, w, block, mir)?;
142         write!(w, "</table>")?;
143
144         Ok(())
145     }
146
147     /// Builds the verbose row: full MIR data, and detailed gen/kill/entry sets.
148     fn node_label_verbose_row<W: io::Write>(&self,
149                                             n: &Node,
150                                             w: &mut W,
151                                             block: BasicBlock,
152                                             mir: &Body<'_>)
153                                             -> io::Result<()> {
154         let i = n.index();
155
156         macro_rules! dump_set_for {
157             ($set:ident, $interpret:ident) => {
158                 write!(w, "<td>")?;
159
160                 let flow = self.mbcx.flow_state();
161                 let entry_interp = flow.$interpret(&flow.operator,
162                                                    flow.sets.$set(i),
163                                                    &self.render_idx);
164                 for e in &entry_interp {
165                     write!(w, "{:?}<br/>", e)?;
166                 }
167                 write!(w, "</td>")?;
168             }
169         }
170
171         write!(w, "<tr>")?;
172         // Entry
173         dump_set_for!(on_entry_set_for, interpret_set);
174
175         // MIR statements
176         write!(w, "<td>")?;
177         {
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)))?;
182             }
183         }
184         write!(w, "</td>")?;
185
186         // Gen
187         dump_set_for!(gen_set_for, interpret_hybrid_set);
188
189         // Kill
190         dump_set_for!(kill_set_for, interpret_hybrid_set);
191
192         write!(w, "</tr>")?;
193
194         Ok(())
195     }
196
197     /// Builds the summary row: terminator, gen/kill/entry bit sets.
198     fn node_label_final_row<W: io::Write>(&self,
199                                           n: &Node,
200                                           w: &mut W,
201                                           block: BasicBlock,
202                                           mir: &Body<'_>)
203                                           -> io::Result<()> {
204         let i = n.index();
205
206         let flow = self.mbcx.flow_state();
207
208         write!(w, "<tr>")?;
209
210         // Entry
211         let set = flow.sets.on_entry_set_for(i);
212         write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?;
213
214         // Terminator
215         write!(w, "<td>")?;
216         {
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))?;
221         }
222         write!(w, "</td>")?;
223
224         // Gen
225         let set = flow.sets.gen_set_for(i);
226         write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
227
228         // Kill
229         let set = flow.sets.kill_set_for(i);
230         write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
231
232         write!(w, "</tr>")?;
233
234         Ok(())
235     }
236 }
237
238 impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
239     where MWF: MirWithFlowState<'tcx>
240 {
241     type Node = Node;
242     type Edge = Edge;
243     fn nodes(&self) -> dot::Nodes<'_, Node> {
244         self.mbcx.mir()
245             .basic_blocks()
246             .indices()
247             .collect::<Vec<_>>()
248             .into()
249     }
250
251     fn edges(&self) -> dot::Edges<'_, Edge> {
252         let mir = self.mbcx.mir();
253
254         mir.basic_blocks()
255            .indices()
256            .flat_map(|bb| outgoing(mir, bb))
257            .collect::<Vec<_>>()
258            .into()
259     }
260
261     fn source(&self, edge: &Edge) -> Node {
262         edge.source
263     }
264
265     fn target(&self, edge: &Edge) -> Node {
266         let mir = self.mbcx.mir();
267         *mir[edge.source].terminator().successors().nth(edge.index).unwrap()
268     }
269 }