|
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