|
1 | 1 | pub use super::*;
|
2 | 2 |
|
3 | 3 | use crate::dataflow::BottomValue;
|
4 |
| -use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; |
| 4 | +use crate::dataflow::{self, GenKill}; |
5 | 5 | use crate::util::storage::AlwaysLiveLocals;
|
6 |
| -use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; |
7 | 6 | use rustc_middle::mir::*;
|
8 |
| -use std::cell::RefCell; |
9 | 7 |
|
10 | 8 | #[derive(Clone)]
|
11 | 9 | pub struct MaybeStorageLive {
|
@@ -78,233 +76,3 @@ impl BottomValue for MaybeStorageLive {
|
78 | 76 | /// bottom = dead
|
79 | 77 | const BOTTOM_VALUE: bool = false;
|
80 | 78 | }
|
81 |
| - |
82 |
| -type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; |
83 |
| - |
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. |
86 |
| -pub struct MaybeRequiresStorage<'mir, 'tcx> { |
87 |
| - body: &'mir Body<'tcx>, |
88 |
| - borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>, |
89 |
| -} |
90 |
| - |
91 |
| -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { |
92 |
| - pub fn new( |
93 |
| - body: &'mir Body<'tcx>, |
94 |
| - borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, |
95 |
| - ) -> Self { |
96 |
| - MaybeRequiresStorage { |
97 |
| - body, |
98 |
| - borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)), |
99 |
| - } |
100 |
| - } |
101 |
| -} |
102 |
| - |
103 |
| -impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { |
104 |
| - type Idx = Local; |
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() |
110 |
| - } |
111 |
| - |
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 |
| - } |
118 |
| - } |
119 |
| -} |
120 |
| - |
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); |
130 |
| - |
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); |
138 |
| - } |
139 |
| - StatementKind::LlvmInlineAsm(asm) => { |
140 |
| - for place in &*asm.outputs { |
141 |
| - trans.gen(place.local); |
142 |
| - } |
143 |
| - } |
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(..) => {} |
152 |
| - } |
153 |
| - } |
154 |
| - |
155 |
| - fn statement_effect( |
156 |
| - &self, |
157 |
| - trans: &mut impl GenKill<Self::Idx>, |
158 |
| - _: &mir::Statement<'tcx>, |
159 |
| - loc: Location, |
160 |
| - ) { |
161 |
| - // If we move from a place then only stops needing storage *after* |
162 |
| - // that statement. |
163 |
| - self.check_for_move(trans, loc); |
164 |
| - } |
165 |
| - |
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); |
174 |
| - |
175 |
| - match &terminator.kind { |
176 |
| - TerminatorKind::Call { destination: Some((place, _)), .. } => { |
177 |
| - trans.gen(place.local); |
178 |
| - } |
179 |
| - |
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 |
| - |
186 |
| - TerminatorKind::InlineAsm { operands, .. } => { |
187 |
| - for op in operands { |
188 |
| - match op { |
189 |
| - InlineAsmOperand::Out { place, .. } |
190 |
| - | InlineAsmOperand::InOut { out_place: place, .. } => { |
191 |
| - if let Some(place) = place { |
192 |
| - trans.gen(place.local); |
193 |
| - } |
194 |
| - } |
195 |
| - InlineAsmOperand::In { .. } |
196 |
| - | InlineAsmOperand::Const { .. } |
197 |
| - | InlineAsmOperand::SymFn { .. } |
198 |
| - | InlineAsmOperand::SymStatic { .. } => {} |
199 |
| - } |
200 |
| - } |
201 |
| - } |
202 |
| - |
203 |
| - // Nothing to do for these. Match exhaustively so this fails to compile when new |
204 |
| - // variants are added. |
205 |
| - TerminatorKind::Call { destination: None, .. } |
206 |
| - | TerminatorKind::Abort |
207 |
| - | TerminatorKind::Assert { .. } |
208 |
| - | TerminatorKind::Drop { .. } |
209 |
| - | TerminatorKind::DropAndReplace { .. } |
210 |
| - | TerminatorKind::FalseEdges { .. } |
211 |
| - | TerminatorKind::FalseUnwind { .. } |
212 |
| - | TerminatorKind::GeneratorDrop |
213 |
| - | TerminatorKind::Goto { .. } |
214 |
| - | TerminatorKind::Resume |
215 |
| - | TerminatorKind::Return |
216 |
| - | TerminatorKind::SwitchInt { .. } |
217 |
| - | TerminatorKind::Unreachable => {} |
218 |
| - } |
219 |
| - } |
220 |
| - |
221 |
| - fn terminator_effect( |
222 |
| - &self, |
223 |
| - trans: &mut impl GenKill<Self::Idx>, |
224 |
| - terminator: &mir::Terminator<'tcx>, |
225 |
| - loc: Location, |
226 |
| - ) { |
227 |
| - match &terminator.kind { |
228 |
| - // For call terminators the destination requires storage for the call |
229 |
| - // and after the call returns successfully, but not after a panic. |
230 |
| - // Since `propagate_call_unwind` doesn't exist, we have to kill the |
231 |
| - // destination here, and then gen it again in `call_return_effect`. |
232 |
| - TerminatorKind::Call { destination: Some((place, _)), .. } => { |
233 |
| - trans.kill(place.local); |
234 |
| - } |
235 |
| - |
236 |
| - // Nothing to do for these. Match exhaustively so this fails to compile when new |
237 |
| - // variants are added. |
238 |
| - TerminatorKind::Call { destination: None, .. } |
239 |
| - | TerminatorKind::Yield { .. } |
240 |
| - | TerminatorKind::Abort |
241 |
| - | TerminatorKind::Assert { .. } |
242 |
| - | TerminatorKind::Drop { .. } |
243 |
| - | TerminatorKind::DropAndReplace { .. } |
244 |
| - | TerminatorKind::FalseEdges { .. } |
245 |
| - | TerminatorKind::FalseUnwind { .. } |
246 |
| - | TerminatorKind::GeneratorDrop |
247 |
| - | TerminatorKind::Goto { .. } |
248 |
| - | TerminatorKind::InlineAsm { .. } |
249 |
| - | TerminatorKind::Resume |
250 |
| - | TerminatorKind::Return |
251 |
| - | TerminatorKind::SwitchInt { .. } |
252 |
| - | TerminatorKind::Unreachable => {} |
253 |
| - } |
254 |
| - |
255 |
| - self.check_for_move(trans, loc); |
256 |
| - } |
257 |
| - |
258 |
| - fn call_return_effect( |
259 |
| - &self, |
260 |
| - trans: &mut impl GenKill<Self::Idx>, |
261 |
| - _block: BasicBlock, |
262 |
| - _func: &mir::Operand<'tcx>, |
263 |
| - _args: &[mir::Operand<'tcx>], |
264 |
| - return_place: mir::Place<'tcx>, |
265 |
| - ) { |
266 |
| - trans.gen(return_place.local); |
267 |
| - } |
268 |
| - |
269 |
| - fn yield_resume_effect( |
270 |
| - &self, |
271 |
| - trans: &mut impl GenKill<Self::Idx>, |
272 |
| - _resume_block: BasicBlock, |
273 |
| - resume_place: mir::Place<'tcx>, |
274 |
| - ) { |
275 |
| - trans.gen(resume_place.local); |
276 |
| - } |
277 |
| -} |
278 |
| - |
279 |
| -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { |
280 |
| - /// Kill locals that are fully moved and have not been borrowed. |
281 |
| - fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) { |
282 |
| - let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; |
283 |
| - visitor.visit_location(&self.body, loc); |
284 |
| - } |
285 |
| -} |
286 |
| - |
287 |
| -impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { |
288 |
| - /// bottom = dead |
289 |
| - const BOTTOM_VALUE: bool = false; |
290 |
| -} |
291 |
| - |
292 |
| -struct MoveVisitor<'a, 'mir, 'tcx, T> { |
293 |
| - borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>, |
294 |
| - trans: &'a mut T, |
295 |
| -} |
296 |
| - |
297 |
| -impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> |
298 |
| -where |
299 |
| - T: GenKill<Local>, |
300 |
| -{ |
301 |
| - fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { |
302 |
| - if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { |
303 |
| - let mut borrowed_locals = self.borrowed_locals.borrow_mut(); |
304 |
| - borrowed_locals.seek_before_primary_effect(loc); |
305 |
| - if !borrowed_locals.contains(*local) { |
306 |
| - self.trans.kill(*local); |
307 |
| - } |
308 |
| - } |
309 |
| - } |
310 |
| -} |
0 commit comments