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