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.
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.
12 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
14 use rustc::mir::transform::MirSource;
15 use rustc::ty::TyCtxt;
16 use rustc_data_structures::fx::FxHashMap;
17 use rustc_data_structures::indexed_vec::{Idx};
18 use std::fmt::Display;
20 use std::io::{self, Write};
21 use std::path::{PathBuf, Path};
23 const INDENT: &'static str = " ";
24 /// Alignment for lining up comments following MIR statements
25 const ALIGN: usize = 40;
27 /// If the session is properly configured, dumps a human-readable
28 /// representation of the mir into:
31 /// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator>
34 /// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
35 /// where `<filter>` takes the following forms:
37 /// - `all` -- dump MIR for all fns, all passes, all everything
38 /// - `substring1&substring2,...` -- `&`-separated list of substrings
39 /// that can appear in the pass-name or the `item_path_str` for the given
40 /// node-id. If any one of the substrings match, the data is dumped out.
41 pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
44 disambiguator: &Display,
47 let filters = match tcx.sess.opts.debugging_opts.dump_mir {
49 Some(ref filters) => filters,
51 let node_id = source.item_id();
52 let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
57 pass_name.contains(filter) ||
58 node_path.contains(filter)
64 dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator, source, mir);
65 for (index, promoted_mir) in mir.promoted.iter_enumerated() {
66 let promoted_source = MirSource::Promoted(source.item_id(), index);
67 dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator,
68 promoted_source, promoted_mir);
72 fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
76 disambiguator: &Display,
79 let promotion_id = match source {
80 MirSource::Promoted(_, id) => format!("-{:?}", id),
84 let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number {
87 format!(".{:03}", pass_num)
90 let mut file_path = PathBuf::new();
91 if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
92 let p = Path::new(file_dir);
95 let file_name = format!("rustc.node{}{}{}.{}.{}.mir",
96 source.item_id(), promotion_id, pass_num, pass_name, disambiguator);
97 file_path.push(&file_name);
98 let _ = fs::File::create(&file_path).and_then(|mut file| {
99 writeln!(file, "// MIR for `{}`", node_path)?;
100 writeln!(file, "// source = {:?}", source)?;
101 writeln!(file, "// pass_name = {}", pass_name)?;
102 writeln!(file, "// disambiguator = {}", disambiguator)?;
104 write_mir_fn(tcx, source, mir, &mut file)?;
109 /// Write out a human-readable textual representation for the given MIR.
110 pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
111 single: Option<DefId>,
115 writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
116 writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;
118 let mut first = true;
119 for def_id in dump_mir_def_ids(tcx, single) {
120 let mir = &tcx.item_mir(def_id);
125 // Put empty lines between all items
129 let id = tcx.hir.as_local_node_id(def_id).unwrap();
130 let src = MirSource::from_node(tcx, id);
131 write_mir_fn(tcx, src, mir, w)?;
133 for (i, mir) in mir.promoted.iter_enumerated() {
135 write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?;
141 pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
146 write_mir_intro(tcx, src, mir, w)?;
147 for block in mir.basic_blocks().indices() {
148 write_basic_block(tcx, block, mir, w)?;
149 if block.index() + 1 != mir.basic_blocks().len() {
158 /// Write out a human-readable textual representation for the given basic block.
159 fn write_basic_block(tcx: TyCtxt,
164 let data = &mir[block];
166 // Basic block label at the top.
167 writeln!(w, "{}{:?}: {{", INDENT, block)?;
169 // List of statements in the middle.
170 let mut current_location = Location { block: block, statement_index: 0 };
171 for statement in &data.statements {
172 let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
173 writeln!(w, "{0:1$} // {2}",
176 comment(tcx, statement.source_info))?;
178 current_location.statement_index += 1;
181 // Terminator at the bottom.
182 let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
183 writeln!(w, "{0:1$} // {2}",
186 comment(tcx, data.terminator().source_info))?;
188 writeln!(w, "{}}}", INDENT)
191 fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
192 format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
195 /// Prints user-defined variables in a scope tree.
197 /// Returns the total number of variables printed.
198 fn write_scope_tree(tcx: TyCtxt,
200 scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>,
202 parent: VisibilityScope,
205 let indent = depth * INDENT.len();
207 let children = match scope_tree.get(&parent) {
208 Some(childs) => childs,
209 None => return Ok(()),
212 for &child in children {
213 let data = &mir.visibility_scopes[child];
214 assert_eq!(data.parent_scope, Some(parent));
215 writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
217 // User variable types (including the user's name in a comment).
218 for local in mir.vars_iter() {
219 let var = &mir.local_decls[local];
220 let (name, source_info) = if var.source_info.scope == child {
221 (var.name.unwrap(), var.source_info)
223 // Not a variable or not declared in this scope.
227 let mut_str = if var.mutability == Mutability::Mut {
233 let indent = indent + INDENT.len();
234 let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
240 writeln!(w, "{0:1$} // \"{2}\" in {3}",
244 comment(tcx, source_info))?;
247 write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
249 writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
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>,
262 write_mir_sig(tcx, src, mir, w)?;
265 // construct a scope tree and write it out
266 let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap();
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)
271 .push(VisibilityScope::new(index));
273 // Only the argument scope has no parent, because it's the root.
274 assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
278 // Print return pointer
279 let indented_retptr = format!("{}let mut {:?}: {};",
283 writeln!(w, "{0:1$} // return pointer",
287 write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
289 write_temp_decls(mir, w)?;
291 // Add an empty line before the first block is printed.
297 fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
301 MirSource::Fn(_) => write!(w, "fn")?,
302 MirSource::Const(_) => write!(w, "const")?,
303 MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
304 MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
305 MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
308 write!(w, " {}", tcx.node_path_str(src.item_id()))?;
310 if let MirSource::Fn(_) = src {
313 // fn argument types.
314 for (i, arg) in mir.args_iter().enumerate() {
318 write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
321 write!(w, ") -> {}", mir.return_ty)
323 assert_eq!(mir.arg_count, 0);
324 write!(w, ": {} =", mir.return_ty)
328 fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
329 // Compiler-introduced temporary types.
330 for temp in mir.temps_iter() {
331 writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
337 pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option<DefId>) -> Vec<DefId> {
338 if let Some(i) = single {
341 tcx.mir_keys(LOCAL_CRATE).iter().cloned().collect()