1 // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Hook into libgraphviz for rendering dataflow graphs for MIR.
13 use syntax::ast::NodeId;
14 use rustc::mir::{BasicBlock, Mir};
15 use rustc_data_structures::bitslice::bits_to_string;
16 use rustc_data_structures::indexed_vec::Idx;
23 use std::marker::PhantomData;
26 use super::{BitDenotation, DataflowState};
27 use super::DataflowBuilder;
28 use super::DebugFormatted;
30 pub trait MirWithFlowState<'tcx> {
31 type BD: BitDenotation;
32 fn node_id(&self) -> NodeId;
33 fn mir(&self) -> &Mir<'tcx>;
34 fn flow_state(&self) -> &DataflowState<Self::BD>;
37 impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
38 where BD: BitDenotation
41 fn node_id(&self) -> NodeId { self.node_id }
42 fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
43 fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
46 struct Graph<'a, 'tcx, MWF:'a, P> where
47 MWF: MirWithFlowState<'tcx>
50 phantom: PhantomData<&'tcx ()>,
54 pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
55 mbcx: &DataflowBuilder<'a, 'tcx, BD>,
59 where BD: BitDenotation,
60 P: Fn(&BD, BD::Idx) -> DebugFormatted
62 let g = Graph { mbcx, phantom: PhantomData, render_idx };
63 let mut v = Vec::new();
64 dot::render(&g, &mut v)?;
65 debug!("print_borrowck_graph_to path: {} node_id: {}",
66 path.display(), mbcx.node_id);
70 pub type Node = BasicBlock;
72 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
73 pub struct Edge { source: BasicBlock, index: usize }
75 fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
76 (0..mir[bb].terminator().successors().count())
77 .map(|index| Edge { source: bb, index: index}).collect()
80 impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
81 where MWF: MirWithFlowState<'tcx>,
82 P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
86 fn graph_id(&self) -> dot::Id {
87 dot::Id::new(format!("graph_for_node_{}",
92 fn node_id(&self, n: &Node) -> dot::Id {
93 dot::Id::new(format!("bb_{}", n.index()))
97 fn node_label(&self, n: &Node) -> dot::LabelText {
98 // Node label is something like this:
99 // +---------+----------------------------------+------------------+------------------+
100 // | ENTRY | MIR | GEN | KILL |
101 // +---------+----------------------------------+------------------+------------------+
102 // | | 0: StorageLive(_7) | bb3[2]: reserved | bb2[0]: reserved |
103 // | | 1: StorageLive(_8) | bb3[2]: active | bb2[0]: active |
104 // | | 2: _8 = &mut _1 | | bb4[2]: reserved |
105 // | | | | bb4[2]: active |
106 // | | | | bb9[0]: reserved |
107 // | | | | bb9[0]: active |
108 // | | | | bb10[0]: reserved|
109 // | | | | bb10[0]: active |
110 // | | | | bb11[0]: reserved|
111 // | | | | bb11[0]: active |
112 // +---------+----------------------------------+------------------+------------------+
113 // | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00] | [f3-0f] |
114 // +---------+----------------------------------+------------------+------------------+
115 let mut v = Vec::new();
116 self.node_label_internal(n, &mut v, *n, self.mbcx.mir()).unwrap();
117 dot::LabelText::html(String::from_utf8(v).unwrap())
121 fn node_shape(&self, _n: &Node) -> Option<dot::LabelText> {
122 Some(dot::LabelText::label("none"))
125 fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> {
126 let term = self.mbcx.mir()[e.source].terminator();
127 let label = &term.kind.fmt_successor_labels()[e.index];
128 dot::LabelText::label(label.clone())
132 impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
133 where MWF: MirWithFlowState<'tcx>,
134 P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
136 /// Generate the node label
137 fn node_label_internal<W: io::Write>(&self,
141 mir: &Mir) -> io::Result<()> {
143 const HDRS: [&'static str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"];
144 const HDR_FMT: &'static str = "bgcolor=\"grey\"";
145 write!(w, "<table><tr><td rowspan=\"{}\">", HDRS.len())?;
146 write!(w, "{:?}", block.index())?;
147 write!(w, "</td></tr><tr>")?;
149 write!(w, "<td {}>{}</td>", HDR_FMT, hdr)?;
154 self.node_label_verbose_row(n, w, block, mir)?;
155 self.node_label_final_row(n, w, block, mir)?;
156 write!(w, "</table>")?;
161 /// Build the verbose row: full MIR data, and detailed gen/kill/entry sets
162 fn node_label_verbose_row<W: io::Write>(&self,
170 macro_rules! dump_set_for {
174 let flow = self.mbcx.flow_state();
175 let entry_interp = flow.interpret_set(&flow.operator,
178 for e in &entry_interp {
179 write!(w, "{:?}<br/>", e)?;
187 dump_set_for!(on_entry_set_for);
192 let data = &mir[block];
193 for (i, statement) in data.statements.iter().enumerate() {
194 write!(w, "{}<br align=\"left\"/>",
195 dot::escape_html(&format!("{:3}: {:?}", i, statement)))?;
201 dump_set_for!(gen_set_for);
204 dump_set_for!(kill_set_for);
211 /// Build the summary row: terminator, gen/kill/entry bit sets
212 fn node_label_final_row<W: io::Write>(&self,
220 macro_rules! dump_set_for {
222 let flow = self.mbcx.flow_state();
223 let bits_per_block = flow.sets.bits_per_block();
224 let set = flow.sets.$set(i);
225 write!(w, "<td>{:?}</td>",
226 dot::escape_html(&bits_to_string(set.words(), bits_per_block)))?;
232 dump_set_for!(on_entry_set_for);
237 let data = &mir[block];
238 let mut terminator_head = String::new();
239 data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
240 write!(w, "{}", dot::escape_html(&terminator_head))?;
245 dump_set_for!(gen_set_for);
248 dump_set_for!(kill_set_for);
256 impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
257 where MWF: MirWithFlowState<'tcx>
261 fn nodes(&self) -> dot::Nodes<Node> {
269 fn edges(&self) -> dot::Edges<Edge> {
270 let mir = self.mbcx.mir();
271 // base initial capacity on assumption every block has at
272 // least one outgoing edge (Which should be true for all
273 // blocks but one, the exit-block).
274 let mut edges = Vec::with_capacity(mir.basic_blocks().len());
275 for bb in mir.basic_blocks().indices() {
276 let outgoing = outgoing(mir, bb);
277 edges.extend(outgoing.into_iter());
282 fn source(&self, edge: &Edge) -> Node {
286 fn target(&self, edge: &Edge) -> Node {
287 let mir = self.mbcx.mir();
288 *mir[edge.source].terminator().successors().nth(edge.index).unwrap()