]>
Commit | Line | Data |
---|---|---|
3157f602 XL |
1 | //! Hook into libgraphviz for rendering dataflow graphs for MIR. |
2 | ||
dc9dc135 | 3 | use rustc::mir::{BasicBlock, Body}; |
dfeec247 | 4 | use rustc_hir::def_id::DefId; |
3157f602 | 5 | |
2c00a5a8 | 6 | use std::fs; |
3157f602 | 7 | use std::io; |
3157f602 | 8 | use std::marker::PhantomData; |
3157f602 XL |
9 | use std::path::Path; |
10 | ||
532ac7d7 XL |
11 | use crate::util::graphviz_safe_def_name; |
12 | ||
041b39d2 | 13 | use super::DataflowBuilder; |
ff7c6d11 | 14 | use super::DebugFormatted; |
dfeec247 | 15 | use super::{BitDenotation, DataflowState}; |
3157f602 | 16 | |
3157f602 | 17 | pub trait MirWithFlowState<'tcx> { |
0731742a | 18 | type BD: BitDenotation<'tcx>; |
532ac7d7 | 19 | fn def_id(&self) -> DefId; |
dc9dc135 | 20 | fn body(&self) -> &Body<'tcx>; |
0731742a | 21 | fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>; |
3157f602 XL |
22 | } |
23 | ||
8faf50e0 | 24 | impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD> |
dfeec247 XL |
25 | where |
26 | BD: BitDenotation<'tcx>, | |
3157f602 XL |
27 | { |
28 | type BD = BD; | |
dfeec247 XL |
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 | } | |
3157f602 XL |
38 | } |
39 | ||
dfeec247 XL |
40 | struct Graph<'a, 'tcx, MWF, P> |
41 | where | |
42 | MWF: MirWithFlowState<'tcx>, | |
3157f602 XL |
43 | { |
44 | mbcx: &'a MWF, | |
45 | phantom: PhantomData<&'tcx ()>, | |
46 | render_idx: P, | |
47 | } | |
48 | ||
041b39d2 XL |
49 | pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>( |
50 | mbcx: &DataflowBuilder<'a, 'tcx, BD>, | |
3157f602 | 51 | path: &Path, |
dfeec247 XL |
52 | render_idx: P, |
53 | ) -> io::Result<()> | |
54 | where | |
55 | BD: BitDenotation<'tcx>, | |
56 | P: Fn(&BD, BD::Idx) -> DebugFormatted, | |
3157f602 | 57 | { |
ff7c6d11 | 58 | let g = Graph { mbcx, phantom: PhantomData, render_idx }; |
3157f602 XL |
59 | let mut v = Vec::new(); |
60 | dot::render(&g, &mut v)?; | |
dfeec247 | 61 | debug!("print_borrowck_graph_to path: {} def_id: {:?}", path.display(), mbcx.def_id); |
2c00a5a8 | 62 | fs::write(path, v) |
3157f602 XL |
63 | } |
64 | ||
65 | pub type Node = BasicBlock; | |
66 | ||
67 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
dfeec247 XL |
68 | pub struct Edge { |
69 | source: BasicBlock, | |
70 | index: usize, | |
71 | } | |
3157f602 | 72 | |
dc9dc135 XL |
73 | fn outgoing(body: &Body<'_>, bb: BasicBlock) -> Vec<Edge> { |
74 | (0..body[bb].terminator().successors().count()) | |
74b04a01 | 75 | .map(|index| Edge { source: bb, index }) |
dfeec247 | 76 | .collect() |
3157f602 XL |
77 | } |
78 | ||
79 | impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> | |
dfeec247 XL |
80 | where |
81 | MWF: MirWithFlowState<'tcx>, | |
82 | P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted, | |
3157f602 XL |
83 | { |
84 | type Node = Node; | |
85 | type Edge = Edge; | |
9fa01778 | 86 | fn graph_id(&self) -> dot::Id<'_> { |
532ac7d7 XL |
87 | let name = graphviz_safe_def_name(self.mbcx.def_id()); |
88 | dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap() | |
3157f602 XL |
89 | } |
90 | ||
9fa01778 | 91 | fn node_id(&self, n: &Node) -> dot::Id<'_> { |
dfeec247 | 92 | dot::Id::new(format!("bb_{}", n.index())).unwrap() |
3157f602 XL |
93 | } |
94 | ||
9fa01778 | 95 | fn node_label(&self, n: &Node) -> dot::LabelText<'_> { |
0531ce1d XL |
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 | // +---------+----------------------------------+------------------+------------------+ | |
3157f602 | 113 | let mut v = Vec::new(); |
dc9dc135 | 114 | self.node_label_internal(n, &mut v, *n, self.mbcx.body()).unwrap(); |
0531ce1d XL |
115 | dot::LabelText::html(String::from_utf8(v).unwrap()) |
116 | } | |
117 | ||
9fa01778 | 118 | fn node_shape(&self, _n: &Node) -> Option<dot::LabelText<'_>> { |
0531ce1d XL |
119 | Some(dot::LabelText::label("none")) |
120 | } | |
121 | ||
122 | fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> { | |
dc9dc135 | 123 | let term = self.mbcx.body()[e.source].terminator(); |
0531ce1d XL |
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> | |
dfeec247 XL |
130 | where |
131 | MWF: MirWithFlowState<'tcx>, | |
132 | P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted, | |
0531ce1d XL |
133 | { |
134 | /// Generate the node label | |
dfeec247 XL |
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<()> { | |
0531ce1d | 142 | // Header rows |
0731742a XL |
143 | const HDRS: [&str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"]; |
144 | const HDR_FMT: &str = "bgcolor=\"grey\""; | |
0531ce1d XL |
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 | |
dc9dc135 XL |
154 | self.node_label_verbose_row(n, w, block, body)?; |
155 | self.node_label_final_row(n, w, block, body)?; | |
0531ce1d XL |
156 | write!(w, "</table>")?; |
157 | ||
158 | Ok(()) | |
159 | } | |
160 | ||
9fa01778 | 161 | /// Builds the verbose row: full MIR data, and detailed gen/kill/entry sets. |
dfeec247 XL |
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<()> { | |
3157f602 | 169 | let i = n.index(); |
0531ce1d XL |
170 | |
171 | macro_rules! dump_set_for { | |
b7449926 | 172 | ($set:ident, $interpret:ident) => { |
0531ce1d XL |
173 | write!(w, "<td>")?; |
174 | ||
175 | let flow = self.mbcx.flow_state(); | |
dfeec247 XL |
176 | let entry_interp = |
177 | flow.$interpret(&flow.operator, flow.sets.$set(i), &self.render_idx); | |
0531ce1d XL |
178 | for e in &entry_interp { |
179 | write!(w, "{:?}<br/>", e)?; | |
3157f602 | 180 | } |
0531ce1d | 181 | write!(w, "</td>")?; |
dfeec247 | 182 | }; |
0531ce1d XL |
183 | } |
184 | ||
185 | write!(w, "<tr>")?; | |
186 | // Entry | |
dc9dc135 | 187 | dump_set_for!(entry_set_for, interpret_set); |
0531ce1d XL |
188 | |
189 | // MIR statements | |
190 | write!(w, "<td>")?; | |
191 | { | |
dc9dc135 | 192 | let data = &body[block]; |
0531ce1d | 193 | for (i, statement) in data.statements.iter().enumerate() { |
dfeec247 XL |
194 | write!( |
195 | w, | |
196 | "{}<br align=\"left\"/>", | |
197 | dot::escape_html(&format!("{:3}: {:?}", i, statement)) | |
198 | )?; | |
3157f602 | 199 | } |
3157f602 | 200 | } |
0531ce1d XL |
201 | write!(w, "</td>")?; |
202 | ||
203 | // Gen | |
b7449926 | 204 | dump_set_for!(gen_set_for, interpret_hybrid_set); |
0531ce1d XL |
205 | |
206 | // Kill | |
b7449926 | 207 | dump_set_for!(kill_set_for, interpret_hybrid_set); |
0531ce1d XL |
208 | |
209 | write!(w, "</tr>")?; | |
210 | ||
211 | Ok(()) | |
212 | } | |
213 | ||
9fa01778 | 214 | /// Builds the summary row: terminator, gen/kill/entry bit sets. |
dfeec247 XL |
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<()> { | |
0531ce1d XL |
222 | let i = n.index(); |
223 | ||
b7449926 | 224 | let flow = self.mbcx.flow_state(); |
3157f602 | 225 | |
0531ce1d | 226 | write!(w, "<tr>")?; |
b7449926 | 227 | |
0531ce1d | 228 | // Entry |
dc9dc135 | 229 | let set = flow.sets.entry_set_for(i); |
0bf4aa26 | 230 | write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?; |
3157f602 | 231 | |
0531ce1d XL |
232 | // Terminator |
233 | write!(w, "<td>")?; | |
234 | { | |
dc9dc135 | 235 | let data = &body[block]; |
0531ce1d XL |
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>")?; | |
3157f602 | 241 | |
dc9dc135 XL |
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)))?; | |
0531ce1d XL |
246 | |
247 | write!(w, "</tr>")?; | |
248 | ||
249 | Ok(()) | |
3157f602 XL |
250 | } |
251 | } | |
252 | ||
253 | impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> | |
dfeec247 XL |
254 | where |
255 | MWF: MirWithFlowState<'tcx>, | |
3157f602 XL |
256 | { |
257 | type Node = Node; | |
258 | type Edge = Edge; | |
9fa01778 | 259 | fn nodes(&self) -> dot::Nodes<'_, Node> { |
dfeec247 | 260 | self.mbcx.body().basic_blocks().indices().collect::<Vec<_>>().into() |
3157f602 XL |
261 | } |
262 | ||
9fa01778 | 263 | fn edges(&self) -> dot::Edges<'_, Edge> { |
dc9dc135 | 264 | let body = self.mbcx.body(); |
b7449926 | 265 | |
dfeec247 | 266 | body.basic_blocks().indices().flat_map(|bb| outgoing(body, bb)).collect::<Vec<_>>().into() |
3157f602 XL |
267 | } |
268 | ||
269 | fn source(&self, edge: &Edge) -> Node { | |
270 | edge.source | |
271 | } | |
272 | ||
273 | fn target(&self, edge: &Edge) -> Node { | |
dc9dc135 XL |
274 | let body = self.mbcx.body(); |
275 | *body[edge.source].terminator().successors().nth(edge.index).unwrap() | |
3157f602 XL |
276 | } |
277 | } |