From 1d737fb032b762e69e8d809c0e042d45e08b457d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 12 Feb 2020 13:41:26 -0800 Subject: [PATCH] Use `MaybeBorrowedLocals` for generator analyses It should have the same semantics as `HaveBeenBorrowedLocals` --- .../dataflow/impls/storage_liveness.rs | 46 ++++++++----------- src/librustc_mir/transform/generator.rs | 20 +++----- 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 040c13e8210..7508d71945e 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -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>>, + borrowed_locals: RefCell>, } 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, 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, 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, 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>>, + borrowed_locals: &'a RefCell>, sets: &'a mut GenKillSet, } @@ -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); } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index a6fc6573178..cd00274afcc 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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()); }