]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/pretty.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_mir / pretty.rs
CommitLineData
9cc50fc6
SL
1// Copyright 2014 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.
4//
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.
10
54a0048b 11use build::{Location, ScopeAuxiliaryVec};
9cc50fc6 12use rustc::mir::repr::*;
54a0048b
SL
13use rustc::ty::{self, TyCtxt};
14use rustc_data_structures::fnv::FnvHashMap;
15use std::fmt::Display;
16use std::fs;
9cc50fc6 17use std::io::{self, Write};
54a0048b
SL
18use syntax::ast::NodeId;
19use syntax::codemap::Span;
9cc50fc6
SL
20
21const INDENT: &'static str = " ";
22
54a0048b
SL
23/// If the session is properly configured, dumps a human-readable
24/// representation of the mir into:
25///
26/// ```
27/// rustc.node<node_id>.<pass_name>.<disambiguator>
28/// ```
29///
30/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
31/// where `<filter>` takes the following forms:
32///
33/// - `all` -- dump MIR for all fns, all passes, all everything
34/// - `substring1&substring2,...` -- `&`-separated list of substrings
35/// that can appear in the pass-name or the `item_path_str` for the given
36/// node-id. If any one of the substrings match, the data is dumped out.
37pub fn dump_mir<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
38 pass_name: &str,
39 disambiguator: &Display,
40 node_id: NodeId,
41 mir: &Mir<'tcx>,
42 auxiliary: Option<&ScopeAuxiliaryVec>) {
43 let filters = match tcx.sess.opts.debugging_opts.dump_mir {
44 None => return,
45 Some(ref filters) => filters,
46 };
47 let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
48 let is_matched =
49 filters.split("&")
50 .any(|filter| {
51 filter == "all" ||
52 pass_name.contains(filter) ||
53 node_path.contains(filter)
54 });
55 if !is_matched {
56 return;
57 }
58
59 let file_name = format!("rustc.node{}.{}.{}.mir",
60 node_id, pass_name, disambiguator);
61 let _ = fs::File::create(&file_name).and_then(|mut file| {
62 try!(writeln!(file, "// MIR for `{}`", node_path));
63 try!(writeln!(file, "// node_id = {}", node_id));
64 try!(writeln!(file, "// pass_name = {}", pass_name));
65 try!(writeln!(file, "// disambiguator = {}", disambiguator));
66 try!(writeln!(file, ""));
67 try!(write_mir_fn(tcx, node_id, mir, &mut file, auxiliary));
68 Ok(())
69 });
70}
71
9cc50fc6 72/// Write out a human-readable textual representation for the given MIR.
54a0048b
SL
73pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &TyCtxt<'tcx>,
74 iter: I,
75 w: &mut Write)
76 -> io::Result<()>
77 where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
78{
79 for (&node_id, mir) in iter {
80 write_mir_fn(tcx, node_id, mir, w, None)?;
81 }
82 Ok(())
83}
9cc50fc6 84
54a0048b
SL
85enum Annotation {
86 EnterScope(ScopeId),
87 ExitScope(ScopeId),
88}
89
90pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
91 node_id: NodeId,
92 mir: &Mir<'tcx>,
93 w: &mut Write,
94 auxiliary: Option<&ScopeAuxiliaryVec>)
95 -> io::Result<()> {
96 // compute scope/entry exit annotations
97 let mut annotations = FnvHashMap();
98 if let Some(auxiliary) = auxiliary {
99 for (index, auxiliary) in auxiliary.vec.iter().enumerate() {
100 let scope_id = ScopeId::new(index);
101
102 annotations.entry(auxiliary.dom)
103 .or_insert(vec![])
104 .push(Annotation::EnterScope(scope_id));
105
106 for &loc in &auxiliary.postdoms {
107 annotations.entry(loc)
108 .or_insert(vec![])
109 .push(Annotation::ExitScope(scope_id));
110 }
111 }
112 }
113
114 write_mir_intro(tcx, node_id, mir, w)?;
9cc50fc6 115 for block in mir.all_basic_blocks() {
54a0048b
SL
116 write_basic_block(tcx, block, mir, w, &annotations)?;
117 }
118
119 // construct a scope tree and write it out
120 let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
121 for (index, scope_data) in mir.scopes.iter().enumerate() {
122 scope_tree.entry(scope_data.parent_scope)
123 .or_insert(vec![])
124 .push(ScopeId::new(index));
9cc50fc6 125 }
54a0048b 126 write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1)?;
9cc50fc6 127
54a0048b
SL
128 writeln!(w, "}}")?;
129 Ok(())
9cc50fc6
SL
130}
131
132/// Write out a human-readable textual representation for the given basic block.
54a0048b
SL
133fn write_basic_block(tcx: &TyCtxt,
134 block: BasicBlock,
135 mir: &Mir,
136 w: &mut Write,
137 annotations: &FnvHashMap<Location, Vec<Annotation>>)
138 -> io::Result<()> {
9cc50fc6
SL
139 let data = mir.basic_block_data(block);
140
141 // Basic block label at the top.
54a0048b 142 writeln!(w, "\n{}{:?}: {{", INDENT, block)?;
9cc50fc6
SL
143
144 // List of statements in the middle.
54a0048b 145 let mut current_location = Location { block: block, statement_index: 0 };
9cc50fc6 146 for statement in &data.statements {
54a0048b
SL
147 if let Some(ref annotations) = annotations.get(&current_location) {
148 for annotation in annotations.iter() {
149 match *annotation {
150 Annotation::EnterScope(id) =>
151 writeln!(w, "{0}{0}// Enter Scope({1})",
152 INDENT, id.index())?,
153 Annotation::ExitScope(id) =>
154 writeln!(w, "{0}{0}// Exit Scope({1})",
155 INDENT, id.index())?,
156 }
157 }
158 }
159
160 writeln!(w, "{0}{0}{1:?}; // {2}",
161 INDENT,
162 statement,
163 comment(tcx, statement.scope, statement.span))?;
164
165 current_location.statement_index += 1;
9cc50fc6
SL
166 }
167
168 // Terminator at the bottom.
54a0048b
SL
169 writeln!(w, "{0}{0}{1:?}; // {2}",
170 INDENT,
171 data.terminator().kind,
172 comment(tcx, data.terminator().scope, data.terminator().span))?;
9cc50fc6
SL
173
174 writeln!(w, "{}}}", INDENT)
175}
176
54a0048b
SL
177fn comment(tcx: &TyCtxt,
178 scope: ScopeId,
179 span: Span)
180 -> String {
181 format!("Scope({}) at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
182}
183
184fn write_scope_tree(tcx: &TyCtxt,
185 mir: &Mir,
186 auxiliary: Option<&ScopeAuxiliaryVec>,
187 scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>,
188 w: &mut Write,
189 parent: Option<ScopeId>,
190 depth: usize)
191 -> io::Result<()> {
192 for &child in scope_tree.get(&parent).unwrap_or(&vec![]) {
193 let indent = depth * INDENT.len();
194 let data = &mir.scopes[child];
195 assert_eq!(data.parent_scope, parent);
196 writeln!(w, "{0:1$}Scope({2}) {{", "", indent, child.index())?;
197
198 let indent = indent + INDENT.len();
199 if let Some(parent) = parent {
200 writeln!(w, "{0:1$}Parent: Scope({2})", "", indent, parent.index())?;
201 }
202
203 if let Some(auxiliary) = auxiliary {
204 let extent = auxiliary[child].extent;
205 let data = tcx.region_maps.code_extent_data(extent);
206 writeln!(w, "{0:1$}Extent: {2:?}", "", indent, data)?;
207 }
208
209 write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
210 Some(child), depth + 1)?;
211 }
212 Ok(())
213}
214
9cc50fc6
SL
215/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
216/// local variables (both user-defined bindings and compiler temporaries).
54a0048b
SL
217fn write_mir_intro(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
218 -> io::Result<()> {
219 write!(w, "fn {}(", tcx.node_path_str(nid))?;
9cc50fc6
SL
220
221 // fn argument types.
222 for (i, arg) in mir.arg_decls.iter().enumerate() {
223 if i > 0 {
54a0048b 224 write!(w, ", ")?;
9cc50fc6 225 }
54a0048b 226 write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
9cc50fc6
SL
227 }
228
54a0048b 229 write!(w, ") -> ")?;
9cc50fc6
SL
230
231 // fn return type.
232 match mir.return_ty {
54a0048b
SL
233 ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
234 ty::FnOutput::FnDiverging => write!(w, "!")?,
9cc50fc6
SL
235 }
236
54a0048b 237 writeln!(w, " {{")?;
9cc50fc6
SL
238
239 // User variable types (including the user's name in a comment).
240 for (i, var) in mir.var_decls.iter().enumerate() {
54a0048b 241 write!(w, "{}let ", INDENT)?;
9cc50fc6 242 if var.mutability == Mutability::Mut {
54a0048b 243 write!(w, "mut ")?;
9cc50fc6 244 }
54a0048b 245 writeln!(w, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name)?;
9cc50fc6
SL
246 }
247
248 // Compiler-introduced temporary types.
249 for (i, temp) in mir.temp_decls.iter().enumerate() {
54a0048b 250 writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;
9cc50fc6
SL
251 }
252
253 Ok(())
254}