]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/graphviz.rs
Rollup merge of #67671 - estebank:type-impl-trait, r=davidtwco
[rust.git] / src / librustc_mir / dataflow / graphviz.rs
1 //! Hook into libgraphviz for rendering dataflow graphs for MIR.
2
3 use rustc::mir::{BasicBlock, Body};
4 use rustc_hir::def_id::DefId;
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::DataflowBuilder;
14 use super::DebugFormatted;
15 use super::{BitDenotation, DataflowState};
16
17 pub trait MirWithFlowState<'tcx> {
18     type BD: BitDenotation<'tcx>;
19     fn def_id(&self) -> DefId;
20     fn body(&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
26     BD: BitDenotation<'tcx>,
27 {
28     type BD = BD;
29     fn def_id(&self) -> DefId {
30         self.def_id
31     }
32     fn body(&self) -> &Body<'tcx> {
33         self.flow_state.body()
34     }
35     fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> {
36         &self.flow_state.flow_state
37     }
38 }
39
40 struct Graph<'a, 'tcx, MWF, P>
41 where
42     MWF: MirWithFlowState<'tcx>,
43 {
44     mbcx: &'a MWF,
45     phantom: PhantomData<&'tcx ()>,
46     render_idx: P,
47 }
48
49 pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
50     mbcx: &DataflowBuilder<'a, 'tcx, BD>,
51     path: &Path,
52     render_idx: P,
53 ) -> io::Result<()>
54 where
55     BD: BitDenotation<'tcx>,
56     P: Fn(&BD, BD::Idx) -> DebugFormatted,
57 {
58     let g = Graph { mbcx, phantom: PhantomData, render_idx };
59     let mut v = Vec::new();
60     dot::render(&g, &mut v)?;
61     debug!("print_borrowck_graph_to path: {} def_id: {:?}", path.display(), mbcx.def_id);
62     fs::write(path, v)
63 }
64
65 pub type Node = BasicBlock;
66
67 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
68 pub struct Edge {
69     source: BasicBlock,
70     index: usize,
71 }
72
73 fn outgoing(body: &Body<'_>, bb: BasicBlock) -> Vec<Edge> {
74     (0..body[bb].terminator().successors().count())
75         .map(|index| Edge { source: bb, index: index })
76         .collect()
77 }
78
79 impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
80 where
81     MWF: MirWithFlowState<'tcx>,
82     P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
83 {
84     type Node = Node;
85     type Edge = Edge;
86     fn graph_id(&self) -> dot::Id<'_> {
87         let name = graphviz_safe_def_name(self.mbcx.def_id());
88         dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
89     }
90
91     fn node_id(&self, n: &Node) -> dot::Id<'_> {
92         dot::Id::new(format!("bb_{}", n.index())).unwrap()
93     }
94
95     fn node_label(&self, n: &Node) -> dot::LabelText<'_> {
96         // Node label is something like this:
97         // +---------+----------------------------------+------------------+------------------+
98         // | ENTRY   | MIR                              | GEN              | KILL             |
99         // +---------+----------------------------------+------------------+------------------+
100         // |         |  0: StorageLive(_7)              | bb3[2]: reserved | bb2[0]: reserved |
101         // |         |  1: StorageLive(_8)              | bb3[2]: active   | bb2[0]: active   |
102         // |         |  2: _8 = &mut _1                 |                  | bb4[2]: reserved |
103         // |         |                                  |                  | bb4[2]: active   |
104         // |         |                                  |                  | bb9[0]: reserved |
105         // |         |                                  |                  | bb9[0]: active   |
106         // |         |                                  |                  | bb10[0]: reserved|
107         // |         |                                  |                  | bb10[0]: active  |
108         // |         |                                  |                  | bb11[0]: reserved|
109         // |         |                                  |                  | bb11[0]: active  |
110         // +---------+----------------------------------+------------------+------------------+
111         // | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00]          | [f3-0f]          |
112         // +---------+----------------------------------+------------------+------------------+
113         let mut v = Vec::new();
114         self.node_label_internal(n, &mut v, *n, self.mbcx.body()).unwrap();
115         dot::LabelText::html(String::from_utf8(v).unwrap())
116     }
117
118     fn node_shape(&self, _n: &Node) -> Option<dot::LabelText<'_>> {
119         Some(dot::LabelText::label("none"))
120     }
121
122     fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> {
123         let term = self.mbcx.body()[e.source].terminator();
124         let label = &term.kind.fmt_successor_labels()[e.index];
125         dot::LabelText::label(label.clone())
126     }
127 }
128
129 impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
130 where
131     MWF: MirWithFlowState<'tcx>,
132     P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
133 {
134     /// Generate the node label
135     fn node_label_internal<W: io::Write>(
136         &self,
137         n: &Node,
138         w: &mut W,
139         block: BasicBlock,
140         body: &Body<'_>,
141     ) -> io::Result<()> {
142         // Header rows
143         const HDRS: [&str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"];
144         const HDR_FMT: &str = "bgcolor=\"grey\"";
145         write!(w, "<table><tr><td rowspan=\"{}\">", HDRS.len())?;
146         write!(w, "{:?}", block.index())?;
147         write!(w, "</td></tr><tr>")?;
148         for hdr in &HDRS {
149             write!(w, "<td {}>{}</td>", HDR_FMT, hdr)?;
150         }
151         write!(w, "</tr>")?;
152
153         // Data row
154         self.node_label_verbose_row(n, w, block, body)?;
155         self.node_label_final_row(n, w, block, body)?;
156         write!(w, "</table>")?;
157
158         Ok(())
159     }
160
161     /// Builds the verbose row: full MIR data, and detailed gen/kill/entry sets.
162     fn node_label_verbose_row<W: io::Write>(
163         &self,
164         n: &Node,
165         w: &mut W,
166         block: BasicBlock,
167         body: &Body<'_>,
168     ) -> io::Result<()> {
169         let i = n.index();
170
171         macro_rules! dump_set_for {
172             ($set:ident, $interpret:ident) => {
173                 write!(w, "<td>")?;
174
175                 let flow = self.mbcx.flow_state();
176                 let entry_interp =
177                     flow.$interpret(&flow.operator, flow.sets.$set(i), &self.render_idx);
178                 for e in &entry_interp {
179                     write!(w, "{:?}<br/>", e)?;
180                 }
181                 write!(w, "</td>")?;
182             };
183         }
184
185         write!(w, "<tr>")?;
186         // Entry
187         dump_set_for!(entry_set_for, interpret_set);
188
189         // MIR statements
190         write!(w, "<td>")?;
191         {
192             let data = &body[block];
193             for (i, statement) in data.statements.iter().enumerate() {
194                 write!(
195                     w,
196                     "{}<br align=\"left\"/>",
197                     dot::escape_html(&format!("{:3}: {:?}", i, statement))
198                 )?;
199             }
200         }
201         write!(w, "</td>")?;
202
203         // Gen
204         dump_set_for!(gen_set_for, interpret_hybrid_set);
205
206         // Kill
207         dump_set_for!(kill_set_for, interpret_hybrid_set);
208
209         write!(w, "</tr>")?;
210
211         Ok(())
212     }
213
214     /// Builds the summary row: terminator, gen/kill/entry bit sets.
215     fn node_label_final_row<W: io::Write>(
216         &self,
217         n: &Node,
218         w: &mut W,
219         block: BasicBlock,
220         body: &Body<'_>,
221     ) -> io::Result<()> {
222         let i = n.index();
223
224         let flow = self.mbcx.flow_state();
225
226         write!(w, "<tr>")?;
227
228         // Entry
229         let set = flow.sets.entry_set_for(i);
230         write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?;
231
232         // Terminator
233         write!(w, "<td>")?;
234         {
235             let data = &body[block];
236             let mut terminator_head = String::new();
237             data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
238             write!(w, "{}", dot::escape_html(&terminator_head))?;
239         }
240         write!(w, "</td>")?;
241
242         // Gen/Kill
243         let trans = flow.sets.trans_for(i);
244         write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.gen_set)))?;
245         write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.kill_set)))?;
246
247         write!(w, "</tr>")?;
248
249         Ok(())
250     }
251 }
252
253 impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
254 where
255     MWF: MirWithFlowState<'tcx>,
256 {
257     type Node = Node;
258     type Edge = Edge;
259     fn nodes(&self) -> dot::Nodes<'_, Node> {
260         self.mbcx.body().basic_blocks().indices().collect::<Vec<_>>().into()
261     }
262
263     fn edges(&self) -> dot::Edges<'_, Edge> {
264         let body = self.mbcx.body();
265
266         body.basic_blocks().indices().flat_map(|bb| outgoing(body, bb)).collect::<Vec<_>>().into()
267     }
268
269     fn source(&self, edge: &Edge) -> Node {
270         edge.source
271     }
272
273     fn target(&self, edge: &Edge) -> Node {
274         let body = self.mbcx.body();
275         *body[edge.source].terminator().successors().nth(edge.index).unwrap()
276     }
277 }