]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
1 | //! Def-use analysis. |
2 | ||
ea8adc8c | 3 | use rustc::mir::{Local, Location, Mir}; |
ff7c6d11 | 4 | use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; |
c30ab7b3 | 5 | use rustc_data_structures::indexed_vec::IndexVec; |
9e0c209e SL |
6 | use std::marker::PhantomData; |
7 | use std::mem; | |
abe05a73 XL |
8 | use std::slice; |
9 | use std::iter; | |
9e0c209e SL |
10 | |
11 | pub struct DefUseAnalysis<'tcx> { | |
12 | info: IndexVec<Local, Info<'tcx>>, | |
9e0c209e SL |
13 | } |
14 | ||
15 | #[derive(Clone)] | |
16 | pub struct Info<'tcx> { | |
17 | pub defs_and_uses: Vec<Use<'tcx>>, | |
18 | } | |
19 | ||
20 | #[derive(Clone)] | |
21 | pub struct Use<'tcx> { | |
ff7c6d11 | 22 | pub context: PlaceContext<'tcx>, |
9e0c209e SL |
23 | pub location: Location, |
24 | } | |
25 | ||
26 | impl<'tcx> DefUseAnalysis<'tcx> { | |
27 | pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { | |
28 | DefUseAnalysis { | |
c30ab7b3 | 29 | info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()), |
9e0c209e SL |
30 | } |
31 | } | |
32 | ||
33 | pub fn analyze(&mut self, mir: &Mir<'tcx>) { | |
abe05a73 XL |
34 | self.clear(); |
35 | ||
9e0c209e SL |
36 | let mut finder = DefUseFinder { |
37 | info: mem::replace(&mut self.info, IndexVec::new()), | |
9e0c209e SL |
38 | }; |
39 | finder.visit_mir(mir); | |
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 | ||
9e0c209e SL |
49 | pub fn local_info(&self, local: Local) -> &Info<'tcx> { |
50 | &self.info[local] | |
51 | } | |
52 | ||
9e0c209e | 53 | fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F) |
ea8adc8c | 54 | where F: for<'a> FnMut(&'a mut Local, |
ff7c6d11 | 55 | PlaceContext<'tcx>, |
9e0c209e | 56 | Location) { |
ff7c6d11 | 57 | for place_use in &self.info[local].defs_and_uses { |
9e0c209e SL |
58 | MutateUseVisitor::new(local, |
59 | &mut callback, | |
ff7c6d11 | 60 | mir).visit_location(mir, 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, | |
67 | mir: &mut Mir<'tcx>, | |
ea8adc8c XL |
68 | new_local: Local) { |
69 | self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local) | |
9e0c209e SL |
70 | } |
71 | } | |
72 | ||
73 | struct DefUseFinder<'tcx> { | |
74 | info: IndexVec<Local, Info<'tcx>>, | |
9e0c209e SL |
75 | } |
76 | ||
9e0c209e | 77 | impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> { |
ea8adc8c XL |
78 | fn visit_local(&mut self, |
79 | &local: &Local, | |
ff7c6d11 | 80 | context: PlaceContext<'tcx>, |
ea8adc8c XL |
81 | location: Location) { |
82 | self.info[local].defs_and_uses.push(Use { | |
83 | context, | |
84 | location, | |
85 | }); | |
9e0c209e SL |
86 | } |
87 | } | |
88 | ||
89 | impl<'tcx> Info<'tcx> { | |
90 | fn new() -> Info<'tcx> { | |
91 | Info { | |
92 | defs_and_uses: vec![], | |
93 | } | |
94 | } | |
95 | ||
abe05a73 XL |
96 | fn clear(&mut self) { |
97 | self.defs_and_uses.clear(); | |
98 | } | |
99 | ||
9e0c209e | 100 | pub fn def_count(&self) -> usize { |
ff7c6d11 | 101 | self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count() |
9e0c209e SL |
102 | } |
103 | ||
104 | pub fn def_count_not_including_drop(&self) -> usize { | |
abe05a73 XL |
105 | self.defs_not_including_drop().count() |
106 | } | |
107 | ||
108 | pub fn defs_not_including_drop( | |
109 | &self, | |
9fa01778 | 110 | ) -> iter::Filter<slice::Iter<'_, Use<'tcx>>, fn(&&Use<'tcx>) -> bool> { |
ff7c6d11 XL |
111 | self.defs_and_uses.iter().filter(|place_use| { |
112 | place_use.context.is_mutating_use() && !place_use.context.is_drop() | |
abe05a73 | 113 | }) |
9e0c209e SL |
114 | } |
115 | ||
116 | pub fn use_count(&self) -> usize { | |
ff7c6d11 XL |
117 | self.defs_and_uses.iter().filter(|place_use| { |
118 | place_use.context.is_nonmutating_use() | |
9e0c209e SL |
119 | }).count() |
120 | } | |
121 | } | |
122 | ||
123 | struct MutateUseVisitor<'tcx, F> { | |
124 | query: Local, | |
125 | callback: F, | |
9e0c209e SL |
126 | phantom: PhantomData<&'tcx ()>, |
127 | } | |
128 | ||
129 | impl<'tcx, F> MutateUseVisitor<'tcx, F> { | |
c30ab7b3 | 130 | fn new(query: Local, callback: F, _: &Mir<'tcx>) |
9e0c209e | 131 | -> MutateUseVisitor<'tcx, F> |
ff7c6d11 | 132 | where F: for<'a> FnMut(&'a mut Local, PlaceContext<'tcx>, Location) { |
9e0c209e | 133 | MutateUseVisitor { |
3b2f2976 XL |
134 | query, |
135 | callback, | |
9e0c209e SL |
136 | phantom: PhantomData, |
137 | } | |
138 | } | |
139 | } | |
140 | ||
141 | impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F> | |
ff7c6d11 | 142 | where F: for<'a> FnMut(&'a mut Local, PlaceContext<'tcx>, Location) { |
ea8adc8c XL |
143 | fn visit_local(&mut self, |
144 | local: &mut Local, | |
ff7c6d11 | 145 | context: PlaceContext<'tcx>, |
9e0c209e | 146 | location: Location) { |
ea8adc8c XL |
147 | if *local == self.query { |
148 | (self.callback)(local, context, location) | |
9e0c209e SL |
149 | } |
150 | } | |
151 | } |