]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/impls/storage_liveness.rs
Auto merge of #66821 - eddyb:global-trait-caching, r=nikomatsakis
[rust.git] / src / librustc_mir / dataflow / impls / storage_liveness.rs
1 pub use super::*;
2
3 use rustc::mir::*;
4 use rustc::mir::visit::{
5     PlaceContext, Visitor, NonMutatingUseContext,
6 };
7 use std::cell::RefCell;
8 use crate::dataflow::BitDenotation;
9 use crate::dataflow::HaveBeenBorrowedLocals;
10 use crate::dataflow::{DataflowResults, DataflowResultsCursor, DataflowResultsRefCursor};
11
12 #[derive(Copy, Clone)]
13 pub struct MaybeStorageLive<'a, 'tcx> {
14     body: &'a Body<'tcx>,
15 }
16
17 impl<'a, 'tcx> MaybeStorageLive<'a, 'tcx> {
18     pub fn new(body: &'a Body<'tcx>)
19                -> Self {
20         MaybeStorageLive { body }
21     }
22
23     pub fn body(&self) -> &Body<'tcx> {
24         self.body
25     }
26 }
27
28 impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
29     type Idx = Local;
30     fn name() -> &'static str { "maybe_storage_live" }
31     fn bits_per_block(&self) -> usize {
32         self.body.local_decls.len()
33     }
34
35     fn start_block_effect(&self, _on_entry: &mut BitSet<Local>) {
36         // Nothing is live on function entry (generators only have a self
37         // argument, and we don't care about that)
38         assert_eq!(1, self.body.arg_count);
39     }
40
41     fn statement_effect(&self,
42                         trans: &mut GenKillSet<Local>,
43                         loc: Location) {
44         let stmt = &self.body[loc.block].statements[loc.statement_index];
45
46         match stmt.kind {
47             StatementKind::StorageLive(l) => trans.gen(l),
48             StatementKind::StorageDead(l) => trans.kill(l),
49             _ => (),
50         }
51     }
52
53     fn terminator_effect(&self,
54                          _trans: &mut GenKillSet<Local>,
55                          _loc: Location) {
56         // Terminators have no effect
57     }
58
59     fn propagate_call_return(
60         &self,
61         _in_out: &mut BitSet<Local>,
62         _call_bb: mir::BasicBlock,
63         _dest_bb: mir::BasicBlock,
64         _dest_place: &mir::Place<'tcx>,
65     ) {
66         // Nothing to do when a call returns successfully
67     }
68 }
69
70 impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> {
71     /// bottom = dead
72     const BOTTOM_VALUE: bool = false;
73 }
74
75 /// Dataflow analysis that determines whether each local requires storage at a
76 /// given location; i.e. whether its storage can go away without being observed.
77 pub struct RequiresStorage<'mir, 'tcx> {
78     body: ReadOnlyBodyAndCache<'mir, 'tcx>,
79     borrowed_locals:
80         RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
81 }
82
83 impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
84     pub fn new(
85         body: ReadOnlyBodyAndCache<'mir, 'tcx>,
86         borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>,
87     ) -> Self {
88         RequiresStorage {
89             body,
90             borrowed_locals: RefCell::new(
91                 DataflowResultsCursor::new(borrowed_locals, *body)
92             ),
93         }
94     }
95
96     pub fn body(&self) -> &Body<'tcx> {
97         &self.body
98     }
99 }
100
101 impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
102     type Idx = Local;
103     fn name() -> &'static str { "requires_storage" }
104     fn bits_per_block(&self) -> usize {
105         self.body.local_decls.len()
106     }
107
108     fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
109         // Nothing is live on function entry (generators only have a self
110         // argument, and we don't care about that)
111         assert_eq!(1, self.body.arg_count);
112     }
113
114     fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
115         // If we borrow or assign to a place then it needs storage for that
116         // statement.
117         self.check_for_borrow(sets, loc);
118
119         let stmt = &self.body[loc.block].statements[loc.statement_index];
120         match stmt.kind {
121             StatementKind::StorageDead(l) => sets.kill(l),
122             StatementKind::Assign(box(ref place, _))
123             | StatementKind::SetDiscriminant { box ref place, .. } => {
124                 if let PlaceBase::Local(local) = place.base {
125                     sets.gen(local);
126                 }
127             }
128             StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
129                 for p in &**outputs {
130                     if let PlaceBase::Local(local) = p.base {
131                         sets.gen(local);
132                     }
133                 }
134             }
135             _ => (),
136         }
137     }
138
139     fn statement_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
140         // If we move from a place then only stops needing storage *after*
141         // that statement.
142         self.check_for_move(sets, loc);
143     }
144
145     fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
146         self.check_for_borrow(sets, loc);
147
148         if let TerminatorKind::Call {
149             destination: Some((Place { base: PlaceBase::Local(local), .. }, _)),
150             ..
151         } = self.body[loc.block].terminator().kind {
152             sets.gen(local);
153         }
154     }
155
156     fn terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
157         // For call terminators the destination requires storage for the call
158         // and after the call returns successfully, but not after a panic.
159         // Since `propagate_call_unwind` doesn't exist, we have to kill the
160         // destination here, and then gen it again in `propagate_call_return`.
161         if let TerminatorKind::Call {
162             destination: Some((ref place, _)),
163             ..
164         } = self.body[loc.block].terminator().kind {
165             if let Some(local) = place.as_local() {
166                 sets.kill(local);
167             }
168         }
169         self.check_for_move(sets, loc);
170     }
171
172     fn propagate_call_return(
173         &self,
174         in_out: &mut BitSet<Local>,
175         _call_bb: mir::BasicBlock,
176         _dest_bb: mir::BasicBlock,
177         dest_place: &mir::Place<'tcx>,
178     ) {
179         if let PlaceBase::Local(local) = dest_place.base {
180             in_out.insert(local);
181         }
182     }
183 }
184
185 impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
186     /// Kill locals that are fully moved and have not been borrowed.
187     fn check_for_move(&self, sets: &mut GenKillSet<Local>, loc: Location) {
188         let mut visitor = MoveVisitor {
189             sets,
190             borrowed_locals: &self.borrowed_locals,
191         };
192         visitor.visit_location(self.body, loc);
193     }
194
195     /// Gen locals that are newly borrowed. This includes borrowing any part of
196     /// a local (we rely on this behavior of `HaveBeenBorrowedLocals`).
197     fn check_for_borrow(&self, sets: &mut GenKillSet<Local>, loc: Location) {
198         let mut borrowed_locals = self.borrowed_locals.borrow_mut();
199         borrowed_locals.seek(loc);
200         borrowed_locals.each_gen_bit(|l| sets.gen(l));
201     }
202 }
203
204 impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
205     /// bottom = dead
206     const BOTTOM_VALUE: bool = false;
207 }
208
209 struct MoveVisitor<'a, 'mir, 'tcx> {
210     borrowed_locals:
211         &'a RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
212     sets: &'a mut GenKillSet<Local>,
213 }
214
215 impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> {
216     fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
217         if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
218             let mut borrowed_locals = self.borrowed_locals.borrow_mut();
219             borrowed_locals.seek(loc);
220             if !borrowed_locals.contains(*local) {
221                 self.sets.kill(*local);
222             }
223         }
224     }
225 }