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
;
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_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
>,
43 disambiguator
: &Display
,
46 let filters
= match tcx
.sess
.opts
.debugging_opts
.dump_mir
{
48 Some(ref filters
) => filters
,
50 let node_id
= src
.item_id();
51 let node_path
= tcx
.item_path_str(tcx
.hir
.local_def_id(node_id
));
56 pass_name
.contains(filter
) ||
57 node_path
.contains(filter
)
63 let promotion_id
= match src
{
64 MirSource
::Promoted(_
, id
) => format
!("-{:?}", id
),
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
);
73 let file_name
= format
!("rustc.node{}{}.{}.{}.mir",
74 node_id
, promotion_id
, pass_name
, disambiguator
);
75 file_path
.push(&file_name
);
76 let _
= fs
::File
::create(&file_path
).and_then(|mut file
| {
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
)?
;
82 write_mir_fn(tcx
, src
, mir
, &mut file
)?
;
87 /// Write out a human-readable textual representation for the given MIR.
88 pub fn write_mir_pretty
<'a
, 'b
, 'tcx
, I
>(tcx
: TyCtxt
<'b
, 'tcx
, 'tcx
>,
92 where I
: Iterator
<Item
=DefId
>, 'tcx
: 'a
95 for def_id
in iter
.filter(DefId
::is_local
) {
96 let mir
= &tcx
.item_mir(def_id
);
101 // Put empty lines between all items
105 let id
= tcx
.hir
.as_local_node_id(def_id
).unwrap();
106 let src
= MirSource
::from_node(tcx
, id
);
107 write_mir_fn(tcx
, src
, mir
, w
)?
;
109 for (i
, mir
) in mir
.promoted
.iter_enumerated() {
111 write_mir_fn(tcx
, MirSource
::Promoted(id
, i
), mir
, w
)?
;
117 pub fn write_mir_fn
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
122 write_mir_intro(tcx
, src
, mir
, w
)?
;
123 for block
in mir
.basic_blocks().indices() {
124 write_basic_block(tcx
, block
, mir
, w
)?
;
125 if block
.index() + 1 != mir
.basic_blocks().len() {
134 /// Write out a human-readable textual representation for the given basic block.
135 fn write_basic_block(tcx
: TyCtxt
,
140 let data
= &mir
[block
];
142 // Basic block label at the top.
143 writeln
!(w
, "{}{:?}: {{", INDENT
, block
)?
;
145 // List of statements in the middle.
146 let mut current_location
= Location { block: block, statement_index: 0 }
;
147 for statement
in &data
.statements
{
148 let indented_mir
= format
!("{0}{0}{1:?};", INDENT
, statement
);
149 writeln
!(w
, "{0:1$} // {2}",
152 comment(tcx
, statement
.source_info
))?
;
154 current_location
.statement_index
+= 1;
157 // Terminator at the bottom.
158 let indented_terminator
= format
!("{0}{0}{1:?};", INDENT
, data
.terminator().kind
);
159 writeln
!(w
, "{0:1$} // {2}",
162 comment(tcx
, data
.terminator().source_info
))?
;
164 writeln
!(w
, "{}}}", INDENT
)
167 fn comment(tcx
: TyCtxt
, SourceInfo { span, scope }
: SourceInfo
) -> String
{
168 format
!("scope {} at {}", scope
.index(), tcx
.sess
.codemap().span_to_string(span
))
171 /// Prints user-defined variables in a scope tree.
173 /// Returns the total number of variables printed.
174 fn write_scope_tree(tcx
: TyCtxt
,
176 scope_tree
: &FxHashMap
<VisibilityScope
, Vec
<VisibilityScope
>>,
178 parent
: VisibilityScope
,
181 let indent
= depth
* INDENT
.len();
183 let children
= match scope_tree
.get(&parent
) {
184 Some(childs
) => childs
,
185 None
=> return Ok(()),
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())?
;
193 // User variable types (including the user's name in a comment).
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())
199 // Not a variable or not declared in this scope.
203 let mut_str
= if var
.mutability
== Mutability
::Mut
{
209 let indent
= indent
+ INDENT
.len();
210 let indented_var
= format
!("{0:1$}let {2}{3:?}: {4};",
216 writeln
!(w
, "{0:1$} // \"{2}\" in {3}",
220 comment(tcx
, source_info
))?
;
223 write_scope_tree(tcx
, mir
, scope_tree
, w
, child
, depth
+ 1)?
;
225 writeln
!(w
, "{0:1$}}}", "", depth
* INDENT
.len())?
;
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).
233 fn write_mir_intro
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
238 write_mir_sig(tcx
, src
, mir
, w
)?
;
241 // construct a scope tree and write it out
242 let mut scope_tree
: FxHashMap
<VisibilityScope
, Vec
<VisibilityScope
>> = FxHashMap();
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
)
247 .push(VisibilityScope
::new(index
));
249 // Only the argument scope has no parent, because it's the root.
250 assert_eq
!(index
, ARGUMENT_VISIBILITY_SCOPE
.index());
254 // Print return pointer
255 let indented_retptr
= format
!("{}let mut {:?}: {};",
259 writeln
!(w
, "{0:1$} // return pointer",
263 write_scope_tree(tcx
, mir
, &scope_tree
, w
, ARGUMENT_VISIBILITY_SCOPE
, 1)?
;
265 write_temp_decls(mir
, w
)?
;
267 // Add an empty line before the first block is printed.
273 fn write_mir_sig(tcx
: TyCtxt
, src
: MirSource
, mir
: &Mir
, w
: &mut Write
)
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")?
,
281 MirSource
::Promoted(_
, i
) => write
!(w
, "{:?} in", i
)?
284 write
!(w
, " {}", tcx
.node_path_str(src
.item_id()))?
;
286 if let MirSource
::Fn(_
) = src
{
289 // fn argument types.
290 for (i
, arg
) in mir
.args_iter().enumerate() {
294 write
!(w
, "{:?}: {}", Lvalue
::Local(arg
), mir
.local_decls
[arg
].ty
)?
;
297 write
!(w
, ") -> {}", mir
.return_ty
)
299 assert_eq
!(mir
.arg_count
, 0);
300 write
!(w
, ": {} =", mir
.return_ty
)
304 fn write_temp_decls(mir
: &Mir
, w
: &mut Write
) -> io
::Result
<()> {
305 // Compiler-introduced temporary types.
306 for temp
in mir
.temps_iter() {
307 writeln
!(w
, "{}let mut {:?}: {};", INDENT
, temp
, mir
.local_decls
[temp
].ty
)?
;