]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
1 | //! Def-use analysis. |
2 | ||
e74abb32 | 3 | use rustc_index::vec::IndexVec; |
ba9703b0 | 4 | use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; |
f9f354fc | 5 | use rustc_middle::mir::{Body, Local, Location, VarDebugInfo}; |
ba9703b0 | 6 | use rustc_middle::ty::TyCtxt; |
9e0c209e SL |
7 | use std::mem; |
8 | ||
48663c56 XL |
9 | pub struct DefUseAnalysis { |
10 | info: IndexVec<Local, Info>, | |
9e0c209e SL |
11 | } |
12 | ||
13 | #[derive(Clone)] | |
48663c56 | 14 | pub struct Info { |
60c5eb7d | 15 | // FIXME(eddyb) use smallvec where possible. |
48663c56 | 16 | pub defs_and_uses: Vec<Use>, |
60c5eb7d | 17 | var_debug_info_indices: Vec<usize>, |
9e0c209e SL |
18 | } |
19 | ||
20 | #[derive(Clone)] | |
48663c56 XL |
21 | pub struct Use { |
22 | pub context: PlaceContext, | |
9e0c209e SL |
23 | pub location: Location, |
24 | } | |
25 | ||
48663c56 | 26 | impl DefUseAnalysis { |
dc9dc135 | 27 | pub fn new(body: &Body<'_>) -> DefUseAnalysis { |
dfeec247 | 28 | DefUseAnalysis { info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()) } |
9e0c209e SL |
29 | } |
30 | ||
f9f354fc | 31 | pub fn analyze(&mut self, body: &Body<'_>) { |
abe05a73 XL |
32 | self.clear(); |
33 | ||
9e0c209e | 34 | let mut finder = DefUseFinder { |
416331ca | 35 | info: mem::take(&mut self.info), |
60c5eb7d XL |
36 | var_debug_info_index: 0, |
37 | in_var_debug_info: false, | |
9e0c209e | 38 | }; |
ba9703b0 | 39 | finder.visit_body(&body); |
9e0c209e SL |
40 | self.info = finder.info |
41 | } | |
42 | ||
abe05a73 XL |
43 | fn clear(&mut self) { |
44 | for info in &mut self.info { | |
45 | info.clear(); | |
46 | } | |
47 | } | |
48 | ||
48663c56 | 49 | pub fn local_info(&self, local: Local) -> &Info { |
9e0c209e SL |
50 | &self.info[local] |
51 | } | |
52 | ||
e74abb32 XL |
53 | fn mutate_defs_and_uses( |
54 | &self, | |
55 | local: Local, | |
f9f354fc | 56 | body: &mut Body<'tcx>, |
e74abb32 XL |
57 | new_local: Local, |
58 | tcx: TyCtxt<'tcx>, | |
59 | ) { | |
60c5eb7d XL |
60 | let mut visitor = MutateUseVisitor::new(local, new_local, tcx); |
61 | let info = &self.info[local]; | |
62 | for place_use in &info.defs_and_uses { | |
63 | visitor.visit_location(body, place_use.location) | |
64 | } | |
65 | // Update debuginfo as well, alongside defs/uses. | |
66 | for &i in &info.var_debug_info_indices { | |
67 | visitor.visit_var_debug_info(&mut body.var_debug_info[i]); | |
9e0c209e SL |
68 | } |
69 | } | |
70 | ||
9fa01778 | 71 | // FIXME(pcwalton): this should update the def-use chains. |
dfeec247 XL |
72 | pub fn replace_all_defs_and_uses_with( |
73 | &self, | |
74 | local: Local, | |
f9f354fc | 75 | body: &mut Body<'tcx>, |
dfeec247 XL |
76 | new_local: Local, |
77 | tcx: TyCtxt<'tcx>, | |
78 | ) { | |
e74abb32 | 79 | self.mutate_defs_and_uses(local, body, new_local, tcx) |
9e0c209e SL |
80 | } |
81 | } | |
82 | ||
48663c56 XL |
83 | struct DefUseFinder { |
84 | info: IndexVec<Local, Info>, | |
60c5eb7d XL |
85 | var_debug_info_index: usize, |
86 | in_var_debug_info: bool, | |
9e0c209e SL |
87 | } |
88 | ||
48663c56 | 89 | impl Visitor<'_> for DefUseFinder { |
dfeec247 | 90 | fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { |
60c5eb7d XL |
91 | let info = &mut self.info[local]; |
92 | if self.in_var_debug_info { | |
93 | info.var_debug_info_indices.push(self.var_debug_info_index); | |
94 | } else { | |
dfeec247 | 95 | info.defs_and_uses.push(Use { context, location }); |
60c5eb7d XL |
96 | } |
97 | } | |
98 | fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) { | |
99 | assert!(!self.in_var_debug_info); | |
100 | self.in_var_debug_info = true; | |
101 | self.super_var_debug_info(var_debug_info); | |
102 | self.in_var_debug_info = false; | |
103 | self.var_debug_info_index += 1; | |
9e0c209e SL |
104 | } |
105 | } | |
106 | ||
48663c56 XL |
107 | impl Info { |
108 | fn new() -> Info { | |
dfeec247 | 109 | Info { defs_and_uses: vec![], var_debug_info_indices: vec![] } |
9e0c209e SL |
110 | } |
111 | ||
abe05a73 XL |
112 | fn clear(&mut self) { |
113 | self.defs_and_uses.clear(); | |
60c5eb7d | 114 | self.var_debug_info_indices.clear(); |
abe05a73 XL |
115 | } |
116 | ||
9e0c209e | 117 | pub fn def_count(&self) -> usize { |
ff7c6d11 | 118 | self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count() |
9e0c209e SL |
119 | } |
120 | ||
121 | pub fn def_count_not_including_drop(&self) -> usize { | |
abe05a73 XL |
122 | self.defs_not_including_drop().count() |
123 | } | |
124 | ||
dfeec247 XL |
125 | pub fn defs_not_including_drop(&self) -> impl Iterator<Item = &Use> { |
126 | self.defs_and_uses | |
127 | .iter() | |
128 | .filter(|place_use| place_use.context.is_mutating_use() && !place_use.context.is_drop()) | |
9e0c209e SL |
129 | } |
130 | ||
131 | pub fn use_count(&self) -> usize { | |
dfeec247 | 132 | self.defs_and_uses.iter().filter(|place_use| place_use.context.is_nonmutating_use()).count() |
9e0c209e SL |
133 | } |
134 | } | |
135 | ||
e74abb32 | 136 | struct MutateUseVisitor<'tcx> { |
9e0c209e | 137 | query: Local, |
e74abb32 XL |
138 | new_local: Local, |
139 | tcx: TyCtxt<'tcx>, | |
9e0c209e SL |
140 | } |
141 | ||
e74abb32 | 142 | impl MutateUseVisitor<'tcx> { |
dfeec247 | 143 | fn new(query: Local, new_local: Local, tcx: TyCtxt<'tcx>) -> MutateUseVisitor<'tcx> { |
e74abb32 | 144 | MutateUseVisitor { query, new_local, tcx } |
9e0c209e SL |
145 | } |
146 | } | |
147 | ||
e74abb32 XL |
148 | impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> { |
149 | fn tcx(&self) -> TyCtxt<'tcx> { | |
150 | self.tcx | |
151 | } | |
152 | ||
dfeec247 | 153 | fn visit_local(&mut self, local: &mut Local, _context: PlaceContext, _location: Location) { |
ea8adc8c | 154 | if *local == self.query { |
e74abb32 XL |
155 | *local = self.new_local; |
156 | } | |
157 | } | |
9e0c209e | 158 | } |