]>
Commit | Line | Data |
---|---|---|
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 | 11 | use rustc::hir; |
5bcae85e | 12 | use rustc::hir::def_id::DefId; |
c30ab7b3 | 13 | use rustc::mir::*; |
a7813a04 | 14 | use rustc::mir::transform::MirSource; |
5bcae85e | 15 | use rustc::ty::TyCtxt; |
476ff2be | 16 | use rustc_data_structures::fx::FxHashMap; |
3157f602 | 17 | use rustc_data_structures::indexed_vec::{Idx}; |
54a0048b SL |
18 | use std::fmt::Display; |
19 | use std::fs; | |
9cc50fc6 | 20 | use std::io::{self, Write}; |
5bcae85e | 21 | use std::path::{PathBuf, Path}; |
9cc50fc6 SL |
22 | |
23 | const INDENT: &'static str = " "; | |
a7813a04 XL |
24 | /// Alignment for lining up comments following MIR statements |
25 | const 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 | 41 | pub 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 |
88 | pub 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 |
117 | pub 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 | 135 | fn 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 | 167 | fn 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 | 174 | fn 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 |
233 | fn 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 | ||
273 | fn 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 | 304 | fn 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 | } |