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