]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
1 | //! Def-use analysis. |
2 | ||
e74abb32 | 3 | use rustc::mir::{Body, Local, Location, PlaceElem}; |
ff7c6d11 | 4 | use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; |
e74abb32 XL |
5 | use rustc::ty::TyCtxt; |
6 | use rustc_index::vec::IndexVec; | |
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 XL |
14 | pub struct Info { |
15 | pub defs_and_uses: Vec<Use>, | |
9e0c209e SL |
16 | } |
17 | ||
18 | #[derive(Clone)] | |
48663c56 XL |
19 | pub struct Use { |
20 | pub context: PlaceContext, | |
9e0c209e SL |
21 | pub location: Location, |
22 | } | |
23 | ||
48663c56 | 24 | impl DefUseAnalysis { |
dc9dc135 | 25 | pub fn new(body: &Body<'_>) -> DefUseAnalysis { |
9e0c209e | 26 | DefUseAnalysis { |
dc9dc135 | 27 | info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()), |
9e0c209e SL |
28 | } |
29 | } | |
30 | ||
dc9dc135 | 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), |
9e0c209e | 36 | }; |
dc9dc135 | 37 | finder.visit_body(body); |
9e0c209e SL |
38 | self.info = finder.info |
39 | } | |
40 | ||
abe05a73 XL |
41 | fn clear(&mut self) { |
42 | for info in &mut self.info { | |
43 | info.clear(); | |
44 | } | |
45 | } | |
46 | ||
48663c56 | 47 | pub fn local_info(&self, local: Local) -> &Info { |
9e0c209e SL |
48 | &self.info[local] |
49 | } | |
50 | ||
e74abb32 XL |
51 | fn mutate_defs_and_uses( |
52 | &self, | |
53 | local: Local, | |
54 | body: &mut Body<'tcx>, | |
55 | new_local: Local, | |
56 | tcx: TyCtxt<'tcx>, | |
57 | ) { | |
ff7c6d11 | 58 | for place_use in &self.info[local].defs_and_uses { |
e74abb32 XL |
59 | MutateUseVisitor::new(local, new_local, body, tcx) |
60 | .visit_location(body, place_use.location) | |
9e0c209e SL |
61 | } |
62 | } | |
63 | ||
9fa01778 | 64 | // FIXME(pcwalton): this should update the def-use chains. |
9e0c209e SL |
65 | pub fn replace_all_defs_and_uses_with(&self, |
66 | local: Local, | |
e74abb32 XL |
67 | body: &mut Body<'tcx>, |
68 | new_local: Local, | |
69 | tcx: TyCtxt<'tcx>) { | |
70 | self.mutate_defs_and_uses(local, body, new_local, tcx) | |
9e0c209e SL |
71 | } |
72 | } | |
73 | ||
48663c56 XL |
74 | struct DefUseFinder { |
75 | info: IndexVec<Local, Info>, | |
9e0c209e SL |
76 | } |
77 | ||
48663c56 | 78 | impl Visitor<'_> for DefUseFinder { |
ea8adc8c XL |
79 | fn visit_local(&mut self, |
80 | &local: &Local, | |
48663c56 | 81 | context: PlaceContext, |
ea8adc8c XL |
82 | location: Location) { |
83 | self.info[local].defs_and_uses.push(Use { | |
84 | context, | |
85 | location, | |
86 | }); | |
9e0c209e SL |
87 | } |
88 | } | |
89 | ||
48663c56 XL |
90 | impl Info { |
91 | fn new() -> Info { | |
9e0c209e SL |
92 | Info { |
93 | defs_and_uses: vec![], | |
94 | } | |
95 | } | |
96 | ||
abe05a73 XL |
97 | fn clear(&mut self) { |
98 | self.defs_and_uses.clear(); | |
99 | } | |
100 | ||
9e0c209e | 101 | pub fn def_count(&self) -> usize { |
ff7c6d11 | 102 | self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count() |
9e0c209e SL |
103 | } |
104 | ||
105 | pub fn def_count_not_including_drop(&self) -> usize { | |
abe05a73 XL |
106 | self.defs_not_including_drop().count() |
107 | } | |
108 | ||
109 | pub fn defs_not_including_drop( | |
110 | &self, | |
48663c56 | 111 | ) -> impl Iterator<Item=&Use> { |
ff7c6d11 XL |
112 | self.defs_and_uses.iter().filter(|place_use| { |
113 | place_use.context.is_mutating_use() && !place_use.context.is_drop() | |
abe05a73 | 114 | }) |
9e0c209e SL |
115 | } |
116 | ||
117 | pub fn use_count(&self) -> usize { | |
ff7c6d11 XL |
118 | self.defs_and_uses.iter().filter(|place_use| { |
119 | place_use.context.is_nonmutating_use() | |
9e0c209e SL |
120 | }).count() |
121 | } | |
122 | } | |
123 | ||
e74abb32 | 124 | struct MutateUseVisitor<'tcx> { |
9e0c209e | 125 | query: Local, |
e74abb32 XL |
126 | new_local: Local, |
127 | tcx: TyCtxt<'tcx>, | |
9e0c209e SL |
128 | } |
129 | ||
e74abb32 XL |
130 | impl MutateUseVisitor<'tcx> { |
131 | fn new( | |
132 | query: Local, | |
133 | new_local: Local, | |
134 | _: &Body<'tcx>, | |
135 | tcx: TyCtxt<'tcx>, | |
136 | ) -> MutateUseVisitor<'tcx> { | |
137 | MutateUseVisitor { query, new_local, tcx } | |
9e0c209e SL |
138 | } |
139 | } | |
140 | ||
e74abb32 XL |
141 | impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> { |
142 | fn tcx(&self) -> TyCtxt<'tcx> { | |
143 | self.tcx | |
144 | } | |
145 | ||
ea8adc8c XL |
146 | fn visit_local(&mut self, |
147 | local: &mut Local, | |
e74abb32 XL |
148 | _context: PlaceContext, |
149 | _location: Location) { | |
ea8adc8c | 150 | if *local == self.query { |
e74abb32 XL |
151 | *local = self.new_local; |
152 | } | |
153 | } | |
154 | ||
155 | fn process_projection_elem( | |
156 | &mut self, | |
157 | elem: &PlaceElem<'tcx>, | |
158 | ) -> Option<PlaceElem<'tcx>> { | |
159 | match elem { | |
160 | PlaceElem::Index(local) if *local == self.query => { | |
161 | Some(PlaceElem::Index(self.new_local)) | |
162 | } | |
163 | _ => None, | |
9e0c209e SL |
164 | } |
165 | } | |
166 | } |