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