]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/util/def_use.rs
0ac743359be96e2c91efbf06c25bd3fa6f718e7b
[rust.git] / src / librustc_mir / util / def_use.rs
1 //! Def-use analysis.
2
3 use rustc_index::vec::IndexVec;
4 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
5 use rustc_middle::mir::{Body, BodyAndCache, Local, Location, ReadOnlyBodyAndCache, VarDebugInfo};
6 use rustc_middle::ty::TyCtxt;
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 { info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()) }
29     }
30
31     pub fn analyze(&mut self, body: ReadOnlyBodyAndCache<'_, '_>) {
32         self.clear();
33
34         let mut finder = DefUseFinder {
35             info: mem::take(&mut self.info),
36             var_debug_info_index: 0,
37             in_var_debug_info: false,
38         };
39         finder.visit_body(&body);
40         self.info = finder.info
41     }
42
43     fn clear(&mut self) {
44         for info in &mut self.info {
45             info.clear();
46         }
47     }
48
49     pub fn local_info(&self, local: Local) -> &Info {
50         &self.info[local]
51     }
52
53     fn mutate_defs_and_uses(
54         &self,
55         local: Local,
56         body: &mut BodyAndCache<'tcx>,
57         new_local: Local,
58         tcx: TyCtxt<'tcx>,
59     ) {
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]);
68         }
69     }
70
71     // FIXME(pcwalton): this should update the def-use chains.
72     pub fn replace_all_defs_and_uses_with(
73         &self,
74         local: Local,
75         body: &mut BodyAndCache<'tcx>,
76         new_local: Local,
77         tcx: TyCtxt<'tcx>,
78     ) {
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, &local: &Local, context: PlaceContext, location: Location) {
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 {
95             info.defs_and_uses.push(Use { context, location });
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;
104     }
105 }
106
107 impl Info {
108     fn new() -> Info {
109         Info { defs_and_uses: vec![], var_debug_info_indices: vec![] }
110     }
111
112     fn clear(&mut self) {
113         self.defs_and_uses.clear();
114         self.var_debug_info_indices.clear();
115     }
116
117     pub fn def_count(&self) -> usize {
118         self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
119     }
120
121     pub fn def_count_not_including_drop(&self) -> usize {
122         self.defs_not_including_drop().count()
123     }
124
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())
129     }
130
131     pub fn use_count(&self) -> usize {
132         self.defs_and_uses.iter().filter(|place_use| place_use.context.is_nonmutating_use()).count()
133     }
134 }
135
136 struct MutateUseVisitor<'tcx> {
137     query: Local,
138     new_local: Local,
139     tcx: TyCtxt<'tcx>,
140 }
141
142 impl MutateUseVisitor<'tcx> {
143     fn new(query: Local, new_local: Local, tcx: TyCtxt<'tcx>) -> MutateUseVisitor<'tcx> {
144         MutateUseVisitor { query, new_local, tcx }
145     }
146 }
147
148 impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
149     fn tcx(&self) -> TyCtxt<'tcx> {
150         self.tcx
151     }
152
153     fn visit_local(&mut self, local: &mut Local, _context: PlaceContext, _location: Location) {
154         if *local == self.query {
155             *local = self.new_local;
156         }
157     }
158 }