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