]>
Commit | Line | Data |
---|---|---|
476ff2be SL |
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}; | |
476ff2be | 16 | use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData}; |
abe05a73 | 17 | use rustc::mir::{Constant, Literal, Location, Local, LocalDecl}; |
476ff2be SL |
18 | use rustc::mir::{Lvalue, LvalueElem, LvalueProjection}; |
19 | use rustc::mir::{Mir, Operand, ProjectionElem}; | |
20 | use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; | |
8bb4bdeb | 21 | use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData}; |
476ff2be | 22 | use rustc::mir::visit as mir_visit; |
ea8adc8c | 23 | use rustc::ty::{self, ClosureSubsts, TyCtxt}; |
476ff2be SL |
24 | use rustc::util::nodemap::{FxHashMap}; |
25 | ||
26 | struct NodeData { | |
27 | count: usize, | |
28 | size: usize, | |
29 | } | |
30 | ||
31 | struct StatCollector<'a, 'tcx: 'a> { | |
32 | _tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
33 | data: FxHashMap<&'static str, NodeData>, | |
34 | } | |
35 | ||
476ff2be SL |
36 | impl<'a, 'tcx> StatCollector<'a, 'tcx> { |
37 | ||
38 | fn record_with_size(&mut self, label: &'static str, node_size: usize) { | |
39 | let entry = self.data.entry(label).or_insert(NodeData { | |
40 | count: 0, | |
41 | size: 0, | |
42 | }); | |
43 | ||
44 | entry.count += 1; | |
45 | entry.size = node_size; | |
46 | } | |
47 | ||
48 | fn record<T>(&mut self, label: &'static str, node: &T) { | |
49 | self.record_with_size(label, ::std::mem::size_of_val(node)); | |
50 | } | |
476ff2be SL |
51 | } |
52 | ||
53 | impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { | |
54 | fn visit_mir(&mut self, mir: &Mir<'tcx>) { | |
55 | self.record("Mir", mir); | |
56 | ||
57 | // since the `super_mir` method does not traverse the MIR of | |
58 | // promoted rvalues, (but we still want to gather statistics | |
59 | // on the structures represented there) we manually traverse | |
60 | // the promoted rvalues here. | |
61 | for promoted_mir in &mir.promoted { | |
62 | self.visit_mir(promoted_mir); | |
63 | } | |
64 | ||
65 | self.super_mir(mir); | |
66 | } | |
67 | ||
68 | fn visit_basic_block_data(&mut self, | |
69 | block: BasicBlock, | |
70 | data: &BasicBlockData<'tcx>) { | |
71 | self.record("BasicBlockData", data); | |
72 | self.super_basic_block_data(block, data); | |
73 | } | |
74 | ||
75 | fn visit_visibility_scope_data(&mut self, | |
76 | scope_data: &VisibilityScopeData) { | |
77 | self.record("VisibilityScopeData", scope_data); | |
78 | self.super_visibility_scope_data(scope_data); | |
79 | } | |
80 | ||
81 | fn visit_statement(&mut self, | |
82 | block: BasicBlock, | |
83 | statement: &Statement<'tcx>, | |
84 | location: Location) { | |
85 | self.record("Statement", statement); | |
86 | self.record(match statement.kind { | |
87 | StatementKind::Assign(..) => "StatementKind::Assign", | |
041b39d2 | 88 | StatementKind::EndRegion(..) => "StatementKind::EndRegion", |
3b2f2976 | 89 | StatementKind::Validate(..) => "StatementKind::Validate", |
476ff2be SL |
90 | StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", |
91 | StatementKind::StorageLive(..) => "StatementKind::StorageLive", | |
92 | StatementKind::StorageDead(..) => "StatementKind::StorageDead", | |
8bb4bdeb | 93 | StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm", |
476ff2be SL |
94 | StatementKind::Nop => "StatementKind::Nop", |
95 | }, &statement.kind); | |
96 | self.super_statement(block, statement, location); | |
97 | } | |
98 | ||
99 | fn visit_terminator(&mut self, | |
100 | block: BasicBlock, | |
101 | terminator: &Terminator<'tcx>, | |
102 | location: Location) { | |
103 | self.record("Terminator", terminator); | |
104 | self.super_terminator(block, terminator, location); | |
105 | } | |
106 | ||
107 | fn visit_terminator_kind(&mut self, | |
108 | block: BasicBlock, | |
109 | kind: &TerminatorKind<'tcx>, | |
110 | location: Location) { | |
111 | self.record("TerminatorKind", kind); | |
112 | self.record(match *kind { | |
113 | TerminatorKind::Goto { .. } => "TerminatorKind::Goto", | |
476ff2be SL |
114 | TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt", |
115 | TerminatorKind::Resume => "TerminatorKind::Resume", | |
116 | TerminatorKind::Return => "TerminatorKind::Return", | |
117 | TerminatorKind::Unreachable => "TerminatorKind::Unreachable", | |
118 | TerminatorKind::Drop { .. } => "TerminatorKind::Drop", | |
119 | TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace", | |
120 | TerminatorKind::Call { .. } => "TerminatorKind::Call", | |
121 | TerminatorKind::Assert { .. } => "TerminatorKind::Assert", | |
ea8adc8c XL |
122 | TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop", |
123 | TerminatorKind::Yield { .. } => "TerminatorKind::Yield", | |
abe05a73 | 124 | TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges", |
476ff2be SL |
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", | |
ea8adc8c XL |
136 | AssertMessage::GeneratorResumedAfterReturn => { |
137 | "AssertMessage::GeneratorResumedAfterReturn" | |
138 | } | |
139 | AssertMessage::GeneratorResumedAfterPanic => { | |
140 | "AssertMessage::GeneratorResumedAfterPanic" | |
141 | } | |
476ff2be SL |
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", | |
8bb4bdeb | 159 | Rvalue::Discriminant(..) => "Rvalue::Discriminant", |
7cac9316 | 160 | Rvalue::NullaryOp(..) => "Rvalue::NullaryOp", |
476ff2be SL |
161 | Rvalue::Aggregate(ref kind, ref _operands) => { |
162 | // AggregateKind is not distinguished by visit API, so | |
163 | // record it. (`super_rvalue` handles `_operands`.) | |
cc61c64b | 164 | self.record(match **kind { |
8bb4bdeb | 165 | AggregateKind::Array(_) => "AggregateKind::Array", |
476ff2be SL |
166 | AggregateKind::Tuple => "AggregateKind::Tuple", |
167 | AggregateKind::Adt(..) => "AggregateKind::Adt", | |
168 | AggregateKind::Closure(..) => "AggregateKind::Closure", | |
ea8adc8c | 169 | AggregateKind::Generator(..) => "AggregateKind::Generator", |
476ff2be SL |
170 | }, kind); |
171 | ||
172 | "Rvalue::Aggregate" | |
173 | } | |
476ff2be SL |
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 { | |
476ff2be SL |
239 | Literal::Value { .. } => "Literal::Value", |
240 | Literal::Promoted { .. } => "Literal::Promoted", | |
241 | }, literal); | |
242 | self.super_literal(literal, location); | |
243 | } | |
244 | ||
245 | fn visit_source_info(&mut self, | |
246 | source_info: &SourceInfo) { | |
247 | self.record("SourceInfo", source_info); | |
248 | self.super_source_info(source_info); | |
249 | } | |
250 | ||
251 | fn visit_closure_substs(&mut self, | |
3b2f2976 XL |
252 | substs: &ClosureSubsts<'tcx>, |
253 | _: Location) { | |
476ff2be SL |
254 | self.record("ClosureSubsts", substs); |
255 | self.super_closure_substs(substs); | |
256 | } | |
257 | ||
ea8adc8c XL |
258 | fn visit_const(&mut self, |
259 | constant: &&'tcx ty::Const<'tcx>, | |
260 | _: Location) { | |
261 | self.record("Const", constant); | |
262 | self.super_const(constant); | |
476ff2be SL |
263 | } |
264 | ||
265 | fn visit_const_usize(&mut self, | |
266 | const_usize: &ConstUsize, | |
267 | _: Location) { | |
268 | self.record("ConstUsize", const_usize); | |
269 | self.super_const_usize(const_usize); | |
270 | } | |
271 | ||
476ff2be | 272 | fn visit_local_decl(&mut self, |
abe05a73 | 273 | local: Local, |
476ff2be SL |
274 | local_decl: &LocalDecl<'tcx>) { |
275 | self.record("LocalDecl", local_decl); | |
abe05a73 | 276 | self.super_local_decl(local, local_decl); |
476ff2be SL |
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 | } |