]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/impls/storage_liveness.rs
Auto merge of #64432 - gnzlbg:simplify_truncate, r=alexcrichton
[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: &'mir Body<'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: &'mir Body<'tcx>,
86         borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>,
87     ) -> Self {
88         RequiresStorage {
89             body,
90             borrowed_locals: RefCell::new(DataflowResultsCursor::new(borrowed_locals, body)),
91         }
92     }
93
94     pub fn body(&self) -> &Body<'tcx> {
95         self.body
96     }
97 }
98
99 impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
100     type Idx = Local;
101     fn name() -> &'static str { "requires_storage" }
102     fn bits_per_block(&self) -> usize {
103         self.body.local_decls.len()
104     }
105
106     fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
107         // Nothing is live on function entry (generators only have a self
108         // argument, and we don't care about that)
109         assert_eq!(1, self.body.arg_count);
110     }
111
112     fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
113         // If we borrow or assign to a place then it needs storage for that
114         // statement.
115         self.check_for_borrow(sets, loc);
116
117         let stmt = &self.body[loc.block].statements[loc.statement_index];
118         match stmt.kind {
119             StatementKind::StorageDead(l) => sets.kill(l),
120             StatementKind::Assign(box(ref place, _))
121             | StatementKind::SetDiscriminant { box ref place, .. } => {
122                 if let PlaceBase::Local(local) = place.base {
123                     sets.gen(local);
124                 }
125             }
126             StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
127                 for p in &**outputs {
128                     if let PlaceBase::Local(local) = p.base {
129                         sets.gen(local);
130                     }
131                 }
132             }
133             _ => (),
134         }
135     }
136
137     fn statement_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
138         // If we move from a place then only stops needing storage *after*
139         // that statement.
140         self.check_for_move(sets, loc);
141     }
142
143     fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
144         self.check_for_borrow(sets, loc);
145
146         if let TerminatorKind::Call {
147             destination: Some((Place { base: PlaceBase::Local(local), .. }, _)),
148             ..
149         } = self.body[loc.block].terminator().kind {
150             sets.gen(local);
151         }
152     }
153
154     fn terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
155         // For call terminators the destination requires storage for the call
156         // and after the call returns successfully, but not after a panic.
157         // Since `propagate_call_unwind` doesn't exist, we have to kill the
158         // destination here, and then gen it again in `propagate_call_return`.
159         if let TerminatorKind::Call {
160             destination: Some((ref place, _)),
161             ..
162         } = self.body[loc.block].terminator().kind {
163             if let Some(local) = place.as_local() {
164                 sets.kill(local);
165             }
166         }
167         self.check_for_move(sets, loc);
168     }
169
170     fn propagate_call_return(
171         &self,
172         in_out: &mut BitSet<Local>,
173         _call_bb: mir::BasicBlock,
174         _dest_bb: mir::BasicBlock,
175         dest_place: &mir::Place<'tcx>,
176     ) {
177         if let PlaceBase::Local(local) = dest_place.base {
178             in_out.insert(local);
179         }
180     }
181 }
182
183 impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
184     /// Kill locals that are fully moved and have not been borrowed.
185     fn check_for_move(&self, sets: &mut GenKillSet<Local>, loc: Location) {
186         let mut visitor = MoveVisitor {
187             sets,
188             borrowed_locals: &self.borrowed_locals,
189         };
190         visitor.visit_location(self.body, loc);
191     }
192
193     /// Gen locals that are newly borrowed. This includes borrowing any part of
194     /// a local (we rely on this behavior of `HaveBeenBorrowedLocals`).
195     fn check_for_borrow(&self, sets: &mut GenKillSet<Local>, loc: Location) {
196         let mut borrowed_locals = self.borrowed_locals.borrow_mut();
197         borrowed_locals.seek(loc);
198         borrowed_locals.each_gen_bit(|l| sets.gen(l));
199     }
200 }
201
202 impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
203     /// bottom = dead
204     const BOTTOM_VALUE: bool = false;
205 }
206
207 struct MoveVisitor<'a, 'mir, 'tcx> {
208     borrowed_locals:
209         &'a RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
210     sets: &'a mut GenKillSet<Local>,
211 }
212
213 impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> {
214     fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
215         if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
216             let mut borrowed_locals = self.borrowed_locals.borrow_mut();
217             borrowed_locals.seek(loc);
218             if !borrowed_locals.contains(*local) {
219                 self.sets.kill(*local);
220             }
221         }
222     }
223 }