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