]>
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 | ||
54a0048b | 11 | use build::{Location, ScopeAuxiliaryVec}; |
9cc50fc6 | 12 | use rustc::mir::repr::*; |
54a0048b SL |
13 | use rustc::ty::{self, TyCtxt}; |
14 | use rustc_data_structures::fnv::FnvHashMap; | |
15 | use std::fmt::Display; | |
16 | use std::fs; | |
9cc50fc6 | 17 | use std::io::{self, Write}; |
54a0048b SL |
18 | use syntax::ast::NodeId; |
19 | use syntax::codemap::Span; | |
9cc50fc6 SL |
20 | |
21 | const INDENT: &'static str = " "; | |
22 | ||
54a0048b SL |
23 | /// If the session is properly configured, dumps a human-readable |
24 | /// representation of the mir into: | |
25 | /// | |
26 | /// ``` | |
27 | /// rustc.node<node_id>.<pass_name>.<disambiguator> | |
28 | /// ``` | |
29 | /// | |
30 | /// Output from this function is controlled by passing `-Z dump-mir=<filter>`, | |
31 | /// where `<filter>` takes the following forms: | |
32 | /// | |
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>, | |
38 | pass_name: &str, | |
39 | disambiguator: &Display, | |
40 | node_id: NodeId, | |
41 | mir: &Mir<'tcx>, | |
42 | auxiliary: Option<&ScopeAuxiliaryVec>) { | |
43 | let filters = match tcx.sess.opts.debugging_opts.dump_mir { | |
44 | None => return, | |
45 | Some(ref filters) => filters, | |
46 | }; | |
47 | let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id)); | |
48 | let is_matched = | |
49 | filters.split("&") | |
50 | .any(|filter| { | |
51 | filter == "all" || | |
52 | pass_name.contains(filter) || | |
53 | node_path.contains(filter) | |
54 | }); | |
55 | if !is_matched { | |
56 | return; | |
57 | } | |
58 | ||
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)); | |
68 | Ok(()) | |
69 | }); | |
70 | } | |
71 | ||
9cc50fc6 | 72 | /// Write out a human-readable textual representation for the given MIR. |
54a0048b SL |
73 | pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &TyCtxt<'tcx>, |
74 | iter: I, | |
75 | w: &mut Write) | |
76 | -> io::Result<()> | |
77 | where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a | |
78 | { | |
79 | for (&node_id, mir) in iter { | |
80 | write_mir_fn(tcx, node_id, mir, w, None)?; | |
81 | } | |
82 | Ok(()) | |
83 | } | |
9cc50fc6 | 84 | |
54a0048b SL |
85 | enum Annotation { |
86 | EnterScope(ScopeId), | |
87 | ExitScope(ScopeId), | |
88 | } | |
89 | ||
90 | pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>, | |
91 | node_id: NodeId, | |
92 | mir: &Mir<'tcx>, | |
93 | w: &mut Write, | |
94 | auxiliary: Option<&ScopeAuxiliaryVec>) | |
95 | -> io::Result<()> { | |
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); | |
101 | ||
102 | annotations.entry(auxiliary.dom) | |
103 | .or_insert(vec![]) | |
104 | .push(Annotation::EnterScope(scope_id)); | |
105 | ||
106 | for &loc in &auxiliary.postdoms { | |
107 | annotations.entry(loc) | |
108 | .or_insert(vec![]) | |
109 | .push(Annotation::ExitScope(scope_id)); | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | write_mir_intro(tcx, node_id, mir, w)?; | |
9cc50fc6 | 115 | for block in mir.all_basic_blocks() { |
54a0048b SL |
116 | write_basic_block(tcx, block, mir, w, &annotations)?; |
117 | } | |
118 | ||
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) | |
123 | .or_insert(vec![]) | |
124 | .push(ScopeId::new(index)); | |
9cc50fc6 | 125 | } |
54a0048b | 126 | write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1)?; |
9cc50fc6 | 127 | |
54a0048b SL |
128 | writeln!(w, "}}")?; |
129 | Ok(()) | |
9cc50fc6 SL |
130 | } |
131 | ||
132 | /// Write out a human-readable textual representation for the given basic block. | |
54a0048b SL |
133 | fn write_basic_block(tcx: &TyCtxt, |
134 | block: BasicBlock, | |
135 | mir: &Mir, | |
136 | w: &mut Write, | |
137 | annotations: &FnvHashMap<Location, Vec<Annotation>>) | |
138 | -> io::Result<()> { | |
9cc50fc6 SL |
139 | let data = mir.basic_block_data(block); |
140 | ||
141 | // Basic block label at the top. | |
54a0048b | 142 | writeln!(w, "\n{}{:?}: {{", INDENT, block)?; |
9cc50fc6 SL |
143 | |
144 | // List of statements in the middle. | |
54a0048b | 145 | let mut current_location = Location { block: block, statement_index: 0 }; |
9cc50fc6 | 146 | for statement in &data.statements { |
54a0048b SL |
147 | if let Some(ref annotations) = annotations.get(¤t_location) { |
148 | for annotation in annotations.iter() { | |
149 | match *annotation { | |
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())?, | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | writeln!(w, "{0}{0}{1:?}; // {2}", | |
161 | INDENT, | |
162 | statement, | |
163 | comment(tcx, statement.scope, statement.span))?; | |
164 | ||
165 | current_location.statement_index += 1; | |
9cc50fc6 SL |
166 | } |
167 | ||
168 | // Terminator at the bottom. | |
54a0048b SL |
169 | writeln!(w, "{0}{0}{1:?}; // {2}", |
170 | INDENT, | |
171 | data.terminator().kind, | |
172 | comment(tcx, data.terminator().scope, data.terminator().span))?; | |
9cc50fc6 SL |
173 | |
174 | writeln!(w, "{}}}", INDENT) | |
175 | } | |
176 | ||
54a0048b SL |
177 | fn comment(tcx: &TyCtxt, |
178 | scope: ScopeId, | |
179 | span: Span) | |
180 | -> String { | |
181 | format!("Scope({}) at {}", scope.index(), tcx.sess.codemap().span_to_string(span)) | |
182 | } | |
183 | ||
184 | fn write_scope_tree(tcx: &TyCtxt, | |
185 | mir: &Mir, | |
186 | auxiliary: Option<&ScopeAuxiliaryVec>, | |
187 | scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>, | |
188 | w: &mut Write, | |
189 | parent: Option<ScopeId>, | |
190 | depth: usize) | |
191 | -> io::Result<()> { | |
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())?; | |
197 | ||
198 | let indent = indent + INDENT.len(); | |
199 | if let Some(parent) = parent { | |
200 | writeln!(w, "{0:1$}Parent: Scope({2})", "", indent, parent.index())?; | |
201 | } | |
202 | ||
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)?; | |
207 | } | |
208 | ||
209 | write_scope_tree(tcx, mir, auxiliary, scope_tree, w, | |
210 | Some(child), depth + 1)?; | |
211 | } | |
212 | Ok(()) | |
213 | } | |
214 | ||
9cc50fc6 SL |
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). | |
54a0048b SL |
217 | fn write_mir_intro(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write) |
218 | -> io::Result<()> { | |
219 | write!(w, "fn {}(", tcx.node_path_str(nid))?; | |
9cc50fc6 SL |
220 | |
221 | // fn argument types. | |
222 | for (i, arg) in mir.arg_decls.iter().enumerate() { | |
223 | if i > 0 { | |
54a0048b | 224 | write!(w, ", ")?; |
9cc50fc6 | 225 | } |
54a0048b | 226 | write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?; |
9cc50fc6 SL |
227 | } |
228 | ||
54a0048b | 229 | write!(w, ") -> ")?; |
9cc50fc6 SL |
230 | |
231 | // fn return type. | |
232 | match mir.return_ty { | |
54a0048b SL |
233 | ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?, |
234 | ty::FnOutput::FnDiverging => write!(w, "!")?, | |
9cc50fc6 SL |
235 | } |
236 | ||
54a0048b | 237 | writeln!(w, " {{")?; |
9cc50fc6 SL |
238 | |
239 | // User variable types (including the user's name in a comment). | |
240 | for (i, var) in mir.var_decls.iter().enumerate() { | |
54a0048b | 241 | write!(w, "{}let ", INDENT)?; |
9cc50fc6 | 242 | if var.mutability == Mutability::Mut { |
54a0048b | 243 | write!(w, "mut ")?; |
9cc50fc6 | 244 | } |
54a0048b | 245 | writeln!(w, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name)?; |
9cc50fc6 SL |
246 | } |
247 | ||
248 | // Compiler-introduced temporary types. | |
249 | for (i, temp) in mir.temp_decls.iter().enumerate() { | |
54a0048b | 250 | writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?; |
9cc50fc6 SL |
251 | } |
252 | ||
253 | Ok(()) | |
254 | } |