graphviz.rs 9.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Hook into libgraphviz for rendering dataflow graphs for MIR.

F
Felix S. Klock II 已提交
13
use syntax::ast::NodeId;
E
Eduard Burtescu 已提交
14
use rustc::mir::{BasicBlock, Mir};
15
use rustc_data_structures::bitslice::bits_to_string;
16 17 18 19

use dot;
use dot::IntoCow;

20
use std::fs;
21
use std::io;
F
Felix S. Klock II 已提交
22 23
use std::marker::PhantomData;
use std::path::Path;
24

F
Felix S. Klock II 已提交
25
use super::{BitDenotation, DataflowState};
26
use super::DataflowBuilder;
27
use super::DebugFormatted;
28

F
Felix S. Klock II 已提交
29
pub trait MirWithFlowState<'tcx> {
30
    type BD: BitDenotation;
F
Felix S. Klock II 已提交
31 32 33 34 35
    fn node_id(&self) -> NodeId;
    fn mir(&self) -> &Mir<'tcx>;
    fn flow_state(&self) -> &DataflowState<Self::BD>;
}

36 37
impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
    where BD: BitDenotation
F
Felix S. Klock II 已提交
38 39 40 41 42 43
{
    type BD = BD;
    fn node_id(&self) -> NodeId { self.node_id }
    fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
    fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
}
44

45 46
struct Graph<'a, 'tcx, MWF:'a, P> where
    MWF: MirWithFlowState<'tcx>
F
Felix S. Klock II 已提交
47 48
{
    mbcx: &'a MWF,
49 50
    phantom: PhantomData<&'tcx ()>,
    render_idx: P,
F
Felix S. Klock II 已提交
51 52
}

53 54
pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
    mbcx: &DataflowBuilder<'a, 'tcx, BD>,
55 56
    path: &Path,
    render_idx: P)
57
    -> io::Result<()>
58
    where BD: BitDenotation,
59
          P: Fn(&BD, BD::Idx) -> DebugFormatted
F
Felix S. Klock II 已提交
60
{
61
    let g = Graph { mbcx, phantom: PhantomData, render_idx };
62
    let mut v = Vec::new();
J
Jorge Aparicio 已提交
63
    dot::render(&g, &mut v)?;
F
Felix S. Klock II 已提交
64 65
    debug!("print_borrowck_graph_to path: {} node_id: {}",
           path.display(), mbcx.node_id);
66
    fs::write(path, v)
67 68 69 70 71 72 73 74
}

pub type Node = BasicBlock;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Edge { source: BasicBlock, index: usize }

fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
75 76
    (0..mir[bb].terminator().successors().count())
        .map(|index| Edge { source: bb, index: index}).collect()
77 78
}

79
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
80
    where MWF: MirWithFlowState<'tcx>,
81
          P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
F
Felix S. Klock II 已提交
82
{
83 84 85
    type Node = Node;
    type Edge = Edge;
    fn graph_id(&self) -> dot::Id {
F
Felix S. Klock II 已提交
86 87
        dot::Id::new(format!("graph_for_node_{}",
                             self.mbcx.node_id()))
88 89 90 91 92 93 94 95 96
            .unwrap()
    }

    fn node_id(&self, n: &Node) -> dot::Id {
        dot::Id::new(format!("bb_{}", n.index()))
            .unwrap()
    }

    fn node_label(&self, n: &Node) -> dot::LabelText {
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
        // Node label is something like this:
        // +---------+----------------------------------+------------------+------------------+
        // | ENTRY   | MIR                              | GEN              | KILL             |
        // +---------+----------------------------------+------------------+------------------+
        // |         |  0: StorageLive(_7)              | bb3[2]: reserved | bb2[0]: reserved |
        // |         |  1: StorageLive(_8)              | bb3[2]: active   | bb2[0]: active   |
        // |         |  2: _8 = &mut _1                 |                  | bb4[2]: reserved |
        // |         |                                  |                  | bb4[2]: active   |
        // |         |                                  |                  | bb9[0]: reserved |
        // |         |                                  |                  | bb9[0]: active   |
        // |         |                                  |                  | bb10[0]: reserved|
        // |         |                                  |                  | bb10[0]: active  |
        // |         |                                  |                  | bb11[0]: reserved|
        // |         |                                  |                  | bb11[0]: active  |
        // +---------+----------------------------------+------------------+------------------+
        // | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00]          | [f3-0f]          |
113
        // +---------+----------------------------------+------------------+------------------+
114
        let mut v = Vec::new();
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
        self.node_label_internal(n, &mut v, *n, self.mbcx.mir()).unwrap();
        dot::LabelText::html(String::from_utf8(v).unwrap())
    }


    fn node_shape(&self, _n: &Node) -> Option<dot::LabelText> {
        Some(dot::LabelText::label("none"))
    }

    fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> {
        let term = self.mbcx.mir()[e.source].terminator();
        let label = &term.kind.fmt_successor_labels()[e.index];
        dot::LabelText::label(label.clone())
    }
}

impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
where MWF: MirWithFlowState<'tcx>,
      P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
{
    /// Generate the node label
    fn node_label_internal<W: io::Write>(&self,
                                         n: &Node,
                                         w: &mut W,
                                         block: BasicBlock,
                                         mir: &Mir) -> io::Result<()> {
        // Header rows
142
        const HDRS: [&'static str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"];
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
        const HDR_FMT: &'static str = "bgcolor=\"grey\"";
        write!(w, "<table><tr><td rowspan=\"{}\">", HDRS.len())?;
        write!(w, "{:?}", block.index())?;
        write!(w, "</td></tr><tr>")?;
        for hdr in &HDRS {
            write!(w, "<td {}>{}</td>", HDR_FMT, hdr)?;
        }
        write!(w, "</tr>")?;

        // Data row
        self.node_label_verbose_row(n, w, block, mir)?;
        self.node_label_final_row(n, w, block, mir)?;
        write!(w, "</table>")?;

        Ok(())
    }

    /// Build the verbose row: full MIR data, and detailed gen/kill/entry sets
    fn node_label_verbose_row<W: io::Write>(&self,
                                            n: &Node,
                                            w: &mut W,
                                            block: BasicBlock,
                                            mir: &Mir)
                                            -> io::Result<()> {
167
        let i = n.index();
168 169

        macro_rules! dump_set_for {
170
            ($set:ident, $interpret:ident) => {
171 172 173
                write!(w, "<td>")?;

                let flow = self.mbcx.flow_state();
174 175 176
                let entry_interp = flow.$interpret(&flow.operator,
                                                   flow.sets.$set(i),
                                                   &self.render_idx);
177 178
                for e in &entry_interp {
                    write!(w, "{:?}<br/>", e)?;
179
                }
180
                write!(w, "</td>")?;
181
            }
182 183 184 185
        }

        write!(w, "<tr>")?;
        // Entry
186
        dump_set_for!(on_entry_set_for, interpret_set);
187 188 189 190 191 192 193 194

        // MIR statements
        write!(w, "<td>")?;
        {
            let data = &mir[block];
            for (i, statement) in data.statements.iter().enumerate() {
                write!(w, "{}<br align=\"left\"/>",
                       dot::escape_html(&format!("{:3}: {:?}", i, statement)))?;
195 196
            }
        }
197 198 199
        write!(w, "</td>")?;

        // Gen
200
        dump_set_for!(gen_set_for, interpret_hybrid_set);
201 202

        // Kill
203
        dump_set_for!(kill_set_for, interpret_hybrid_set);
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218

        write!(w, "</tr>")?;

        Ok(())
    }

    /// Build the summary row: terminator, gen/kill/entry bit sets
    fn node_label_final_row<W: io::Write>(&self,
                                          n: &Node,
                                          w: &mut W,
                                          block: BasicBlock,
                                          mir: &Mir)
                                          -> io::Result<()> {
        let i = n.index();

219 220
        let flow = self.mbcx.flow_state();
        let bits_per_block = flow.sets.bits_per_block();
F
Felix S. Klock II 已提交
221

222
        write!(w, "<tr>")?;
223

224
        // Entry
225 226
        let set = flow.sets.on_entry_set_for(i);
        write!(w, "<td>{:?}</td>", dot::escape_html(&bits_to_string(set.words(), bits_per_block)))?;
227

228 229 230 231 232 233 234 235 236
        // Terminator
        write!(w, "<td>")?;
        {
            let data = &mir[block];
            let mut terminator_head = String::new();
            data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
            write!(w, "{}", dot::escape_html(&terminator_head))?;
        }
        write!(w, "</td>")?;
237

238
        // Gen
239 240
        let set = flow.sets.gen_set_for(i);
        write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
241

242
        // Kill
243 244
        let set = flow.sets.kill_set_for(i);
        write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
245 246 247 248

        write!(w, "</tr>")?;

        Ok(())
249 250 251
    }
}

252
impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
F
Felix S. Klock II 已提交
253 254
    where MWF: MirWithFlowState<'tcx>
{
255 256 257
    type Node = Node;
    type Edge = Edge;
    fn nodes(&self) -> dot::Nodes<Node> {
258 259 260 261 262
        self.mbcx.mir()
            .basic_blocks()
            .indices()
            .collect::<Vec<_>>()
            .into_cow()
263 264 265
    }

    fn edges(&self) -> dot::Edges<Edge> {
F
Felix S. Klock II 已提交
266
        let mir = self.mbcx.mir();
267 268 269 270 271 272

        mir.basic_blocks()
           .indices()
           .flat_map(|bb| outgoing(mir, bb))
           .collect::<Vec<_>>()
           .into_cow()
273 274 275 276 277 278 279
    }

    fn source(&self, edge: &Edge) -> Node {
        edge.source
    }

    fn target(&self, edge: &Edge) -> Node {
F
Felix S. Klock II 已提交
280
        let mir = self.mbcx.mir();
281
        *mir[edge.source].terminator().successors().nth(edge.index).unwrap()
282 283
    }
}