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
::{MirSuite, MirPassIndex, MirSource}
;
15 use rustc
::ty
::TyCtxt
;
16 use rustc
::ty
::item_path
;
17 use rustc_data_structures
::fx
::FxHashMap
;
18 use rustc_data_structures
::indexed_vec
::{Idx}
;
19 use std
::fmt
::Display
;
21 use std
::io
::{self, Write}
;
22 use std
::path
::{PathBuf, Path}
;
24 const INDENT
: &'
static str = " ";
25 /// Alignment for lining up comments following MIR statements
26 const ALIGN
: usize = 40;
28 /// If the session is properly configured, dumps a human-readable
29 /// representation of the mir into:
32 /// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator>
35 /// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
36 /// where `<filter>` takes the following forms:
38 /// - `all` -- dump MIR for all fns, all passes, all everything
39 /// - `substring1&substring2,...` -- `&`-separated list of substrings
40 /// that can appear in the pass-name or the `item_path_str` for the given
41 /// node-id. If any one of the substrings match, the data is dumped out.
42 pub fn dump_mir
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
43 pass_num
: Option
<(MirSuite
, MirPassIndex
)>,
45 disambiguator
: &Display
,
48 if !dump_enabled(tcx
, pass_name
, source
) {
52 let node_path
= item_path
::with_forced_impl_filename_line(|| { // see notes on #41697 below
53 tcx
.item_path_str(tcx
.hir
.local_def_id(source
.item_id()))
55 dump_matched_mir_node(tcx
, pass_num
, pass_name
, &node_path
,
56 disambiguator
, source
, mir
);
57 for (index
, promoted_mir
) in mir
.promoted
.iter_enumerated() {
58 let promoted_source
= MirSource
::Promoted(source
.item_id(), index
);
59 dump_matched_mir_node(tcx
, pass_num
, pass_name
, &node_path
, disambiguator
,
60 promoted_source
, promoted_mir
);
64 pub fn dump_enabled
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
68 let filters
= match tcx
.sess
.opts
.debugging_opts
.dump_mir
{
70 Some(ref filters
) => filters
,
72 let node_id
= source
.item_id();
73 let node_path
= item_path
::with_forced_impl_filename_line(|| { // see notes on #41697 below
74 tcx
.item_path_str(tcx
.hir
.local_def_id(node_id
))
79 pass_name
.contains(filter
) ||
80 node_path
.contains(filter
)
84 // #41697 -- we use `with_forced_impl_filename_line()` because
85 // `item_path_str()` would otherwise trigger `type_of`, and this can
86 // run while we are already attempting to evaluate `type_of`.
88 fn dump_matched_mir_node
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
89 pass_num
: Option
<(MirSuite
, MirPassIndex
)>,
92 disambiguator
: &Display
,
95 let promotion_id
= match source
{
96 MirSource
::Promoted(_
, id
) => format
!("-{:?}", id
),
97 MirSource
::GeneratorDrop(_
) => format
!("-drop"),
101 let pass_num
= if tcx
.sess
.opts
.debugging_opts
.dump_mir_exclude_pass_number
{
105 None
=> format
!(".-------"),
106 Some((suite
, pass_num
)) => format
!(".{:03}-{:03}", suite
.0, pass_num
.0),
110 let mut file_path
= PathBuf
::new();
111 if let Some(ref file_dir
) = tcx
.sess
.opts
.debugging_opts
.dump_mir_dir
{
112 let p
= Path
::new(file_dir
);
115 let _
= fs
::create_dir_all(&file_path
);
116 let file_name
= format
!("rustc.node{}{}{}.{}.{}.mir",
117 source
.item_id(), promotion_id
, pass_num
, pass_name
, disambiguator
);
118 file_path
.push(&file_name
);
119 let _
= fs
::File
::create(&file_path
).and_then(|mut file
| {
120 writeln
!(file
, "// MIR for `{}`", node_path
)?
;
121 writeln
!(file
, "// source = {:?}", source
)?
;
122 writeln
!(file
, "// pass_name = {}", pass_name
)?
;
123 writeln
!(file
, "// disambiguator = {}", disambiguator
)?
;
124 if let Some(ref layout
) = mir
.generator_layout
{
125 writeln
!(file
, "// generator_layout = {:?}", layout
)?
;
128 write_mir_fn(tcx
, source
, mir
, &mut file
)?
;
133 /// Write out a human-readable textual representation for the given MIR.
134 pub fn write_mir_pretty
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
135 single
: Option
<DefId
>,
139 writeln
!(w
, "// WARNING: This output format is intended for human consumers only")?
;
140 writeln
!(w
, "// and is subject to change without notice. Knock yourself out.")?
;
142 let mut first
= true;
143 for def_id
in dump_mir_def_ids(tcx
, single
) {
144 let mir
= &tcx
.optimized_mir(def_id
);
149 // Put empty lines between all items
153 let id
= tcx
.hir
.as_local_node_id(def_id
).unwrap();
154 let src
= MirSource
::from_node(tcx
, id
);
155 write_mir_fn(tcx
, src
, mir
, w
)?
;
157 for (i
, mir
) in mir
.promoted
.iter_enumerated() {
159 write_mir_fn(tcx
, MirSource
::Promoted(id
, i
), mir
, w
)?
;
165 pub fn write_mir_fn
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
170 write_mir_intro(tcx
, src
, mir
, w
)?
;
171 for block
in mir
.basic_blocks().indices() {
172 write_basic_block(tcx
, block
, mir
, w
)?
;
173 if block
.index() + 1 != mir
.basic_blocks().len() {
182 /// Write out a human-readable textual representation for the given basic block.
183 pub fn write_basic_block(tcx
: TyCtxt
,
188 let data
= &mir
[block
];
190 // Basic block label at the top.
191 let cleanup_text
= if data
.is_cleanup { " // cleanup" }
else { "" }
;
192 let lbl
= format
!("{}{:?}: {{", INDENT
, block
);
193 writeln
!(w
, "{0:1$}{2}", lbl
, ALIGN
, cleanup_text
)?
;
195 // List of statements in the middle.
196 let mut current_location
= Location { block: block, statement_index: 0 }
;
197 for statement
in &data
.statements
{
198 let indented_mir
= format
!("{0}{0}{1:?};", INDENT
, statement
);
199 writeln
!(w
, "{0:1$} // {2}",
202 comment(tcx
, statement
.source_info
))?
;
204 current_location
.statement_index
+= 1;
207 // Terminator at the bottom.
208 let indented_terminator
= format
!("{0}{0}{1:?};", INDENT
, data
.terminator().kind
);
209 writeln
!(w
, "{0:1$} // {2}",
212 comment(tcx
, data
.terminator().source_info
))?
;
214 writeln
!(w
, "{}}}", INDENT
)
217 fn comment(tcx
: TyCtxt
, SourceInfo { span, scope }
: SourceInfo
) -> String
{
218 format
!("scope {} at {}", scope
.index(), tcx
.sess
.codemap().span_to_string(span
))
221 /// Prints user-defined variables in a scope tree.
223 /// Returns the total number of variables printed.
224 fn write_scope_tree(tcx
: TyCtxt
,
226 scope_tree
: &FxHashMap
<VisibilityScope
, Vec
<VisibilityScope
>>,
228 parent
: VisibilityScope
,
231 let indent
= depth
* INDENT
.len();
233 let children
= match scope_tree
.get(&parent
) {
234 Some(childs
) => childs
,
235 None
=> return Ok(()),
238 for &child
in children
{
239 let data
= &mir
.visibility_scopes
[child
];
240 assert_eq
!(data
.parent_scope
, Some(parent
));
241 writeln
!(w
, "{0:1$}scope {2} {{", "", indent
, child
.index())?
;
243 // User variable types (including the user's name in a comment).
244 for local
in mir
.vars_iter() {
245 let var
= &mir
.local_decls
[local
];
246 let (name
, source_info
) = if var
.source_info
.scope
== child
{
247 (var
.name
.unwrap(), var
.source_info
)
249 // Not a variable or not declared in this scope.
253 let mut_str
= if var
.mutability
== Mutability
::Mut
{
259 let indent
= indent
+ INDENT
.len();
260 let indented_var
= format
!("{0:1$}let {2}{3:?}: {4};",
266 writeln
!(w
, "{0:1$} // \"{2}\" in {3}",
270 comment(tcx
, source_info
))?
;
273 write_scope_tree(tcx
, mir
, scope_tree
, w
, child
, depth
+ 1)?
;
275 writeln
!(w
, "{0:1$}}}", "", depth
* INDENT
.len())?
;
281 /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
282 /// local variables (both user-defined bindings and compiler temporaries).
283 pub fn write_mir_intro
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
288 write_mir_sig(tcx
, src
, mir
, w
)?
;
291 // construct a scope tree and write it out
292 let mut scope_tree
: FxHashMap
<VisibilityScope
, Vec
<VisibilityScope
>> = FxHashMap();
293 for (index
, scope_data
) in mir
.visibility_scopes
.iter().enumerate() {
294 if let Some(parent
) = scope_data
.parent_scope
{
295 scope_tree
.entry(parent
)
297 .push(VisibilityScope
::new(index
));
299 // Only the argument scope has no parent, because it's the root.
300 assert_eq
!(index
, ARGUMENT_VISIBILITY_SCOPE
.index());
304 // Print return pointer
305 let indented_retptr
= format
!("{}let mut {:?}: {};",
309 writeln
!(w
, "{0:1$} // return pointer",
313 write_scope_tree(tcx
, mir
, &scope_tree
, w
, ARGUMENT_VISIBILITY_SCOPE
, 1)?
;
315 write_temp_decls(mir
, w
)?
;
317 // Add an empty line before the first block is printed.
323 fn write_mir_sig(tcx
: TyCtxt
, src
: MirSource
, mir
: &Mir
, w
: &mut Write
)
327 MirSource
::Fn(_
) => write
!(w
, "fn")?
,
328 MirSource
::Const(_
) => write
!(w
, "const")?
,
329 MirSource
::Static(_
, hir
::MutImmutable
) => write
!(w
, "static")?
,
330 MirSource
::Static(_
, hir
::MutMutable
) => write
!(w
, "static mut")?
,
331 MirSource
::Promoted(_
, i
) => write
!(w
, "{:?} in", i
)?
,
332 MirSource
::GeneratorDrop(_
) => write
!(w
, "drop_glue")?
,
335 item_path
::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere
336 write
!(w
, " {}", tcx
.node_path_str(src
.item_id()))
340 MirSource
::Fn(_
) | MirSource
::GeneratorDrop(_
) => {
343 // fn argument types.
344 for (i
, arg
) in mir
.args_iter().enumerate() {
348 write
!(w
, "{:?}: {}", Lvalue
::Local(arg
), mir
.local_decls
[arg
].ty
)?
;
351 write
!(w
, ") -> {}", mir
.return_ty
)
353 MirSource
::Const(..) |
354 MirSource
::Static(..) |
355 MirSource
::Promoted(..) => {
356 assert_eq
!(mir
.arg_count
, 0);
357 write
!(w
, ": {} =", mir
.return_ty
)
362 fn write_temp_decls(mir
: &Mir
, w
: &mut Write
) -> io
::Result
<()> {
363 // Compiler-introduced temporary types.
364 for temp
in mir
.temps_iter() {
365 writeln
!(w
, "{}let mut {:?}: {};", INDENT
, temp
, mir
.local_decls
[temp
].ty
)?
;
371 pub fn dump_mir_def_ids(tcx
: TyCtxt
, single
: Option
<DefId
>) -> Vec
<DefId
> {
372 if let Some(i
) = single
{
375 tcx
.mir_keys(LOCAL_CRATE
).iter().cloned().collect()