]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/pretty.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_mir / pretty.rs
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
11 use build::{ScopeAuxiliaryVec, ScopeId};
12 use rustc::hir;
13 use rustc::hir::def_id::DefId;
14 use rustc::mir::repr::*;
15 use rustc::mir::mir_map::MirMap;
16 use rustc::mir::transform::MirSource;
17 use rustc::ty::TyCtxt;
18 use rustc_data_structures::fnv::FnvHashMap;
19 use rustc_data_structures::indexed_vec::{Idx};
20 use std::fmt::Display;
21 use std::fs;
22 use std::io::{self, Write};
23 use std::path::{PathBuf, Path};
24
25 const INDENT: &'static str = " ";
26 /// Alignment for lining up comments following MIR statements
27 const ALIGN: usize = 40;
28
29 /// If the session is properly configured, dumps a human-readable
30 /// representation of the mir into:
31 ///
32 /// ```text
33 /// rustc.node<node_id>.<pass_name>.<disambiguator>
34 /// ```
35 ///
36 /// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
37 /// where `<filter>` takes the following forms:
38 ///
39 /// - `all` -- dump MIR for all fns, all passes, all everything
40 /// - `substring1&substring2,...` -- `&`-separated list of substrings
41 /// that can appear in the pass-name or the `item_path_str` for the given
42 /// node-id. If any one of the substrings match, the data is dumped out.
43 pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
44 pass_name: &str,
45 disambiguator: &Display,
46 src: MirSource,
47 mir: &Mir<'tcx>,
48 auxiliary: Option<&ScopeAuxiliaryVec>) {
49 let filters = match tcx.sess.opts.debugging_opts.dump_mir {
50 None => return,
51 Some(ref filters) => filters,
52 };
53 let node_id = src.item_id();
54 let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
55 let is_matched =
56 filters.split("&")
57 .any(|filter| {
58 filter == "all" ||
59 pass_name.contains(filter) ||
60 node_path.contains(filter)
61 });
62 if !is_matched {
63 return;
64 }
65
66 let promotion_id = match src {
67 MirSource::Promoted(_, id) => format!("-{:?}", id),
68 _ => String::new()
69 };
70
71 let mut file_path = PathBuf::new();
72 if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
73 let p = Path::new(file_dir);
74 file_path.push(p);
75 };
76 let file_name = format!("rustc.node{}{}.{}.{}.mir",
77 node_id, promotion_id, pass_name, disambiguator);
78 file_path.push(&file_name);
79 let _ = fs::File::create(&file_path).and_then(|mut file| {
80 writeln!(file, "// MIR for `{}`", node_path)?;
81 writeln!(file, "// node_id = {}", node_id)?;
82 writeln!(file, "// pass_name = {}", pass_name)?;
83 writeln!(file, "// disambiguator = {}", disambiguator)?;
84 writeln!(file, "")?;
85 write_mir_fn(tcx, src, mir, &mut file, auxiliary)?;
86 Ok(())
87 });
88 }
89
90 /// Write out a human-readable textual representation for the given MIR.
91 pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
92 iter: I,
93 mir_map: &MirMap<'tcx>,
94 w: &mut Write)
95 -> io::Result<()>
96 where I: Iterator<Item=DefId>, 'tcx: 'a
97 {
98 let mut first = true;
99 for def_id in iter {
100 let mir = &mir_map.map[&def_id];
101
102 if first {
103 first = false;
104 } else {
105 // Put empty lines between all items
106 writeln!(w, "")?;
107 }
108
109 let id = tcx.map.as_local_node_id(def_id).unwrap();
110 let src = MirSource::from_node(tcx, id);
111 write_mir_fn(tcx, src, mir, w, None)?;
112
113 for (i, mir) in mir.promoted.iter_enumerated() {
114 writeln!(w, "")?;
115 write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
116 }
117 }
118 Ok(())
119 }
120
121 enum Annotation {
122 EnterScope(ScopeId),
123 ExitScope(ScopeId),
124 }
125
126 fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>)
127 -> FnvHashMap<Location, Vec<Annotation>>
128 {
129 // compute scope/entry exit annotations
130 let mut annotations = FnvHashMap();
131 if let Some(auxiliary) = auxiliary {
132 for (scope_id, auxiliary) in auxiliary.iter_enumerated() {
133 annotations.entry(auxiliary.dom)
134 .or_insert(vec![])
135 .push(Annotation::EnterScope(scope_id));
136
137 for &loc in &auxiliary.postdoms {
138 annotations.entry(loc)
139 .or_insert(vec![])
140 .push(Annotation::ExitScope(scope_id));
141 }
142 }
143 }
144 return annotations;
145 }
146
147 pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
148 src: MirSource,
149 mir: &Mir<'tcx>,
150 w: &mut Write,
151 auxiliary: Option<&ScopeAuxiliaryVec>)
152 -> io::Result<()> {
153 let annotations = scope_entry_exit_annotations(auxiliary);
154 write_mir_intro(tcx, src, mir, w)?;
155 for block in mir.basic_blocks().indices() {
156 write_basic_block(tcx, block, mir, w, &annotations)?;
157 if block.index() + 1 != mir.basic_blocks().len() {
158 writeln!(w, "")?;
159 }
160 }
161
162 writeln!(w, "}}")?;
163 Ok(())
164 }
165
166 /// Write out a human-readable textual representation for the given basic block.
167 fn write_basic_block(tcx: TyCtxt,
168 block: BasicBlock,
169 mir: &Mir,
170 w: &mut Write,
171 annotations: &FnvHashMap<Location, Vec<Annotation>>)
172 -> io::Result<()> {
173 let data = &mir[block];
174
175 // Basic block label at the top.
176 writeln!(w, "{}{:?}: {{", INDENT, block)?;
177
178 // List of statements in the middle.
179 let mut current_location = Location { block: block, statement_index: 0 };
180 for statement in &data.statements {
181 if let Some(ref annotations) = annotations.get(&current_location) {
182 for annotation in annotations.iter() {
183 match *annotation {
184 Annotation::EnterScope(id) =>
185 writeln!(w, "{0}{0}// Enter Scope({1})",
186 INDENT, id.index())?,
187 Annotation::ExitScope(id) =>
188 writeln!(w, "{0}{0}// Exit Scope({1})",
189 INDENT, id.index())?,
190 }
191 }
192 }
193
194 let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
195 writeln!(w, "{0:1$} // {2}",
196 indented_mir,
197 ALIGN,
198 comment(tcx, statement.source_info))?;
199
200 current_location.statement_index += 1;
201 }
202
203 // Terminator at the bottom.
204 let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
205 writeln!(w, "{0:1$} // {2}",
206 indented_terminator,
207 ALIGN,
208 comment(tcx, data.terminator().source_info))?;
209
210 writeln!(w, "{}}}", INDENT)
211 }
212
213 fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
214 format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
215 }
216
217 fn write_scope_tree(tcx: TyCtxt,
218 mir: &Mir,
219 scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
220 w: &mut Write,
221 parent: VisibilityScope,
222 depth: usize)
223 -> io::Result<()> {
224 let indent = depth * INDENT.len();
225
226 let children = match scope_tree.get(&parent) {
227 Some(childs) => childs,
228 None => return Ok(()),
229 };
230
231 for &child in children {
232 let data = &mir.visibility_scopes[child];
233 assert_eq!(data.parent_scope, Some(parent));
234 writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
235
236 // User variable types (including the user's name in a comment).
237 for (id, var) in mir.var_decls.iter_enumerated() {
238 // Skip if not declared in this scope.
239 if var.source_info.scope != child {
240 continue;
241 }
242
243 let mut_str = if var.mutability == Mutability::Mut {
244 "mut "
245 } else {
246 ""
247 };
248
249 let indent = indent + INDENT.len();
250 let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
251 INDENT,
252 indent,
253 mut_str,
254 id,
255 var.ty);
256 writeln!(w, "{0:1$} // \"{2}\" in {3}",
257 indented_var,
258 ALIGN,
259 var.name,
260 comment(tcx, var.source_info))?;
261 }
262
263 write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
264
265 writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
266 }
267
268 Ok(())
269 }
270
271 /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
272 /// local variables (both user-defined bindings and compiler temporaries).
273 fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
274 src: MirSource,
275 mir: &Mir,
276 w: &mut Write)
277 -> io::Result<()> {
278 write_mir_sig(tcx, src, mir, w)?;
279 writeln!(w, " {{")?;
280
281 // construct a scope tree and write it out
282 let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
283 for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
284 if let Some(parent) = scope_data.parent_scope {
285 scope_tree.entry(parent)
286 .or_insert(vec![])
287 .push(VisibilityScope::new(index));
288 } else {
289 // Only the argument scope has no parent, because it's the root.
290 assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
291 }
292 }
293
294 write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
295
296 write_mir_decls(mir, w)
297 }
298
299 fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
300 -> io::Result<()>
301 {
302 match src {
303 MirSource::Fn(_) => write!(w, "fn")?,
304 MirSource::Const(_) => write!(w, "const")?,
305 MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
306 MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
307 MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
308 }
309
310 write!(w, " {}", tcx.node_path_str(src.item_id()))?;
311
312 if let MirSource::Fn(_) = src {
313 write!(w, "(")?;
314
315 // fn argument types.
316 for (i, arg) in mir.arg_decls.iter_enumerated() {
317 if i.index() != 0 {
318 write!(w, ", ")?;
319 }
320 write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
321 }
322
323 write!(w, ") -> {}", mir.return_ty)
324 } else {
325 assert!(mir.arg_decls.is_empty());
326 write!(w, ": {} =", mir.return_ty)
327 }
328 }
329
330 fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
331 // Compiler-introduced temporary types.
332 for (id, temp) in mir.temp_decls.iter_enumerated() {
333 writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
334 }
335
336 // Wrote any declaration? Add an empty line before the first block is printed.
337 if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
338 writeln!(w, "")?;
339 }
340
341 Ok(())
342 }