]> git.lizzy.rs Git - rust.git/blob - src/librustc_passes/mir_stats.rs
Auto merge of #43648 - RalfJung:jemalloc-debug, r=alexcrichton
[rust.git] / src / librustc_passes / mir_stats.rs
1 // Copyright 2016 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
11 // The visitors in this module collect sizes and counts of the most important
12 // pieces of MIR. The resulting numbers are good approximations but not
13 // completely accurate (some things might be counted twice, others missed).
14
15 use rustc_const_math::{ConstUsize};
16 use rustc::middle::const_val::{ConstVal};
17 use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
18 use rustc::mir::{Constant, Literal, Location, LocalDecl};
19 use rustc::mir::{Lvalue, LvalueElem, LvalueProjection};
20 use rustc::mir::{Mir, Operand, ProjectionElem};
21 use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
22 use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
23 use rustc::mir::visit as mir_visit;
24 use rustc::ty::{ClosureSubsts, TyCtxt};
25 use rustc::util::nodemap::{FxHashMap};
26
27 struct NodeData {
28     count: usize,
29     size: usize,
30 }
31
32 struct StatCollector<'a, 'tcx: 'a> {
33     _tcx: TyCtxt<'a, 'tcx, 'tcx>,
34     data: FxHashMap<&'static str, NodeData>,
35 }
36
37 impl<'a, 'tcx> StatCollector<'a, 'tcx> {
38
39     fn record_with_size(&mut self, label: &'static str, node_size: usize) {
40         let entry = self.data.entry(label).or_insert(NodeData {
41             count: 0,
42             size: 0,
43         });
44
45         entry.count += 1;
46         entry.size = node_size;
47     }
48
49     fn record<T>(&mut self, label: &'static str, node: &T) {
50         self.record_with_size(label, ::std::mem::size_of_val(node));
51     }
52 }
53
54 impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
55     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
56         self.record("Mir", mir);
57
58         // since the `super_mir` method does not traverse the MIR of
59         // promoted rvalues, (but we still want to gather statistics
60         // on the structures represented there) we manually traverse
61         // the promoted rvalues here.
62         for promoted_mir in &mir.promoted {
63             self.visit_mir(promoted_mir);
64         }
65
66         self.super_mir(mir);
67     }
68
69     fn visit_basic_block_data(&mut self,
70                               block: BasicBlock,
71                               data: &BasicBlockData<'tcx>) {
72         self.record("BasicBlockData", data);
73         self.super_basic_block_data(block, data);
74     }
75
76     fn visit_visibility_scope_data(&mut self,
77                                    scope_data: &VisibilityScopeData) {
78         self.record("VisibilityScopeData", scope_data);
79         self.super_visibility_scope_data(scope_data);
80     }
81
82     fn visit_statement(&mut self,
83                        block: BasicBlock,
84                        statement: &Statement<'tcx>,
85                        location: Location) {
86         self.record("Statement", statement);
87         self.record(match statement.kind {
88             StatementKind::Assign(..) => "StatementKind::Assign",
89             StatementKind::EndRegion(..) => "StatementKind::EndRegion",
90             StatementKind::Validate(..) => "StatementKind::Validate",
91             StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant",
92             StatementKind::StorageLive(..) => "StatementKind::StorageLive",
93             StatementKind::StorageDead(..) => "StatementKind::StorageDead",
94             StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
95             StatementKind::Nop => "StatementKind::Nop",
96         }, &statement.kind);
97         self.super_statement(block, statement, location);
98     }
99
100     fn visit_terminator(&mut self,
101                         block: BasicBlock,
102                         terminator: &Terminator<'tcx>,
103                         location: Location) {
104         self.record("Terminator", terminator);
105         self.super_terminator(block, terminator, location);
106     }
107
108     fn visit_terminator_kind(&mut self,
109                              block: BasicBlock,
110                              kind: &TerminatorKind<'tcx>,
111                              location: Location) {
112         self.record("TerminatorKind", kind);
113         self.record(match *kind {
114             TerminatorKind::Goto { .. } => "TerminatorKind::Goto",
115             TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt",
116             TerminatorKind::Resume => "TerminatorKind::Resume",
117             TerminatorKind::Return => "TerminatorKind::Return",
118             TerminatorKind::Unreachable => "TerminatorKind::Unreachable",
119             TerminatorKind::Drop { .. } => "TerminatorKind::Drop",
120             TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace",
121             TerminatorKind::Call { .. } => "TerminatorKind::Call",
122             TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
123             TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
124             TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
125         }, kind);
126         self.super_terminator_kind(block, kind, location);
127     }
128
129     fn visit_assert_message(&mut self,
130                             msg: &AssertMessage<'tcx>,
131                             location: Location) {
132         self.record("AssertMessage", msg);
133         self.record(match *msg {
134             AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
135             AssertMessage::Math(..) => "AssertMessage::Math",
136             AssertMessage::GeneratorResumedAfterReturn => {
137                 "AssertMessage::GeneratorResumedAfterReturn"
138             }
139             AssertMessage::GeneratorResumedAfterPanic => {
140                 "AssertMessage::GeneratorResumedAfterPanic"
141             }
142         }, msg);
143         self.super_assert_message(msg, location);
144     }
145
146     fn visit_rvalue(&mut self,
147                     rvalue: &Rvalue<'tcx>,
148                     location: Location) {
149         self.record("Rvalue", rvalue);
150         let rvalue_kind = match *rvalue {
151             Rvalue::Use(..) => "Rvalue::Use",
152             Rvalue::Repeat(..) => "Rvalue::Repeat",
153             Rvalue::Ref(..) => "Rvalue::Ref",
154             Rvalue::Len(..) => "Rvalue::Len",
155             Rvalue::Cast(..) => "Rvalue::Cast",
156             Rvalue::BinaryOp(..) => "Rvalue::BinaryOp",
157             Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp",
158             Rvalue::UnaryOp(..) => "Rvalue::UnaryOp",
159             Rvalue::Discriminant(..) => "Rvalue::Discriminant",
160             Rvalue::NullaryOp(..) => "Rvalue::NullaryOp",
161             Rvalue::Aggregate(ref kind, ref _operands) => {
162                 // AggregateKind is not distinguished by visit API, so
163                 // record it. (`super_rvalue` handles `_operands`.)
164                 self.record(match **kind {
165                     AggregateKind::Array(_) => "AggregateKind::Array",
166                     AggregateKind::Tuple => "AggregateKind::Tuple",
167                     AggregateKind::Adt(..) => "AggregateKind::Adt",
168                     AggregateKind::Closure(..) => "AggregateKind::Closure",
169                     AggregateKind::Generator(..) => "AggregateKind::Generator",
170                 }, kind);
171
172                 "Rvalue::Aggregate"
173             }
174         };
175         self.record(rvalue_kind, rvalue);
176         self.super_rvalue(rvalue, location);
177     }
178
179     fn visit_operand(&mut self,
180                      operand: &Operand<'tcx>,
181                      location: Location) {
182         self.record("Operand", operand);
183         self.record(match *operand {
184             Operand::Consume(..) => "Operand::Consume",
185             Operand::Constant(..) => "Operand::Constant",
186         }, operand);
187         self.super_operand(operand, location);
188     }
189
190     fn visit_lvalue(&mut self,
191                     lvalue: &Lvalue<'tcx>,
192                     context: mir_visit::LvalueContext<'tcx>,
193                     location: Location) {
194         self.record("Lvalue", lvalue);
195         self.record(match *lvalue {
196             Lvalue::Local(..) => "Lvalue::Local",
197             Lvalue::Static(..) => "Lvalue::Static",
198             Lvalue::Projection(..) => "Lvalue::Projection",
199         }, lvalue);
200         self.super_lvalue(lvalue, context, location);
201     }
202
203     fn visit_projection(&mut self,
204                         lvalue: &LvalueProjection<'tcx>,
205                         context: mir_visit::LvalueContext<'tcx>,
206                         location: Location) {
207         self.record("LvalueProjection", lvalue);
208         self.super_projection(lvalue, context, location);
209     }
210
211     fn visit_projection_elem(&mut self,
212                              lvalue: &LvalueElem<'tcx>,
213                              context: mir_visit::LvalueContext<'tcx>,
214                              location: Location) {
215         self.record("LvalueElem", lvalue);
216         self.record(match *lvalue {
217             ProjectionElem::Deref => "LvalueElem::Deref",
218             ProjectionElem::Subslice { .. } => "LvalueElem::Subslice",
219             ProjectionElem::Field(..) => "LvalueElem::Field",
220             ProjectionElem::Index(..) => "LvalueElem::Index",
221             ProjectionElem::ConstantIndex { .. } => "LvalueElem::ConstantIndex",
222             ProjectionElem::Downcast(..) => "LvalueElem::Downcast",
223         }, lvalue);
224         self.super_projection_elem(lvalue, context, location);
225     }
226
227     fn visit_constant(&mut self,
228                       constant: &Constant<'tcx>,
229                       location: Location) {
230         self.record("Constant", constant);
231         self.super_constant(constant, location);
232     }
233
234     fn visit_literal(&mut self,
235                      literal: &Literal<'tcx>,
236                      location: Location) {
237         self.record("Literal", literal);
238         self.record(match *literal {
239             Literal::Item { .. } => "Literal::Item",
240             Literal::Value { .. } => "Literal::Value",
241             Literal::Promoted { .. } => "Literal::Promoted",
242         }, literal);
243         self.super_literal(literal, location);
244     }
245
246     fn visit_source_info(&mut self,
247                          source_info: &SourceInfo) {
248         self.record("SourceInfo", source_info);
249         self.super_source_info(source_info);
250     }
251
252     fn visit_closure_substs(&mut self,
253                             substs: &ClosureSubsts<'tcx>,
254                             _: Location) {
255         self.record("ClosureSubsts", substs);
256         self.super_closure_substs(substs);
257     }
258
259     fn visit_const_val(&mut self,
260                        const_val: &ConstVal,
261                        _: Location) {
262         self.record("ConstVal", const_val);
263         self.super_const_val(const_val);
264     }
265
266     fn visit_const_usize(&mut self,
267                          const_usize: &ConstUsize,
268                          _: Location) {
269         self.record("ConstUsize", const_usize);
270         self.super_const_usize(const_usize);
271     }
272
273     fn visit_local_decl(&mut self,
274                         local_decl: &LocalDecl<'tcx>) {
275         self.record("LocalDecl", local_decl);
276         self.super_local_decl(local_decl);
277     }
278
279     fn visit_visibility_scope(&mut self,
280                               scope: &VisibilityScope) {
281         self.record("VisiblityScope", scope);
282         self.super_visibility_scope(scope);
283     }
284 }