]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | pub use super::*; |
2 | ||
74b04a01 | 3 | use crate::dataflow::BottomValue; |
ba9703b0 XL |
4 | use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; |
5 | use crate::util::storage::AlwaysLiveLocals; | |
6 | use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; | |
7 | use rustc_middle::mir::*; | |
dfeec247 | 8 | use std::cell::RefCell; |
ea8adc8c | 9 | |
ba9703b0 XL |
10 | #[derive(Clone)] |
11 | pub struct MaybeStorageLive { | |
12 | always_live_locals: AlwaysLiveLocals, | |
13 | } | |
14 | ||
15 | impl MaybeStorageLive { | |
16 | pub fn new(always_live_locals: AlwaysLiveLocals) -> Self { | |
17 | MaybeStorageLive { always_live_locals } | |
18 | } | |
19 | } | |
ea8adc8c | 20 | |
74b04a01 XL |
21 | impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive { |
22 | type Idx = Local; | |
ea8adc8c | 23 | |
74b04a01 | 24 | const NAME: &'static str = "maybe_storage_live"; |
ea8adc8c | 25 | |
74b04a01 XL |
26 | fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { |
27 | body.local_decls.len() | |
ea8adc8c XL |
28 | } |
29 | ||
74b04a01 | 30 | fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) { |
ba9703b0 XL |
31 | assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); |
32 | for local in self.always_live_locals.iter() { | |
33 | on_entry.insert(local); | |
34 | } | |
35 | ||
36 | for arg in body.args_iter() { | |
74b04a01 XL |
37 | on_entry.insert(arg); |
38 | } | |
ea8adc8c | 39 | } |
74b04a01 | 40 | } |
ea8adc8c | 41 | |
74b04a01 XL |
42 | impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive { |
43 | fn statement_effect( | |
44 | &self, | |
45 | trans: &mut impl GenKill<Self::Idx>, | |
46 | stmt: &mir::Statement<'tcx>, | |
47 | _: Location, | |
48 | ) { | |
ea8adc8c | 49 | match stmt.kind { |
dc9dc135 XL |
50 | StatementKind::StorageLive(l) => trans.gen(l), |
51 | StatementKind::StorageDead(l) => trans.kill(l), | |
ea8adc8c XL |
52 | _ => (), |
53 | } | |
54 | } | |
55 | ||
74b04a01 XL |
56 | fn terminator_effect( |
57 | &self, | |
58 | _trans: &mut impl GenKill<Self::Idx>, | |
59 | _: &mir::Terminator<'tcx>, | |
60 | _: Location, | |
61 | ) { | |
ea8adc8c XL |
62 | // Terminators have no effect |
63 | } | |
64 | ||
74b04a01 | 65 | fn call_return_effect( |
0731742a | 66 | &self, |
74b04a01 XL |
67 | _trans: &mut impl GenKill<Self::Idx>, |
68 | _block: BasicBlock, | |
69 | _func: &mir::Operand<'tcx>, | |
70 | _args: &[mir::Operand<'tcx>], | |
ba9703b0 | 71 | _return_place: mir::Place<'tcx>, |
0731742a | 72 | ) { |
ea8adc8c XL |
73 | // Nothing to do when a call returns successfully |
74 | } | |
75 | } | |
76 | ||
74b04a01 | 77 | impl BottomValue for MaybeStorageLive { |
dc9dc135 XL |
78 | /// bottom = dead |
79 | const BOTTOM_VALUE: bool = false; | |
80 | } | |
81 | ||
74b04a01 XL |
82 | type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; |
83 | ||
dc9dc135 XL |
84 | /// Dataflow analysis that determines whether each local requires storage at a |
85 | /// given location; i.e. whether its storage can go away without being observed. | |
74b04a01 | 86 | pub struct MaybeRequiresStorage<'mir, 'tcx> { |
60c5eb7d | 87 | body: ReadOnlyBodyAndCache<'mir, 'tcx>, |
74b04a01 | 88 | borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>, |
dc9dc135 XL |
89 | } |
90 | ||
74b04a01 | 91 | impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { |
dc9dc135 | 92 | pub fn new( |
60c5eb7d | 93 | body: ReadOnlyBodyAndCache<'mir, 'tcx>, |
74b04a01 | 94 | borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, |
dc9dc135 | 95 | ) -> Self { |
74b04a01 | 96 | MaybeRequiresStorage { |
dc9dc135 | 97 | body, |
ba9703b0 | 98 | borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)), |
dc9dc135 XL |
99 | } |
100 | } | |
dc9dc135 XL |
101 | } |
102 | ||
74b04a01 | 103 | impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { |
dc9dc135 | 104 | type Idx = Local; |
74b04a01 XL |
105 | |
106 | const NAME: &'static str = "requires_storage"; | |
107 | ||
108 | fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { | |
109 | body.local_decls.len() | |
dc9dc135 XL |
110 | } |
111 | ||
74b04a01 XL |
112 | fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) { |
113 | // The resume argument is live on function entry (we don't care about | |
114 | // the `self` argument) | |
115 | for arg in body.args_iter().skip(1) { | |
116 | on_entry.insert(arg); | |
117 | } | |
dc9dc135 | 118 | } |
74b04a01 | 119 | } |
dc9dc135 | 120 | |
74b04a01 XL |
121 | impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { |
122 | fn before_statement_effect( | |
123 | &self, | |
124 | trans: &mut impl GenKill<Self::Idx>, | |
125 | stmt: &mir::Statement<'tcx>, | |
126 | loc: Location, | |
127 | ) { | |
128 | // If a place is borrowed in a statement, it needs storage for that statement. | |
129 | self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc); | |
dc9dc135 | 130 | |
74b04a01 XL |
131 | match &stmt.kind { |
132 | StatementKind::StorageDead(l) => trans.kill(*l), | |
133 | ||
134 | // If a place is assigned to in a statement, it needs storage for that statement. | |
135 | StatementKind::Assign(box (place, _)) | |
136 | | StatementKind::SetDiscriminant { box place, .. } => { | |
137 | trans.gen(place.local); | |
dc9dc135 | 138 | } |
ba9703b0 | 139 | StatementKind::LlvmInlineAsm(asm) => { |
74b04a01 XL |
140 | for place in &*asm.outputs { |
141 | trans.gen(place.local); | |
dc9dc135 XL |
142 | } |
143 | } | |
74b04a01 XL |
144 | |
145 | // Nothing to do for these. Match exhaustively so this fails to compile when new | |
146 | // variants are added. | |
147 | StatementKind::AscribeUserType(..) | |
148 | | StatementKind::FakeRead(..) | |
149 | | StatementKind::Nop | |
150 | | StatementKind::Retag(..) | |
151 | | StatementKind::StorageLive(..) => {} | |
dc9dc135 XL |
152 | } |
153 | } | |
154 | ||
74b04a01 XL |
155 | fn statement_effect( |
156 | &self, | |
157 | trans: &mut impl GenKill<Self::Idx>, | |
158 | _: &mir::Statement<'tcx>, | |
159 | loc: Location, | |
160 | ) { | |
e74abb32 XL |
161 | // If we move from a place then only stops needing storage *after* |
162 | // that statement. | |
74b04a01 | 163 | self.check_for_move(trans, loc); |
e74abb32 XL |
164 | } |
165 | ||
74b04a01 XL |
166 | fn before_terminator_effect( |
167 | &self, | |
168 | trans: &mut impl GenKill<Self::Idx>, | |
169 | terminator: &mir::Terminator<'tcx>, | |
170 | loc: Location, | |
171 | ) { | |
172 | // If a place is borrowed in a terminator, it needs storage for that terminator. | |
173 | self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); | |
e74abb32 | 174 | |
74b04a01 | 175 | match &terminator.kind { |
ba9703b0 | 176 | TerminatorKind::Call { destination: Some((place, _)), .. } => { |
74b04a01 XL |
177 | trans.gen(place.local); |
178 | } | |
179 | ||
ba9703b0 XL |
180 | // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for |
181 | // that is that a `yield` will return from the function, and `resume_arg` is written | |
182 | // only when the generator is later resumed. Unlike `Call`, this doesn't require the | |
183 | // place to have storage *before* the yield, only after. | |
184 | TerminatorKind::Yield { .. } => {} | |
185 | ||
74b04a01 XL |
186 | // Nothing to do for these. Match exhaustively so this fails to compile when new |
187 | // variants are added. | |
188 | TerminatorKind::Call { destination: None, .. } | |
189 | | TerminatorKind::Abort | |
190 | | TerminatorKind::Assert { .. } | |
191 | | TerminatorKind::Drop { .. } | |
192 | | TerminatorKind::DropAndReplace { .. } | |
193 | | TerminatorKind::FalseEdges { .. } | |
194 | | TerminatorKind::FalseUnwind { .. } | |
195 | | TerminatorKind::GeneratorDrop | |
196 | | TerminatorKind::Goto { .. } | |
197 | | TerminatorKind::Resume | |
198 | | TerminatorKind::Return | |
199 | | TerminatorKind::SwitchInt { .. } | |
200 | | TerminatorKind::Unreachable => {} | |
e74abb32 XL |
201 | } |
202 | } | |
203 | ||
74b04a01 XL |
204 | fn terminator_effect( |
205 | &self, | |
206 | trans: &mut impl GenKill<Self::Idx>, | |
207 | terminator: &mir::Terminator<'tcx>, | |
208 | loc: Location, | |
209 | ) { | |
210 | match &terminator.kind { | |
211 | // For call terminators the destination requires storage for the call | |
212 | // and after the call returns successfully, but not after a panic. | |
213 | // Since `propagate_call_unwind` doesn't exist, we have to kill the | |
214 | // destination here, and then gen it again in `call_return_effect`. | |
215 | TerminatorKind::Call { destination: Some((place, _)), .. } => { | |
216 | trans.kill(place.local); | |
e74abb32 | 217 | } |
74b04a01 XL |
218 | |
219 | // Nothing to do for these. Match exhaustively so this fails to compile when new | |
220 | // variants are added. | |
221 | TerminatorKind::Call { destination: None, .. } | |
222 | | TerminatorKind::Yield { .. } | |
223 | | TerminatorKind::Abort | |
224 | | TerminatorKind::Assert { .. } | |
225 | | TerminatorKind::Drop { .. } | |
226 | | TerminatorKind::DropAndReplace { .. } | |
227 | | TerminatorKind::FalseEdges { .. } | |
228 | | TerminatorKind::FalseUnwind { .. } | |
229 | | TerminatorKind::GeneratorDrop | |
230 | | TerminatorKind::Goto { .. } | |
231 | | TerminatorKind::Resume | |
232 | | TerminatorKind::Return | |
233 | | TerminatorKind::SwitchInt { .. } | |
234 | | TerminatorKind::Unreachable => {} | |
e74abb32 | 235 | } |
74b04a01 XL |
236 | |
237 | self.check_for_move(trans, loc); | |
dc9dc135 XL |
238 | } |
239 | ||
74b04a01 | 240 | fn call_return_effect( |
dc9dc135 | 241 | &self, |
74b04a01 XL |
242 | trans: &mut impl GenKill<Self::Idx>, |
243 | _block: BasicBlock, | |
244 | _func: &mir::Operand<'tcx>, | |
245 | _args: &[mir::Operand<'tcx>], | |
ba9703b0 | 246 | return_place: mir::Place<'tcx>, |
dc9dc135 | 247 | ) { |
74b04a01 | 248 | trans.gen(return_place.local); |
dc9dc135 | 249 | } |
ba9703b0 XL |
250 | |
251 | fn yield_resume_effect( | |
252 | &self, | |
253 | trans: &mut BitSet<Self::Idx>, | |
254 | _resume_block: BasicBlock, | |
255 | resume_place: mir::Place<'tcx>, | |
256 | ) { | |
257 | trans.gen(resume_place.local); | |
258 | } | |
dc9dc135 XL |
259 | } |
260 | ||
74b04a01 | 261 | impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { |
dc9dc135 | 262 | /// Kill locals that are fully moved and have not been borrowed. |
74b04a01 XL |
263 | fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) { |
264 | let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; | |
ba9703b0 | 265 | visitor.visit_location(&self.body, loc); |
dc9dc135 | 266 | } |
ea8adc8c XL |
267 | } |
268 | ||
74b04a01 | 269 | impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { |
dc9dc135 XL |
270 | /// bottom = dead |
271 | const BOTTOM_VALUE: bool = false; | |
272 | } | |
273 | ||
74b04a01 XL |
274 | struct MoveVisitor<'a, 'mir, 'tcx, T> { |
275 | borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>, | |
276 | trans: &'a mut T, | |
dc9dc135 XL |
277 | } |
278 | ||
74b04a01 XL |
279 | impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> |
280 | where | |
281 | T: GenKill<Local>, | |
282 | { | |
dc9dc135 XL |
283 | fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { |
284 | if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { | |
285 | let mut borrowed_locals = self.borrowed_locals.borrow_mut(); | |
74b04a01 | 286 | borrowed_locals.seek_before(loc); |
dc9dc135 | 287 | if !borrowed_locals.contains(*local) { |
74b04a01 | 288 | self.trans.kill(*local); |
dc9dc135 XL |
289 | } |
290 | } | |
ea8adc8c XL |
291 | } |
292 | } |