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
::{Location, ScopeAuxiliaryVec}
;
12 use rustc
::mir
::repr
::*;
13 use rustc
::ty
::{self, TyCtxt}
;
14 use rustc_data_structures
::fnv
::FnvHashMap
;
15 use std
::fmt
::Display
;
17 use std
::io
::{self, Write}
;
18 use syntax
::ast
::NodeId
;
19 use syntax
::codemap
::Span
;
21 const INDENT
: &'
static str = " ";
23 /// If the session is properly configured, dumps a human-readable
24 /// representation of the mir into:
27 /// rustc.node<node_id>.<pass_name>.<disambiguator>
30 /// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
31 /// where `<filter>` takes the following forms:
33 /// - `all` -- dump MIR for all fns, all passes, all everything
34 /// - `substring1&substring2,...` -- `&`-separated list of substrings
35 /// that can appear in the pass-name or the `item_path_str` for the given
36 /// node-id. If any one of the substrings match, the data is dumped out.
37 pub fn dump_mir
<'a
, 'tcx
>(tcx
: &TyCtxt
<'tcx
>,
39 disambiguator
: &Display
,
42 auxiliary
: Option
<&ScopeAuxiliaryVec
>) {
43 let filters
= match tcx
.sess
.opts
.debugging_opts
.dump_mir
{
45 Some(ref filters
) => filters
,
47 let node_path
= tcx
.item_path_str(tcx
.map
.local_def_id(node_id
));
52 pass_name
.contains(filter
) ||
53 node_path
.contains(filter
)
59 let file_name
= format
!("rustc.node{}.{}.{}.mir",
60 node_id
, pass_name
, disambiguator
);
61 let _
= fs
::File
::create(&file_name
).and_then(|mut file
| {
62 try
!(writeln
!(file
, "// MIR for `{}`", node_path
));
63 try
!(writeln
!(file
, "// node_id = {}", node_id
));
64 try
!(writeln
!(file
, "// pass_name = {}", pass_name
));
65 try
!(writeln
!(file
, "// disambiguator = {}", disambiguator
));
66 try
!(writeln
!(file
, ""));
67 try
!(write_mir_fn(tcx
, node_id
, mir
, &mut file
, auxiliary
));
72 /// Write out a human-readable textual representation for the given MIR.
73 pub fn write_mir_pretty
<'a
, 'tcx
, I
>(tcx
: &TyCtxt
<'tcx
>,
77 where I
: Iterator
<Item
=(&'a NodeId
, &'a Mir
<'tcx
>)>, 'tcx
: 'a
79 for (&node_id
, mir
) in iter
{
80 write_mir_fn(tcx
, node_id
, mir
, w
, None
)?
;
90 pub fn write_mir_fn
<'tcx
>(tcx
: &TyCtxt
<'tcx
>,
94 auxiliary
: Option
<&ScopeAuxiliaryVec
>)
96 // compute scope/entry exit annotations
97 let mut annotations
= FnvHashMap();
98 if let Some(auxiliary
) = auxiliary
{
99 for (index
, auxiliary
) in auxiliary
.vec
.iter().enumerate() {
100 let scope_id
= ScopeId
::new(index
);
102 annotations
.entry(auxiliary
.dom
)
104 .push(Annotation
::EnterScope(scope_id
));
106 for &loc
in &auxiliary
.postdoms
{
107 annotations
.entry(loc
)
109 .push(Annotation
::ExitScope(scope_id
));
114 write_mir_intro(tcx
, node_id
, mir
, w
)?
;
115 for block
in mir
.all_basic_blocks() {
116 write_basic_block(tcx
, block
, mir
, w
, &annotations
)?
;
119 // construct a scope tree and write it out
120 let mut scope_tree
: FnvHashMap
<Option
<ScopeId
>, Vec
<ScopeId
>> = FnvHashMap();
121 for (index
, scope_data
) in mir
.scopes
.iter().enumerate() {
122 scope_tree
.entry(scope_data
.parent_scope
)
124 .push(ScopeId
::new(index
));
126 write_scope_tree(tcx
, mir
, auxiliary
, &scope_tree
, w
, None
, 1)?
;
132 /// Write out a human-readable textual representation for the given basic block.
133 fn write_basic_block(tcx
: &TyCtxt
,
137 annotations
: &FnvHashMap
<Location
, Vec
<Annotation
>>)
139 let data
= mir
.basic_block_data(block
);
141 // Basic block label at the top.
142 writeln
!(w
, "\n{}{:?}: {{", INDENT
, block
)?
;
144 // List of statements in the middle.
145 let mut current_location
= Location { block: block, statement_index: 0 }
;
146 for statement
in &data
.statements
{
147 if let Some(ref annotations
) = annotations
.get(¤t_location
) {
148 for annotation
in annotations
.iter() {
150 Annotation
::EnterScope(id
) =>
151 writeln
!(w
, "{0}{0}// Enter Scope({1})",
152 INDENT
, id
.index())?
,
153 Annotation
::ExitScope(id
) =>
154 writeln
!(w
, "{0}{0}// Exit Scope({1})",
155 INDENT
, id
.index())?
,
160 writeln
!(w
, "{0}{0}{1:?}; // {2}",
163 comment(tcx
, statement
.scope
, statement
.span
))?
;
165 current_location
.statement_index
+= 1;
168 // Terminator at the bottom.
169 writeln
!(w
, "{0}{0}{1:?}; // {2}",
171 data
.terminator().kind
,
172 comment(tcx
, data
.terminator().scope
, data
.terminator().span
))?
;
174 writeln
!(w
, "{}}}", INDENT
)
177 fn comment(tcx
: &TyCtxt
,
181 format
!("Scope({}) at {}", scope
.index(), tcx
.sess
.codemap().span_to_string(span
))
184 fn write_scope_tree(tcx
: &TyCtxt
,
186 auxiliary
: Option
<&ScopeAuxiliaryVec
>,
187 scope_tree
: &FnvHashMap
<Option
<ScopeId
>, Vec
<ScopeId
>>,
189 parent
: Option
<ScopeId
>,
192 for &child
in scope_tree
.get(&parent
).unwrap_or(&vec
![]) {
193 let indent
= depth
* INDENT
.len();
194 let data
= &mir
.scopes
[child
];
195 assert_eq
!(data
.parent_scope
, parent
);
196 writeln
!(w
, "{0:1$}Scope({2}) {{", "", indent
, child
.index())?
;
198 let indent
= indent
+ INDENT
.len();
199 if let Some(parent
) = parent
{
200 writeln
!(w
, "{0:1$}Parent: Scope({2})", "", indent
, parent
.index())?
;
203 if let Some(auxiliary
) = auxiliary
{
204 let extent
= auxiliary
[child
].extent
;
205 let data
= tcx
.region_maps
.code_extent_data(extent
);
206 writeln
!(w
, "{0:1$}Extent: {2:?}", "", indent
, data
)?
;
209 write_scope_tree(tcx
, mir
, auxiliary
, scope_tree
, w
,
210 Some(child
), depth
+ 1)?
;
215 /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
216 /// local variables (both user-defined bindings and compiler temporaries).
217 fn write_mir_intro(tcx
: &TyCtxt
, nid
: NodeId
, mir
: &Mir
, w
: &mut Write
)
219 write
!(w
, "fn {}(", tcx
.node_path_str(nid
))?
;
221 // fn argument types.
222 for (i
, arg
) in mir
.arg_decls
.iter().enumerate() {
226 write
!(w
, "{:?}: {}", Lvalue
::Arg(i
as u32), arg
.ty
)?
;
232 match mir
.return_ty
{
233 ty
::FnOutput
::FnConverging(ty
) => write
!(w
, "{}", ty
)?
,
234 ty
::FnOutput
::FnDiverging
=> write
!(w
, "!")?
,
239 // User variable types (including the user's name in a comment).
240 for (i
, var
) in mir
.var_decls
.iter().enumerate() {
241 write
!(w
, "{}let ", INDENT
)?
;
242 if var
.mutability
== Mutability
::Mut
{
245 writeln
!(w
, "{:?}: {}; // {}", Lvalue
::Var(i
as u32), var
.ty
, var
.name
)?
;
248 // Compiler-introduced temporary types.
249 for (i
, temp
) in mir
.temp_decls
.iter().enumerate() {
250 writeln
!(w
, "{}let mut {:?}: {};", INDENT
, Lvalue
::Temp(i
as u32), temp
.ty
)?
;