Use MaybeBorrowedLocals
for generator analyses
It should have the same semantics as `HaveBeenBorrowedLocals`
This commit is contained in:
parent
9972502baf
commit
1d737fb032
2 changed files with 27 additions and 39 deletions
|
@ -1,8 +1,8 @@
|
|||
pub use super::*;
|
||||
|
||||
use crate::dataflow::generic::{Results, ResultsRefCursor};
|
||||
use crate::dataflow::BitDenotation;
|
||||
use crate::dataflow::HaveBeenBorrowedLocals;
|
||||
use crate::dataflow::{DataflowResults, DataflowResultsCursor, DataflowResultsRefCursor};
|
||||
use crate::dataflow::MaybeBorrowedLocals;
|
||||
use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc::mir::*;
|
||||
use std::cell::RefCell;
|
||||
|
@ -69,22 +69,23 @@ impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> {
|
|||
const BOTTOM_VALUE: bool = false;
|
||||
}
|
||||
|
||||
type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
|
||||
|
||||
/// Dataflow analysis that determines whether each local requires storage at a
|
||||
/// given location; i.e. whether its storage can go away without being observed.
|
||||
pub struct RequiresStorage<'mir, 'tcx> {
|
||||
body: ReadOnlyBodyAndCache<'mir, 'tcx>,
|
||||
borrowed_locals:
|
||||
RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
|
||||
borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
|
||||
pub fn new(
|
||||
body: ReadOnlyBodyAndCache<'mir, 'tcx>,
|
||||
borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>,
|
||||
borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
|
||||
) -> Self {
|
||||
RequiresStorage {
|
||||
body,
|
||||
borrowed_locals: RefCell::new(DataflowResultsCursor::new(borrowed_locals, *body)),
|
||||
borrowed_locals: RefCell::new(ResultsRefCursor::new(*body, borrowed_locals)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,11 +112,12 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
|
||||
// If we borrow or assign to a place then it needs storage for that
|
||||
// statement.
|
||||
self.check_for_borrow(sets, loc);
|
||||
|
||||
let stmt = &self.body[loc.block].statements[loc.statement_index];
|
||||
|
||||
// If a place is borrowed in a statement, it needs storage for that statement.
|
||||
self.borrowed_locals.borrow().analysis().statement_effect(sets, stmt, loc);
|
||||
|
||||
// If a place is assigned to in a statement, it needs storage for that statement.
|
||||
match stmt.kind {
|
||||
StatementKind::StorageDead(l) => sets.kill(l),
|
||||
StatementKind::Assign(box (ref place, _))
|
||||
|
@ -138,12 +140,13 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
|
||||
self.check_for_borrow(sets, loc);
|
||||
let terminator = self.body[loc.block].terminator();
|
||||
|
||||
if let TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } =
|
||||
self.body[loc.block].terminator().kind
|
||||
{
|
||||
sets.gen(local);
|
||||
// If a place is borrowed in a terminator, it needs storage for that terminator.
|
||||
self.borrowed_locals.borrow().analysis().terminator_effect(sets, terminator, loc);
|
||||
|
||||
if let TerminatorKind::Call { destination: Some((place, _)), .. } = terminator.kind {
|
||||
sets.gen(place.local);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,14 +182,6 @@ impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
|
|||
let mut visitor = MoveVisitor { sets, borrowed_locals: &self.borrowed_locals };
|
||||
visitor.visit_location(self.body, loc);
|
||||
}
|
||||
|
||||
/// Gen locals that are newly borrowed. This includes borrowing any part of
|
||||
/// a local (we rely on this behavior of `HaveBeenBorrowedLocals`).
|
||||
fn check_for_borrow(&self, sets: &mut GenKillSet<Local>, loc: Location) {
|
||||
let mut borrowed_locals = self.borrowed_locals.borrow_mut();
|
||||
borrowed_locals.seek(loc);
|
||||
borrowed_locals.each_gen_bit(|l| sets.gen(l));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
|
||||
|
@ -195,8 +190,7 @@ impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
struct MoveVisitor<'a, 'mir, 'tcx> {
|
||||
borrowed_locals:
|
||||
&'a RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
|
||||
borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
|
||||
sets: &'a mut GenKillSet<Local>,
|
||||
}
|
||||
|
||||
|
@ -204,7 +198,7 @@ impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> {
|
|||
fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
|
||||
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
|
||||
let mut borrowed_locals = self.borrowed_locals.borrow_mut();
|
||||
borrowed_locals.seek(loc);
|
||||
borrowed_locals.seek_before(loc);
|
||||
if !borrowed_locals.contains(*local) {
|
||||
self.sets.kill(*local);
|
||||
}
|
||||
|
|
|
@ -49,9 +49,10 @@
|
|||
//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
|
||||
//! Otherwise it drops all the values in scope at the last suspension point.
|
||||
|
||||
use crate::dataflow::generic::{Analysis, ResultsCursor};
|
||||
use crate::dataflow::{do_dataflow, DataflowResultsCursor, DebugFormatted};
|
||||
use crate::dataflow::{DataflowResults, DataflowResultsConsumer, FlowAtLocation};
|
||||
use crate::dataflow::{HaveBeenBorrowedLocals, MaybeStorageLive, RequiresStorage};
|
||||
use crate::dataflow::{MaybeBorrowedLocals, MaybeStorageLive, RequiresStorage};
|
||||
use crate::transform::no_landing_pads::no_landing_pads;
|
||||
use crate::transform::simplify;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
@ -471,17 +472,10 @@ fn locals_live_across_suspend_points(
|
|||
|
||||
// Calculate the MIR locals which have been previously
|
||||
// borrowed (even if they are still active).
|
||||
let borrowed_locals_analysis = HaveBeenBorrowedLocals::new(body_ref);
|
||||
let borrowed_locals_results = do_dataflow(
|
||||
tcx,
|
||||
body_ref,
|
||||
def_id,
|
||||
&[],
|
||||
&dead_unwinds,
|
||||
borrowed_locals_analysis,
|
||||
|bd, p| DebugFormatted::new(&bd.body().local_decls[p]),
|
||||
);
|
||||
let mut borrowed_locals_cursor = DataflowResultsCursor::new(&borrowed_locals_results, body_ref);
|
||||
let borrowed_locals_results =
|
||||
MaybeBorrowedLocals::new().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint();
|
||||
|
||||
let mut borrowed_locals_cursor = ResultsCursor::new(body_ref, &borrowed_locals_results);
|
||||
|
||||
// Calculate the MIR locals that we actually need to keep storage around
|
||||
// for.
|
||||
|
@ -521,7 +515,7 @@ fn locals_live_across_suspend_points(
|
|||
// If a borrow is converted to a raw reference, we must also assume that it lives
|
||||
// forever. Note that the final liveness is still bounded by the storage liveness
|
||||
// of the local, which happens using the `intersect` operation below.
|
||||
borrowed_locals_cursor.seek(loc);
|
||||
borrowed_locals_cursor.seek_before(loc);
|
||||
liveness.outs[block].union(borrowed_locals_cursor.get());
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue