]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/dataflow/impls/storage_liveness.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / src / librustc_mir / dataflow / impls / storage_liveness.rs
CommitLineData
ea8adc8c
XL
1pub use super::*;
2
74b04a01 3use crate::dataflow::BottomValue;
ba9703b0
XL
4use crate::dataflow::{self, GenKill, Results, ResultsRefCursor};
5use crate::util::storage::AlwaysLiveLocals;
6use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
7use rustc_middle::mir::*;
dfeec247 8use std::cell::RefCell;
ea8adc8c 9
ba9703b0
XL
10#[derive(Clone)]
11pub struct MaybeStorageLive {
12 always_live_locals: AlwaysLiveLocals,
13}
14
15impl MaybeStorageLive {
16 pub fn new(always_live_locals: AlwaysLiveLocals) -> Self {
17 MaybeStorageLive { always_live_locals }
18 }
19}
ea8adc8c 20
74b04a01
XL
21impl 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
42impl 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 77impl BottomValue for MaybeStorageLive {
dc9dc135
XL
78 /// bottom = dead
79 const BOTTOM_VALUE: bool = false;
80}
81
74b04a01
XL
82type 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 86pub struct MaybeRequiresStorage<'mir, 'tcx> {
f9f354fc 87 body: &'mir Body<'tcx>,
74b04a01 88 borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
dc9dc135
XL
89}
90
74b04a01 91impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
dc9dc135 92 pub fn new(
f9f354fc 93 body: &'mir Body<'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 103impl<'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
121impl<'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
f9f354fc
XL
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
74b04a01
XL
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 { .. }
f035d41b 210 | TerminatorKind::FalseEdge { .. }
74b04a01
XL
211 | TerminatorKind::FalseUnwind { .. }
212 | TerminatorKind::GeneratorDrop
213 | TerminatorKind::Goto { .. }
214 | TerminatorKind::Resume
215 | TerminatorKind::Return
216 | TerminatorKind::SwitchInt { .. }
217 | TerminatorKind::Unreachable => {}
e74abb32
XL
218 }
219 }
220
74b04a01
XL
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);
e74abb32 234 }
74b04a01
XL
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 { .. }
f035d41b 244 | TerminatorKind::FalseEdge { .. }
74b04a01
XL
245 | TerminatorKind::FalseUnwind { .. }
246 | TerminatorKind::GeneratorDrop
247 | TerminatorKind::Goto { .. }
f9f354fc 248 | TerminatorKind::InlineAsm { .. }
74b04a01
XL
249 | TerminatorKind::Resume
250 | TerminatorKind::Return
251 | TerminatorKind::SwitchInt { .. }
252 | TerminatorKind::Unreachable => {}
e74abb32 253 }
74b04a01
XL
254
255 self.check_for_move(trans, loc);
dc9dc135
XL
256 }
257
74b04a01 258 fn call_return_effect(
dc9dc135 259 &self,
74b04a01
XL
260 trans: &mut impl GenKill<Self::Idx>,
261 _block: BasicBlock,
262 _func: &mir::Operand<'tcx>,
263 _args: &[mir::Operand<'tcx>],
ba9703b0 264 return_place: mir::Place<'tcx>,
dc9dc135 265 ) {
74b04a01 266 trans.gen(return_place.local);
dc9dc135 267 }
ba9703b0
XL
268
269 fn yield_resume_effect(
270 &self,
f9f354fc 271 trans: &mut impl GenKill<Self::Idx>,
ba9703b0
XL
272 _resume_block: BasicBlock,
273 resume_place: mir::Place<'tcx>,
274 ) {
275 trans.gen(resume_place.local);
276 }
dc9dc135
XL
277}
278
74b04a01 279impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
dc9dc135 280 /// Kill locals that are fully moved and have not been borrowed.
74b04a01
XL
281 fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) {
282 let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals };
ba9703b0 283 visitor.visit_location(&self.body, loc);
dc9dc135 284 }
ea8adc8c
XL
285}
286
74b04a01 287impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> {
dc9dc135
XL
288 /// bottom = dead
289 const BOTTOM_VALUE: bool = false;
290}
291
74b04a01
XL
292struct MoveVisitor<'a, 'mir, 'tcx, T> {
293 borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
294 trans: &'a mut T,
dc9dc135
XL
295}
296
74b04a01
XL
297impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
298where
299 T: GenKill<Local>,
300{
dc9dc135
XL
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();
f9f354fc 304 borrowed_locals.seek_before_primary_effect(loc);
dc9dc135 305 if !borrowed_locals.contains(*local) {
74b04a01 306 self.trans.kill(*local);
dc9dc135
XL
307 }
308 }
ea8adc8c
XL
309 }
310}