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