]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/dataflow/graphviz.rs
New upstream version 1.43.0+dfsg1
[rustc.git] / src / librustc_mir / dataflow / graphviz.rs
CommitLineData
3157f602
XL
1//! Hook into libgraphviz for rendering dataflow graphs for MIR.
2
dc9dc135 3use rustc::mir::{BasicBlock, Body};
dfeec247 4use rustc_hir::def_id::DefId;
3157f602 5
2c00a5a8 6use std::fs;
3157f602 7use std::io;
3157f602 8use std::marker::PhantomData;
3157f602
XL
9use std::path::Path;
10
532ac7d7
XL
11use crate::util::graphviz_safe_def_name;
12
041b39d2 13use super::DataflowBuilder;
ff7c6d11 14use super::DebugFormatted;
dfeec247 15use super::{BitDenotation, DataflowState};
3157f602 16
3157f602 17pub 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 24impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
dfeec247
XL
25where
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
40struct Graph<'a, 'tcx, MWF, P>
41where
42 MWF: MirWithFlowState<'tcx>,
3157f602
XL
43{
44 mbcx: &'a MWF,
45 phantom: PhantomData<&'tcx ()>,
46 render_idx: P,
47}
48
041b39d2
XL
49pub(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<()>
54where
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
65pub type Node = BasicBlock;
66
67#[derive(Copy, Clone, PartialEq, Eq, Debug)]
dfeec247
XL
68pub struct Edge {
69 source: BasicBlock,
70 index: usize,
71}
3157f602 72
dc9dc135
XL
73fn 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
79impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
dfeec247
XL
80where
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
129impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
dfeec247
XL
130where
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
253impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
dfeec247
XL
254where
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}