Rewrite MIR graphviz printing and improve MIR debug printing.
This commit is contained in:
parent
27a1834ce5
commit
9000ecf761
5 changed files with 236 additions and 200 deletions
|
|
@ -11,14 +11,15 @@
|
|||
use middle::const_eval::ConstVal;
|
||||
use middle::def_id::DefId;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
||||
use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
||||
use rustc_back::slice;
|
||||
use rustc_data_structures::tuple_slice::TupleSlice;
|
||||
use rustc_front::hir::InlineAsm;
|
||||
use syntax::ast::Name;
|
||||
use syntax::codemap::Span;
|
||||
use std::fmt::{Debug, Formatter, Error};
|
||||
use std::u32;
|
||||
use std::borrow::{Cow, IntoCow};
|
||||
use std::fmt::{Debug, Formatter, Error, Write};
|
||||
use std::{iter, u32};
|
||||
|
||||
/// Lowered representation of a single function.
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
|
@ -317,23 +318,43 @@ impl<'tcx> BasicBlockData<'tcx> {
|
|||
|
||||
impl<'tcx> Debug for Terminator<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
try!(self.fmt_head(fmt));
|
||||
let successors = self.successors();
|
||||
let labels = self.fmt_successor_labels();
|
||||
assert_eq!(successors.len(), labels.len());
|
||||
|
||||
match successors.len() {
|
||||
0 => Ok(()),
|
||||
|
||||
1 => write!(fmt, " -> {:?}", successors[0]),
|
||||
|
||||
_ => {
|
||||
try!(write!(fmt, " -> ["));
|
||||
for (i, target) in successors.iter().enumerate() {
|
||||
if i > 0 {
|
||||
try!(write!(fmt, ", "));
|
||||
}
|
||||
try!(write!(fmt, "{}: {:?}", labels[i], target));
|
||||
}
|
||||
write!(fmt, "]")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Terminator<'tcx> {
|
||||
pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> Result<(), Error> {
|
||||
use self::Terminator::*;
|
||||
match *self {
|
||||
Goto { target } =>
|
||||
write!(fmt, "goto -> {:?}", target),
|
||||
Panic { target } =>
|
||||
write!(fmt, "panic -> {:?}", target),
|
||||
If { cond: ref lv, ref targets } =>
|
||||
write!(fmt, "if({:?}) -> {:?}", lv, targets),
|
||||
Switch { discr: ref lv, adt_def: _, ref targets } =>
|
||||
write!(fmt, "switch({:?}) -> {:?}", lv, targets),
|
||||
SwitchInt { discr: ref lv, switch_ty: _, ref values, ref targets } =>
|
||||
write!(fmt, "switchInt({:?}, {:?}) -> {:?}", lv, values, targets),
|
||||
Diverge =>
|
||||
write!(fmt, "diverge"),
|
||||
Return =>
|
||||
write!(fmt, "return"),
|
||||
Call { data: ref c, targets } => {
|
||||
Goto { .. } => write!(fmt, "goto"),
|
||||
Panic { .. } => write!(fmt, "panic"),
|
||||
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
|
||||
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
|
||||
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
|
||||
Diverge => write!(fmt, "diverge"),
|
||||
Return => write!(fmt, "return"),
|
||||
Call { data: ref c, .. } => {
|
||||
try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func));
|
||||
for (index, arg) in c.args.iter().enumerate() {
|
||||
if index > 0 {
|
||||
|
|
@ -341,7 +362,33 @@ impl<'tcx> Debug for Terminator<'tcx> {
|
|||
}
|
||||
try!(write!(fmt, "{:?}", arg));
|
||||
}
|
||||
write!(fmt, ") -> {:?}", targets)
|
||||
write!(fmt, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
|
||||
use self::Terminator::*;
|
||||
match *self {
|
||||
Diverge | Return => vec![],
|
||||
Goto { .. } | Panic { .. } => vec!["".into_cow()],
|
||||
If { .. } => vec!["true".into_cow(), "false".into_cow()],
|
||||
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
|
||||
Switch { ref adt_def, .. } => {
|
||||
adt_def.variants
|
||||
.iter()
|
||||
.map(|variant| variant.name.to_string().into_cow())
|
||||
.collect()
|
||||
}
|
||||
SwitchInt { ref values, .. } => {
|
||||
values.iter()
|
||||
.map(|const_val| {
|
||||
let mut buf = String::new();
|
||||
fmt_const_val(&mut buf, const_val).unwrap();
|
||||
buf.into_cow()
|
||||
})
|
||||
.chain(iter::once(String::from("otherwise").into_cow()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -495,19 +542,19 @@ impl<'tcx> Debug for Lvalue<'tcx> {
|
|||
|
||||
match *self {
|
||||
Var(id) =>
|
||||
write!(fmt,"Var({:?})", id),
|
||||
write!(fmt,"v{:?}", id),
|
||||
Arg(id) =>
|
||||
write!(fmt,"Arg({:?})", id),
|
||||
write!(fmt,"a{:?}", id),
|
||||
Temp(id) =>
|
||||
write!(fmt,"Temp({:?})", id),
|
||||
write!(fmt,"t{:?}", id),
|
||||
Static(id) =>
|
||||
write!(fmt,"Static({:?})", id),
|
||||
ReturnPointer =>
|
||||
write!(fmt,"ReturnPointer"),
|
||||
Projection(ref data) =>
|
||||
match data.elem {
|
||||
ProjectionElem::Downcast(_, variant_index) =>
|
||||
write!(fmt,"({:?} as {:?})", data.base, variant_index),
|
||||
ProjectionElem::Downcast(ref adt_def, index) =>
|
||||
write!(fmt,"({:?} as {})", data.base, adt_def.variants[index].name),
|
||||
ProjectionElem::Deref =>
|
||||
write!(fmt,"(*{:?})", data.base),
|
||||
ProjectionElem::Field(field) =>
|
||||
|
|
@ -671,12 +718,12 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
Use(ref lvalue) => write!(fmt, "{:?}", lvalue),
|
||||
Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b),
|
||||
Ref(ref a, bk, ref b) => write!(fmt, "&{:?} {:?} {:?}", a, bk, b),
|
||||
Len(ref a) => write!(fmt, "LEN({:?})", a),
|
||||
Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?}", lv, ty, kind),
|
||||
BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?},{:?})", op, a, b),
|
||||
Len(ref a) => write!(fmt, "Len({:?})", a),
|
||||
Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?})", lv, ty, kind),
|
||||
BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b),
|
||||
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
|
||||
Box(ref t) => write!(fmt, "Box {:?}", t),
|
||||
Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>({:?})", kind, lvs),
|
||||
Box(ref t) => write!(fmt, "Box({:?})", t),
|
||||
Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>{:?}", kind, lvs),
|
||||
InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm),
|
||||
Slice { ref input, from_start, from_end } =>
|
||||
write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
|
||||
|
|
@ -691,7 +738,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
// this does not necessarily mean that they are "==" in Rust -- in
|
||||
// particular one must be wary of `NaN`!
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub struct Constant<'tcx> {
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
|
|
@ -707,7 +754,7 @@ pub enum ItemKind {
|
|||
Method,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Literal<'tcx> {
|
||||
Item {
|
||||
def_id: DefId,
|
||||
|
|
@ -718,3 +765,37 @@ pub enum Literal<'tcx> {
|
|||
value: ConstVal,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Constant<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
write!(fmt, "{:?}", self.literal)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Literal<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
use self::Literal::*;
|
||||
match *self {
|
||||
Item { def_id, .. } =>
|
||||
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
|
||||
Value { ref value } => fmt_const_val(fmt, value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> Result<(), Error> {
|
||||
use middle::const_eval::ConstVal::*;
|
||||
match *const_val {
|
||||
Float(f) => write!(fmt, "{:?}", f),
|
||||
Int(n) => write!(fmt, "{:?}", n),
|
||||
Uint(n) => write!(fmt, "{:?}", n),
|
||||
Str(ref s) => write!(fmt, "Str({:?})", s),
|
||||
ByteStr(ref bytes) => write!(fmt, "ByteStr{:?}", bytes),
|
||||
Bool(b) => write!(fmt, "{:?}", b),
|
||||
Struct(id) => write!(fmt, "Struct({:?})", id),
|
||||
Tuple(id) => write!(fmt, "Tuple({:?})", id),
|
||||
Function(def_id) => write!(fmt, "Function({:?})", def_id),
|
||||
Array(id, n) => write!(fmt, "Array({:?}, {:?})", id, n),
|
||||
Repeat(id, n) => write!(fmt, "Repeat({:?}, {:?})", id, n),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
120
src/librustc_mir/graphviz.rs
Normal file
120
src/librustc_mir/graphviz.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
use dot;
|
||||
use rustc::mir::repr::*;
|
||||
use rustc::middle::ty;
|
||||
use std::io::{self, Write};
|
||||
|
||||
pub fn write_mir_graphviz<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
|
||||
try!(writeln!(w, "digraph Mir {{"));
|
||||
|
||||
// Global graph properties
|
||||
try!(writeln!(w, r#"graph [fontname="monospace"];"#));
|
||||
try!(writeln!(w, r#"node [fontname="monospace"];"#));
|
||||
try!(writeln!(w, r#"edge [fontname="monospace"];"#));
|
||||
|
||||
// Graph label
|
||||
try!(write_graph_label(mir, w));
|
||||
|
||||
// Nodes
|
||||
for block in mir.all_basic_blocks() {
|
||||
try!(write_node(block, mir, w));
|
||||
}
|
||||
|
||||
// Edges
|
||||
for source in mir.all_basic_blocks() {
|
||||
try!(write_edges(source, mir, w));
|
||||
}
|
||||
|
||||
writeln!(w, "}}")
|
||||
}
|
||||
|
||||
fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
|
||||
let data = mir.basic_block_data(block);
|
||||
|
||||
try!(write!(w, r#"bb{} [shape="none", label=<"#, block.index()));
|
||||
try!(write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#));
|
||||
|
||||
try!(write!(w, r#"<tr><td bgcolor="gray" align="center">"#));
|
||||
try!(write!(w, "{}", block.index()));
|
||||
try!(write!(w, "</td></tr>"));
|
||||
|
||||
if !data.statements.is_empty() {
|
||||
try!(write!(w, r#"<tr><td align="left" balign="left">"#));
|
||||
for statement in &data.statements {
|
||||
try!(write!(w, "{}", dot::escape_html(&format!("{:?}", statement))));
|
||||
try!(write!(w, "<br/>"));
|
||||
}
|
||||
try!(write!(w, "</td></tr>"));
|
||||
}
|
||||
|
||||
try!(write!(w, r#"<tr><td align="left">"#));
|
||||
|
||||
let mut terminator_head = String::new();
|
||||
data.terminator.fmt_head(&mut terminator_head).unwrap();
|
||||
try!(write!(w, "{}", dot::escape_html(&terminator_head)));
|
||||
try!(write!(w, "</td></tr>"));
|
||||
|
||||
try!(write!(w, "</table>"));
|
||||
writeln!(w, ">];")
|
||||
}
|
||||
|
||||
fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
|
||||
let terminator = &mir.basic_block_data(source).terminator;
|
||||
let labels = terminator.fmt_successor_labels();
|
||||
|
||||
for (i, target) in terminator.successors().into_iter().enumerate() {
|
||||
try!(write!(w, "bb{} -> bb{}", source.index(), target.index()));
|
||||
try!(writeln!(w, r#" [label="{}"];"#, labels[i]));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_graph_label<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
|
||||
try!(write!(w, "label=<"));
|
||||
try!(write!(w, "fn("));
|
||||
|
||||
for (i, arg) in mir.arg_decls.iter().enumerate() {
|
||||
if i > 0 {
|
||||
try!(write!(w, ", "));
|
||||
}
|
||||
try!(write!(w, "{}", dot::escape_html(&format!("a{}: {:?}", i, arg.ty))));
|
||||
}
|
||||
|
||||
try!(write!(w, "{}", dot::escape_html(") -> ")));
|
||||
|
||||
match mir.return_ty {
|
||||
ty::FnOutput::FnConverging(ty) =>
|
||||
try!(write!(w, "{}", dot::escape_html(&format!("{:?}", ty)))),
|
||||
ty::FnOutput::FnDiverging =>
|
||||
try!(write!(w, "{}", dot::escape_html("!"))),
|
||||
}
|
||||
|
||||
try!(write!(w, r#"<br align="left"/>"#));
|
||||
|
||||
for (i, var) in mir.var_decls.iter().enumerate() {
|
||||
try!(write!(w, "let "));
|
||||
if var.mutability == Mutability::Mut {
|
||||
try!(write!(w, "mut "));
|
||||
}
|
||||
let text = format!("v{}: {:?}; // {}", i, var.ty, var.name);
|
||||
try!(write!(w, "{}", dot::escape_html(&text)));
|
||||
try!(write!(w, r#"<br align="left"/>"#));
|
||||
}
|
||||
|
||||
for (i, temp) in mir.temp_decls.iter().enumerate() {
|
||||
try!(write!(w, "{}", dot::escape_html(&format!("let t{}: {:?};", i, temp.ty))));
|
||||
try!(write!(w, r#"<br align="left"/>"#));
|
||||
}
|
||||
|
||||
writeln!(w, ">;")
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
use dot;
|
||||
use rustc::mir::repr::*;
|
||||
use std::borrow::IntoCow;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct EdgeIndex {
|
||||
source: BasicBlock,
|
||||
target: BasicBlock,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
|
||||
fn graph_id(&'a self) -> dot::Id<'a> {
|
||||
dot::Id::new("Mir").unwrap()
|
||||
}
|
||||
|
||||
fn node_id(&'a self, n: &BasicBlock) -> dot::Id<'a> {
|
||||
dot::Id::new(format!("BB{}", n.index())).unwrap()
|
||||
}
|
||||
|
||||
fn node_shape(&'a self, _: &BasicBlock) -> Option<dot::LabelText<'a>> {
|
||||
Some(dot::LabelText::label("none"))
|
||||
}
|
||||
|
||||
fn node_label(&'a self, &n: &BasicBlock) -> dot::LabelText<'a> {
|
||||
let mut buffer = String::new();
|
||||
buffer.push_str("<table border=\"0\" cellborder=\"1\" cellspacing=\"0\">");
|
||||
|
||||
buffer.push_str("<tr><td><b>");
|
||||
buffer.push_str(&escape(format!("{:?}", n)));
|
||||
buffer.push_str("</b></td></tr>");
|
||||
|
||||
let data = self.basic_block_data(n);
|
||||
for statement in &data.statements {
|
||||
buffer.push_str("<tr><td align=\"left\">");
|
||||
buffer.push_str(&escape(format!("{:?}", statement)));
|
||||
buffer.push_str("</td></tr>");
|
||||
}
|
||||
|
||||
buffer.push_str("<tr><td align=\"left\" bgcolor=\"cornsilk\">");
|
||||
buffer.push_str(&escape(format!("{:?}", &data.terminator)));
|
||||
buffer.push_str("</td></tr>");
|
||||
|
||||
buffer.push_str("</table>");
|
||||
|
||||
dot::LabelText::html(buffer)
|
||||
}
|
||||
|
||||
fn edge_label(&'a self, edge: &EdgeIndex) -> dot::LabelText<'a> {
|
||||
dot::LabelText::label(format!("{}", edge.index))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
|
||||
fn nodes(&'a self) -> dot::Nodes<'a, BasicBlock> {
|
||||
self.all_basic_blocks().into_cow()
|
||||
}
|
||||
|
||||
fn edges(&'a self) -> dot::Edges<'a, EdgeIndex> {
|
||||
self.all_basic_blocks()
|
||||
.into_iter()
|
||||
.flat_map(|source| {
|
||||
self.basic_block_data(source)
|
||||
.terminator
|
||||
.successors()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(move |(index, &target)| {
|
||||
EdgeIndex {
|
||||
source: source,
|
||||
target: target,
|
||||
index: index,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_cow()
|
||||
}
|
||||
|
||||
fn source(&'a self, edge: &EdgeIndex) -> BasicBlock {
|
||||
edge.source
|
||||
}
|
||||
|
||||
fn target(&'a self, edge: &EdgeIndex) -> BasicBlock {
|
||||
edge.target
|
||||
}
|
||||
}
|
||||
|
||||
fn escape(text: String) -> String {
|
||||
let text = dot::escape_html(&text);
|
||||
let text = all_to_subscript("Temp", text);
|
||||
let text = all_to_subscript("Var", text);
|
||||
let text = all_to_subscript("Arg", text);
|
||||
let text = all_to_subscript("BB", text);
|
||||
text
|
||||
}
|
||||
|
||||
/// A call like `all_to_subscript("Temp", "Temp(123)")` will convert
|
||||
/// to `Temp₁₂₃`.
|
||||
fn all_to_subscript(header: &str, mut text: String) -> String {
|
||||
let mut offset = 0;
|
||||
while offset < text.len() {
|
||||
if let Some(text1) = to_subscript1(header, &text, &mut offset) {
|
||||
text = text1;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
|
||||
/// Looks for `Foo(\d*)` where `header=="Foo"` and replaces the `\d` with subscripts.
|
||||
/// Updates `offset` to point to the next location where we might want to search.
|
||||
/// Returns an updated string if changes were made, else None.
|
||||
fn to_subscript1(header: &str, text: &str, offset: &mut usize) -> Option<String> {
|
||||
let a = match text[*offset..].find(header) {
|
||||
None => {
|
||||
*offset = text.len();
|
||||
return None;
|
||||
}
|
||||
Some(a) => a + *offset,
|
||||
};
|
||||
|
||||
// Example:
|
||||
//
|
||||
// header: "Foo"
|
||||
// text: ....Foo(123)...
|
||||
// ^ ^
|
||||
// a b
|
||||
|
||||
let b = a + header.len();
|
||||
*offset = b;
|
||||
|
||||
let mut chars = text[b..].chars();
|
||||
if Some('(') != chars.next() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut result = String::new();
|
||||
result.push_str(&text[..b]);
|
||||
|
||||
while let Some(c) = chars.next() {
|
||||
if c == ')' {
|
||||
break;
|
||||
}
|
||||
if !c.is_digit(10) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// 0x208 is _0 in unicode, 0x209 is _1, etc
|
||||
const SUBSCRIPTS: &'static str = "₀₁₂₃₄₅₆₇₈₉";
|
||||
let n = (c as usize) - ('0' as usize);
|
||||
result.extend(SUBSCRIPTS.chars().skip(n).take(1));
|
||||
}
|
||||
|
||||
result.extend(chars);
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
#![crate_type = "dylib"]
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(into_cow)]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
extern crate graphviz as dot;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ extern crate rustc;
|
|||
extern crate rustc_front;
|
||||
|
||||
use build;
|
||||
use dot;
|
||||
use graphviz;
|
||||
use transform::*;
|
||||
use rustc::mir::repr::Mir;
|
||||
use hair::cx::Cx;
|
||||
|
|
@ -157,7 +157,9 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
|
|||
Some(s) => {
|
||||
match
|
||||
File::create(format!("{}{}", prefix, s))
|
||||
.and_then(|ref mut output| dot::render(&mir, output))
|
||||
.and_then(|ref mut output| {
|
||||
graphviz::write_mir_graphviz(&mir, output)
|
||||
})
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(e) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue