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.
11 use build
::{ScopeAuxiliaryVec, ScopeId}
;
13 use rustc
::hir
::def_id
::DefId
;
14 use rustc
::mir
::repr
::*;
15 use rustc
::mir
::mir_map
::MirMap
;
16 use rustc
::mir
::transform
::MirSource
;
17 use rustc
::ty
::TyCtxt
;
18 use rustc_data_structures
::fnv
::FnvHashMap
;
19 use rustc_data_structures
::indexed_vec
::{Idx}
;
20 use std
::fmt
::Display
;
22 use std
::io
::{self, Write}
;
23 use std
::path
::{PathBuf, Path}
;
25 const INDENT
: &'
static str = " ";
26 /// Alignment for lining up comments following MIR statements
27 const ALIGN
: usize = 40;
29 /// If the session is properly configured, dumps a human-readable
30 /// representation of the mir into:
33 /// rustc.node<node_id>.<pass_name>.<disambiguator>
36 /// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
37 /// where `<filter>` takes the following forms:
39 /// - `all` -- dump MIR for all fns, all passes, all everything
40 /// - `substring1&substring2,...` -- `&`-separated list of substrings
41 /// that can appear in the pass-name or the `item_path_str` for the given
42 /// node-id. If any one of the substrings match, the data is dumped out.
43 pub fn dump_mir
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
45 disambiguator
: &Display
,
48 auxiliary
: Option
<&ScopeAuxiliaryVec
>) {
49 let filters
= match tcx
.sess
.opts
.debugging_opts
.dump_mir
{
51 Some(ref filters
) => filters
,
53 let node_id
= src
.item_id();
54 let node_path
= tcx
.item_path_str(tcx
.map
.local_def_id(node_id
));
59 pass_name
.contains(filter
) ||
60 node_path
.contains(filter
)
66 let promotion_id
= match src
{
67 MirSource
::Promoted(_
, id
) => format
!("-{:?}", id
),
71 let mut file_path
= PathBuf
::new();
72 if let Some(ref file_dir
) = tcx
.sess
.opts
.debugging_opts
.dump_mir_dir
{
73 let p
= Path
::new(file_dir
);
76 let file_name
= format
!("rustc.node{}{}.{}.{}.mir",
77 node_id
, promotion_id
, pass_name
, disambiguator
);
78 file_path
.push(&file_name
);
79 let _
= fs
::File
::create(&file_path
).and_then(|mut file
| {
80 writeln
!(file
, "// MIR for `{}`", node_path
)?
;
81 writeln
!(file
, "// node_id = {}", node_id
)?
;
82 writeln
!(file
, "// pass_name = {}", pass_name
)?
;
83 writeln
!(file
, "// disambiguator = {}", disambiguator
)?
;
85 write_mir_fn(tcx
, src
, mir
, &mut file
, auxiliary
)?
;
90 /// Write out a human-readable textual representation for the given MIR.
91 pub fn write_mir_pretty
<'a
, 'b
, 'tcx
, I
>(tcx
: TyCtxt
<'b
, 'tcx
, 'tcx
>,
93 mir_map
: &MirMap
<'tcx
>,
96 where I
: Iterator
<Item
=DefId
>, 'tcx
: 'a
100 let mir
= &mir_map
.map
[&def_id
];
105 // Put empty lines between all items
109 let id
= tcx
.map
.as_local_node_id(def_id
).unwrap();
110 let src
= MirSource
::from_node(tcx
, id
);
111 write_mir_fn(tcx
, src
, mir
, w
, None
)?
;
113 for (i
, mir
) in mir
.promoted
.iter_enumerated() {
115 write_mir_fn(tcx
, MirSource
::Promoted(id
, i
), mir
, w
, None
)?
;
126 fn scope_entry_exit_annotations(auxiliary
: Option
<&ScopeAuxiliaryVec
>)
127 -> FnvHashMap
<Location
, Vec
<Annotation
>>
129 // compute scope/entry exit annotations
130 let mut annotations
= FnvHashMap();
131 if let Some(auxiliary
) = auxiliary
{
132 for (scope_id
, auxiliary
) in auxiliary
.iter_enumerated() {
133 annotations
.entry(auxiliary
.dom
)
135 .push(Annotation
::EnterScope(scope_id
));
137 for &loc
in &auxiliary
.postdoms
{
138 annotations
.entry(loc
)
140 .push(Annotation
::ExitScope(scope_id
));
147 pub fn write_mir_fn
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
151 auxiliary
: Option
<&ScopeAuxiliaryVec
>)
153 let annotations
= scope_entry_exit_annotations(auxiliary
);
154 write_mir_intro(tcx
, src
, mir
, w
)?
;
155 for block
in mir
.basic_blocks().indices() {
156 write_basic_block(tcx
, block
, mir
, w
, &annotations
)?
;
157 if block
.index() + 1 != mir
.basic_blocks().len() {
166 /// Write out a human-readable textual representation for the given basic block.
167 fn write_basic_block(tcx
: TyCtxt
,
171 annotations
: &FnvHashMap
<Location
, Vec
<Annotation
>>)
173 let data
= &mir
[block
];
175 // Basic block label at the top.
176 writeln
!(w
, "{}{:?}: {{", INDENT
, block
)?
;
178 // List of statements in the middle.
179 let mut current_location
= Location { block: block, statement_index: 0 }
;
180 for statement
in &data
.statements
{
181 if let Some(ref annotations
) = annotations
.get(¤t_location
) {
182 for annotation
in annotations
.iter() {
184 Annotation
::EnterScope(id
) =>
185 writeln
!(w
, "{0}{0}// Enter Scope({1})",
186 INDENT
, id
.index())?
,
187 Annotation
::ExitScope(id
) =>
188 writeln
!(w
, "{0}{0}// Exit Scope({1})",
189 INDENT
, id
.index())?
,
194 let indented_mir
= format
!("{0}{0}{1:?};", INDENT
, statement
);
195 writeln
!(w
, "{0:1$} // {2}",
198 comment(tcx
, statement
.source_info
))?
;
200 current_location
.statement_index
+= 1;
203 // Terminator at the bottom.
204 let indented_terminator
= format
!("{0}{0}{1:?};", INDENT
, data
.terminator().kind
);
205 writeln
!(w
, "{0:1$} // {2}",
208 comment(tcx
, data
.terminator().source_info
))?
;
210 writeln
!(w
, "{}}}", INDENT
)
213 fn comment(tcx
: TyCtxt
, SourceInfo { span, scope }
: SourceInfo
) -> String
{
214 format
!("scope {} at {}", scope
.index(), tcx
.sess
.codemap().span_to_string(span
))
217 fn write_scope_tree(tcx
: TyCtxt
,
219 scope_tree
: &FnvHashMap
<VisibilityScope
, Vec
<VisibilityScope
>>,
221 parent
: VisibilityScope
,
224 let indent
= depth
* INDENT
.len();
226 let children
= match scope_tree
.get(&parent
) {
227 Some(childs
) => childs
,
228 None
=> return Ok(()),
231 for &child
in children
{
232 let data
= &mir
.visibility_scopes
[child
];
233 assert_eq
!(data
.parent_scope
, Some(parent
));
234 writeln
!(w
, "{0:1$}scope {2} {{", "", indent
, child
.index())?
;
236 // User variable types (including the user's name in a comment).
237 for (id
, var
) in mir
.var_decls
.iter_enumerated() {
238 // Skip if not declared in this scope.
239 if var
.source_info
.scope
!= child
{
243 let mut_str
= if var
.mutability
== Mutability
::Mut
{
249 let indent
= indent
+ INDENT
.len();
250 let indented_var
= format
!("{0:1$}let {2}{3:?}: {4};",
256 writeln
!(w
, "{0:1$} // \"{2}\" in {3}",
260 comment(tcx
, var
.source_info
))?
;
263 write_scope_tree(tcx
, mir
, scope_tree
, w
, child
, depth
+ 1)?
;
265 writeln
!(w
, "{0:1$}}}", "", depth
* INDENT
.len())?
;
271 /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
272 /// local variables (both user-defined bindings and compiler temporaries).
273 fn write_mir_intro
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
278 write_mir_sig(tcx
, src
, mir
, w
)?
;
281 // construct a scope tree and write it out
282 let mut scope_tree
: FnvHashMap
<VisibilityScope
, Vec
<VisibilityScope
>> = FnvHashMap();
283 for (index
, scope_data
) in mir
.visibility_scopes
.iter().enumerate() {
284 if let Some(parent
) = scope_data
.parent_scope
{
285 scope_tree
.entry(parent
)
287 .push(VisibilityScope
::new(index
));
289 // Only the argument scope has no parent, because it's the root.
290 assert_eq
!(index
, ARGUMENT_VISIBILITY_SCOPE
.index());
294 write_scope_tree(tcx
, mir
, &scope_tree
, w
, ARGUMENT_VISIBILITY_SCOPE
, 1)?
;
296 write_mir_decls(mir
, w
)
299 fn write_mir_sig(tcx
: TyCtxt
, src
: MirSource
, mir
: &Mir
, w
: &mut Write
)
303 MirSource
::Fn(_
) => write
!(w
, "fn")?
,
304 MirSource
::Const(_
) => write
!(w
, "const")?
,
305 MirSource
::Static(_
, hir
::MutImmutable
) => write
!(w
, "static")?
,
306 MirSource
::Static(_
, hir
::MutMutable
) => write
!(w
, "static mut")?
,
307 MirSource
::Promoted(_
, i
) => write
!(w
, "{:?} in", i
)?
310 write
!(w
, " {}", tcx
.node_path_str(src
.item_id()))?
;
312 if let MirSource
::Fn(_
) = src
{
315 // fn argument types.
316 for (i
, arg
) in mir
.arg_decls
.iter_enumerated() {
320 write
!(w
, "{:?}: {}", Lvalue
::Arg(i
), arg
.ty
)?
;
323 write
!(w
, ") -> {}", mir
.return_ty
)
325 assert
!(mir
.arg_decls
.is_empty());
326 write
!(w
, ": {} =", mir
.return_ty
)
330 fn write_mir_decls(mir
: &Mir
, w
: &mut Write
) -> io
::Result
<()> {
331 // Compiler-introduced temporary types.
332 for (id
, temp
) in mir
.temp_decls
.iter_enumerated() {
333 writeln
!(w
, "{}let mut {:?}: {};", INDENT
, id
, temp
.ty
)?
;
336 // Wrote any declaration? Add an empty line before the first block is printed.
337 if !mir
.var_decls
.is_empty() || !mir
.temp_decls
.is_empty() {