]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_mir_dataflow / src / impls / storage_liveness.rs
CommitLineData
ea8adc8c
XL
1pub use super::*;
2
a2a8927a 3use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
ba9703b0
XL
4use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
5use rustc_middle::mir::*;
9c376795 6use std::borrow::Cow;
dfeec247 7use std::cell::RefCell;
ea8adc8c 8
ba9703b0 9#[derive(Clone)]
9c376795
FG
10pub struct MaybeStorageLive<'a> {
11 always_live_locals: Cow<'a, BitSet<Local>>,
ba9703b0
XL
12}
13
9c376795
FG
14impl<'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 20impl<'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 42impl<'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
77type 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 81pub struct MaybeRequiresStorage<'mir, 'tcx> {
f9f354fc 82 body: &'mir Body<'tcx>,
74b04a01 83 borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
dc9dc135
XL
84}
85
74b04a01 86impl<'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 98impl<'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 117impl<'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 275impl<'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
283struct MoveVisitor<'a, 'mir, 'tcx, T> {
284 borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
285 trans: &'a mut T,
dc9dc135
XL
286}
287
74b04a01
XL
288impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
289where
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}