]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Def-use analysis. | |
12 | ||
ea8adc8c | 13 | use rustc::mir::{Local, Location, Mir}; |
9e0c209e | 14 | use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; |
c30ab7b3 | 15 | use rustc_data_structures::indexed_vec::IndexVec; |
9e0c209e SL |
16 | use std::marker::PhantomData; |
17 | use std::mem; | |
abe05a73 XL |
18 | use std::slice; |
19 | use std::iter; | |
9e0c209e SL |
20 | |
21 | pub struct DefUseAnalysis<'tcx> { | |
22 | info: IndexVec<Local, Info<'tcx>>, | |
9e0c209e SL |
23 | } |
24 | ||
25 | #[derive(Clone)] | |
26 | pub struct Info<'tcx> { | |
27 | pub defs_and_uses: Vec<Use<'tcx>>, | |
28 | } | |
29 | ||
30 | #[derive(Clone)] | |
31 | pub struct Use<'tcx> { | |
32 | pub context: LvalueContext<'tcx>, | |
33 | pub location: Location, | |
34 | } | |
35 | ||
36 | impl<'tcx> DefUseAnalysis<'tcx> { | |
37 | pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { | |
38 | DefUseAnalysis { | |
c30ab7b3 | 39 | info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()), |
9e0c209e SL |
40 | } |
41 | } | |
42 | ||
43 | pub fn analyze(&mut self, mir: &Mir<'tcx>) { | |
abe05a73 XL |
44 | self.clear(); |
45 | ||
9e0c209e SL |
46 | let mut finder = DefUseFinder { |
47 | info: mem::replace(&mut self.info, IndexVec::new()), | |
9e0c209e SL |
48 | }; |
49 | finder.visit_mir(mir); | |
50 | self.info = finder.info | |
51 | } | |
52 | ||
abe05a73 XL |
53 | fn clear(&mut self) { |
54 | for info in &mut self.info { | |
55 | info.clear(); | |
56 | } | |
57 | } | |
58 | ||
9e0c209e SL |
59 | pub fn local_info(&self, local: Local) -> &Info<'tcx> { |
60 | &self.info[local] | |
61 | } | |
62 | ||
9e0c209e | 63 | fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F) |
ea8adc8c | 64 | where F: for<'a> FnMut(&'a mut Local, |
9e0c209e SL |
65 | LvalueContext<'tcx>, |
66 | Location) { | |
67 | for lvalue_use in &self.info[local].defs_and_uses { | |
68 | MutateUseVisitor::new(local, | |
69 | &mut callback, | |
9e0c209e SL |
70 | mir).visit_location(mir, lvalue_use.location) |
71 | } | |
72 | } | |
73 | ||
74 | /// FIXME(pcwalton): This should update the def-use chains. | |
75 | pub fn replace_all_defs_and_uses_with(&self, | |
76 | local: Local, | |
77 | mir: &mut Mir<'tcx>, | |
ea8adc8c XL |
78 | new_local: Local) { |
79 | self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local) | |
9e0c209e SL |
80 | } |
81 | } | |
82 | ||
83 | struct DefUseFinder<'tcx> { | |
84 | info: IndexVec<Local, Info<'tcx>>, | |
9e0c209e SL |
85 | } |
86 | ||
9e0c209e | 87 | impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> { |
ea8adc8c XL |
88 | fn visit_local(&mut self, |
89 | &local: &Local, | |
90 | context: LvalueContext<'tcx>, | |
91 | location: Location) { | |
92 | self.info[local].defs_and_uses.push(Use { | |
93 | context, | |
94 | location, | |
95 | }); | |
9e0c209e SL |
96 | } |
97 | } | |
98 | ||
99 | impl<'tcx> Info<'tcx> { | |
100 | fn new() -> Info<'tcx> { | |
101 | Info { | |
102 | defs_and_uses: vec![], | |
103 | } | |
104 | } | |
105 | ||
abe05a73 XL |
106 | fn clear(&mut self) { |
107 | self.defs_and_uses.clear(); | |
108 | } | |
109 | ||
9e0c209e SL |
110 | pub fn def_count(&self) -> usize { |
111 | self.defs_and_uses.iter().filter(|lvalue_use| lvalue_use.context.is_mutating_use()).count() | |
112 | } | |
113 | ||
114 | pub fn def_count_not_including_drop(&self) -> usize { | |
abe05a73 XL |
115 | self.defs_not_including_drop().count() |
116 | } | |
117 | ||
118 | pub fn defs_not_including_drop( | |
119 | &self, | |
120 | ) -> iter::Filter<slice::Iter<Use<'tcx>>, fn(&&Use<'tcx>) -> bool> { | |
9e0c209e SL |
121 | self.defs_and_uses.iter().filter(|lvalue_use| { |
122 | lvalue_use.context.is_mutating_use() && !lvalue_use.context.is_drop() | |
abe05a73 | 123 | }) |
9e0c209e SL |
124 | } |
125 | ||
126 | pub fn use_count(&self) -> usize { | |
127 | self.defs_and_uses.iter().filter(|lvalue_use| { | |
128 | lvalue_use.context.is_nonmutating_use() | |
129 | }).count() | |
130 | } | |
131 | } | |
132 | ||
133 | struct MutateUseVisitor<'tcx, F> { | |
134 | query: Local, | |
135 | callback: F, | |
9e0c209e SL |
136 | phantom: PhantomData<&'tcx ()>, |
137 | } | |
138 | ||
139 | impl<'tcx, F> MutateUseVisitor<'tcx, F> { | |
c30ab7b3 | 140 | fn new(query: Local, callback: F, _: &Mir<'tcx>) |
9e0c209e | 141 | -> MutateUseVisitor<'tcx, F> |
ea8adc8c | 142 | where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) { |
9e0c209e | 143 | MutateUseVisitor { |
3b2f2976 XL |
144 | query, |
145 | callback, | |
9e0c209e SL |
146 | phantom: PhantomData, |
147 | } | |
148 | } | |
149 | } | |
150 | ||
151 | impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F> | |
ea8adc8c XL |
152 | where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) { |
153 | fn visit_local(&mut self, | |
154 | local: &mut Local, | |
9e0c209e SL |
155 | context: LvalueContext<'tcx>, |
156 | location: Location) { | |
ea8adc8c XL |
157 | if *local == self.query { |
158 | (self.callback)(local, context, location) | |
9e0c209e SL |
159 | } |
160 | } | |
161 | } |