]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/util/def_use.rs
Rollup merge of #66941 - CAD97:nord, r=Dylan-DPC
[rust.git] / src / librustc_mir / util / def_use.rs
1 //! Def-use analysis.
2
3 use rustc::mir::{Body, BodyCache, Local, Location, PlaceElem, ReadOnlyBodyCache, VarDebugInfo};
4 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
5 use rustc::ty::TyCtxt;
6 use rustc_index::vec::IndexVec;
7 use std::mem;
8
9 pub struct DefUseAnalysis {
10     info: IndexVec<Local, Info>,
11 }
12
13 #[derive(Clone)]
14 pub struct Info {
15     // FIXME(eddyb) use smallvec where possible.
16     pub defs_and_uses: Vec<Use>,
17     var_debug_info_indices: Vec<usize>,
18 }
19
20 #[derive(Clone)]
21 pub struct Use {
22     pub context: PlaceContext,
23     pub location: Location,
24 }
25
26 impl DefUseAnalysis {
27     pub fn new(body: &Body<'_>) -> DefUseAnalysis {
28         DefUseAnalysis {
29             info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
30         }
31     }
32
33     pub fn analyze(&mut self, body: ReadOnlyBodyCache<'_, '_>) {
34         self.clear();
35
36         let mut finder = DefUseFinder {
37             info: mem::take(&mut self.info),
38             var_debug_info_index: 0,
39             in_var_debug_info: false,
40         };
41         finder.visit_body(body);
42         self.info = finder.info
43     }
44
45     fn clear(&mut self) {
46         for info in &mut self.info {
47             info.clear();
48         }
49     }
50
51     pub fn local_info(&self, local: Local) -> &Info {
52         &self.info[local]
53     }
54
55     fn mutate_defs_and_uses(
56         &self,
57         local: Local,
58         body: &mut BodyCache<'tcx>,
59         new_local: Local,
60         tcx: TyCtxt<'tcx>,
61     ) {
62         let mut visitor = MutateUseVisitor::new(local, new_local, tcx);
63         let info = &self.info[local];
64         for place_use in &info.defs_and_uses {
65             visitor.visit_location(body, place_use.location)
66         }
67         // Update debuginfo as well, alongside defs/uses.
68         for &i in &info.var_debug_info_indices {
69             visitor.visit_var_debug_info(&mut body.var_debug_info[i]);
70         }
71     }
72
73     // FIXME(pcwalton): this should update the def-use chains.
74     pub fn replace_all_defs_and_uses_with(&self,
75                                           local: Local,
76                                           body: &mut BodyCache<'tcx>,
77                                           new_local: Local,
78                                           tcx: TyCtxt<'tcx>) {
79         self.mutate_defs_and_uses(local, body, new_local, tcx)
80     }
81 }
82
83 struct DefUseFinder {
84     info: IndexVec<Local, Info>,
85     var_debug_info_index: usize,
86     in_var_debug_info: bool,
87 }
88
89 impl Visitor<'_> for DefUseFinder {
90     fn visit_local(&mut self,
91                    &local: &Local,
92                    context: PlaceContext,
93                    location: Location) {
94         let info = &mut self.info[local];
95         if self.in_var_debug_info {
96             info.var_debug_info_indices.push(self.var_debug_info_index);
97         } else {
98             info.defs_and_uses.push(Use {
99                 context,
100                 location,
101             });
102         }
103     }
104     fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) {
105         assert!(!self.in_var_debug_info);
106         self.in_var_debug_info = true;
107         self.super_var_debug_info(var_debug_info);
108         self.in_var_debug_info = false;
109         self.var_debug_info_index += 1;
110     }
111 }
112
113 impl Info {
114     fn new() -> Info {
115         Info {
116             defs_and_uses: vec![],
117             var_debug_info_indices: vec![],
118         }
119     }
120
121     fn clear(&mut self) {
122         self.defs_and_uses.clear();
123         self.var_debug_info_indices.clear();
124     }
125
126     pub fn def_count(&self) -> usize {
127         self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
128     }
129
130     pub fn def_count_not_including_drop(&self) -> usize {
131         self.defs_not_including_drop().count()
132     }
133
134     pub fn defs_not_including_drop(
135         &self,
136     ) -> impl Iterator<Item=&Use> {
137         self.defs_and_uses.iter().filter(|place_use| {
138             place_use.context.is_mutating_use() && !place_use.context.is_drop()
139         })
140     }
141
142     pub fn use_count(&self) -> usize {
143         self.defs_and_uses.iter().filter(|place_use| {
144             place_use.context.is_nonmutating_use()
145         }).count()
146     }
147 }
148
149 struct MutateUseVisitor<'tcx> {
150     query: Local,
151     new_local: Local,
152     tcx: TyCtxt<'tcx>,
153 }
154
155 impl MutateUseVisitor<'tcx> {
156     fn new(
157         query: Local,
158         new_local: Local,
159         tcx: TyCtxt<'tcx>,
160     ) -> MutateUseVisitor<'tcx> {
161         MutateUseVisitor { query, new_local, tcx }
162     }
163 }
164
165 impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
166     fn tcx(&self) -> TyCtxt<'tcx> {
167         self.tcx
168     }
169
170     fn visit_local(&mut self,
171                     local: &mut Local,
172                     _context: PlaceContext,
173                     _location: Location) {
174         if *local == self.query {
175             *local = self.new_local;
176         }
177     }
178
179     fn process_projection_elem(
180         &mut self,
181         elem: &PlaceElem<'tcx>,
182     ) -> Option<PlaceElem<'tcx>> {
183         match elem {
184             PlaceElem::Index(local) if *local == self.query => {
185                 Some(PlaceElem::Index(self.new_local))
186             }
187             _ => None,
188         }
189     }
190 }