From ce3f37b42ba25ab6fe2f401135be847a0351fbbe Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 20 Jan 2020 15:14:24 -0800 Subject: [PATCH] Use new dataflow interface for initialization/borrows analyses --- src/librustc_mir/dataflow/impls/borrows.rs | 90 ++++--- src/librustc_mir/dataflow/impls/mod.rs | 263 +++++++++++++-------- 2 files changed, 220 insertions(+), 133 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index f94ee67f2bea..151ae28bae25 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -10,7 +10,8 @@ use crate::borrow_check::{ places_conflict, BorrowData, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, }; -use crate::dataflow::{BitDenotation, BottomValue, GenKillSet}; +use crate::dataflow::generic::{self, GenKill}; +use crate::dataflow::BottomValue; use std::rc::Rc; @@ -172,7 +173,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location( &self, - trans: &mut GenKillSet, + trans: &mut impl GenKill, location: Location, ) { // NOTE: The state associated with a given `location` @@ -187,16 +188,21 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // region, then setting that gen-bit will override any // potential kill introduced here. if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { - trans.kill_all(indices); + trans.kill_all(indices.iter().copied()); } } /// Kill any borrows that conflict with `place`. - fn kill_borrows_on_place(&self, trans: &mut GenKillSet, place: &Place<'tcx>) { + fn kill_borrows_on_place(&self, trans: &mut impl GenKill, place: &Place<'tcx>) { debug!("kill_borrows_on_place: place={:?}", place); - let other_borrows_of_local = - self.borrow_set.local_map.get(&place.local).into_iter().flat_map(|bs| bs.into_iter()); + let other_borrows_of_local = self + .borrow_set + .local_map + .get(&place.local) + .into_iter() + .flat_map(|bs| bs.into_iter()) + .copied(); // If the borrowed place is a local with no projections, all other borrows of this // local must conflict. This is purely an optimization so we don't have to call @@ -212,7 +218,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // pair of array indices are unequal, so that when `places_conflict` returns true, we // will be assured that two places being compared definitely denotes the same sets of // locations. - let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| { + let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { places_conflict( self.tcx, self.body, @@ -226,36 +232,41 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } } -impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { +impl<'tcx> generic::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { type Idx = BorrowIndex; - fn name() -> &'static str { - "borrows" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "borrows"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.borrow_set.borrows.len() * 2 } - fn start_block_effect(&self, _entry_set: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet) { // no borrows of code region_scopes have been taken prior to // function execution, so this method has no effect. } - fn before_statement_effect(&self, trans: &mut GenKillSet, location: Location) { - debug!("Borrows::before_statement_effect trans: {:?} location: {:?}", trans, location); + fn pretty_print_idx(&self, w: &mut impl std::io::Write, idx: Self::Idx) -> std::io::Result<()> { + write!(w, "{:?}", self.location(idx)) + } +} + +impl<'tcx> generic::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { + fn before_statement_effect( + &self, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { self.kill_loans_out_of_scope_at_location(trans, location); } - fn statement_effect(&self, trans: &mut GenKillSet, location: Location) { - debug!("Borrows::statement_effect: trans={:?} location={:?}", trans, location); - - let block = &self.body.basic_blocks().get(location.block).unwrap_or_else(|| { - panic!("could not find block at location {:?}", location); - }); - let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| { - panic!("could not find statement at location {:?}"); - }); - - debug!("Borrows::statement_effect: stmt={:?}", stmt); + fn statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + location: Location, + ) { match stmt.kind { mir::StatementKind::Assign(box (ref lhs, ref rhs)) => { if let mir::Rvalue::Ref(_, _, ref place) = *rhs { @@ -301,18 +312,29 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { } } - fn before_terminator_effect(&self, trans: &mut GenKillSet, location: Location) { - debug!("Borrows::before_terminator_effect: trans={:?} location={:?}", trans, location); + fn before_terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { self.kill_loans_out_of_scope_at_location(trans, location); } - fn terminator_effect(&self, _: &mut GenKillSet, _: Location) {} - - fn propagate_call_return( + fn terminator_effect( &self, - _in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + _: &mut impl GenKill, + _: &mir::Terminator<'tcx>, + _: Location, + ) { + } + + fn call_return_effect( + &self, + _trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], _dest_place: &mir::Place<'tcx>, ) { } diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 6b66406338d1..5b2264c2a652 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -11,8 +11,9 @@ use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; +use super::generic::{AnalysisDomain, GenKill, GenKillAnalysis}; use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex}; -use super::{BitDenotation, BottomValue, GenKillSet}; +use super::{BottomValue, GenKillSet}; use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; @@ -216,6 +217,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// } /// ``` pub struct EverInitializedPlaces<'a, 'tcx> { + #[allow(dead_code)] tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>, @@ -235,7 +237,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut GenKillSet, + trans: &mut impl GenKill, path: MovePathIndex, state: DropFlagState, ) { @@ -248,7 +250,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut GenKillSet, + trans: &mut impl GenKill, path: MovePathIndex, state: DropFlagState, ) { @@ -261,7 +263,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut GenKillSet, + trans: &mut impl GenKill, path: MovePathIndex, state: DropFlagState, ) { @@ -272,39 +274,56 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } } -impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; - fn name() -> &'static str { - "maybe_init" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "maybe_init"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().move_paths.len() } - fn start_block_effect(&self, entry_set: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet) { drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - entry_set.insert(path); + state.insert(path); }); } - fn statement_effect(&self, trans: &mut GenKillSet, location: Location) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) + fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { + write!(w, "{}", self.move_data().move_paths[mpi]) } +} - fn terminator_effect(&self, trans: &mut GenKillSet, location: Location) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn propagate_call_return( +impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + fn statement_effect( &self, - in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], dest_place: &mir::Place<'tcx>, ) { // when a call returns successfully, that means we need to set @@ -315,50 +334,67 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(dest_place.as_ref()), |mpi| { - in_out.insert(mpi); + trans.gen(mpi); }, ); } } -impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; - fn name() -> &'static str { - "maybe_uninit" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "maybe_uninit"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().move_paths.len() } // sets on_entry bits for Arg places - fn start_block_effect(&self, entry_set: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet) { // set all bits to 1 (uninit) before gathering counterevidence - assert!(self.bits_per_block() == entry_set.domain_size()); - entry_set.insert_all(); + assert!(self.bits_per_block(body) == state.domain_size()); + state.insert_all(); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - entry_set.remove(path); + state.remove(path); }); } - fn statement_effect(&self, trans: &mut GenKillSet, location: Location) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) + fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { + write!(w, "{}", self.move_data().move_paths[mpi]) } +} - fn terminator_effect(&self, trans: &mut GenKillSet, location: Location) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn propagate_call_return( +impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + fn statement_effect( &self, - in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], dest_place: &mir::Place<'tcx>, ) { // when a call returns successfully, that means we need to set @@ -369,48 +405,65 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(dest_place.as_ref()), |mpi| { - in_out.remove(mpi); + trans.kill(mpi); }, ); } } -impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { +impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { type Idx = MovePathIndex; - fn name() -> &'static str { - "definite_init" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "definite_init"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().move_paths.len() } // sets on_entry bits for Arg places - fn start_block_effect(&self, entry_set: &mut BitSet) { - entry_set.clear(); + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet) { + state.clear(); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - entry_set.insert(path); + state.insert(path); }); } - fn statement_effect(&self, trans: &mut GenKillSet, location: Location) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) + fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { + write!(w, "{}", self.move_data().move_paths[mpi]) } +} - fn terminator_effect(&self, trans: &mut GenKillSet, location: Location) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn propagate_call_return( +impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { + fn statement_effect( &self, - in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], dest_place: &mir::Place<'tcx>, ) { // when a call returns successfully, that means we need to set @@ -421,30 +474,36 @@ impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(dest_place.as_ref()), |mpi| { - in_out.insert(mpi); + trans.gen(mpi); }, ); } } -impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { type Idx = InitIndex; - fn name() -> &'static str { - "ever_init" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "ever_init"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().inits.len() } - fn start_block_effect(&self, entry_set: &mut BitSet) { - for arg_init in 0..self.body.arg_count { - entry_set.insert(InitIndex::new(arg_init)); + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet) { + for arg_init in 0..body.arg_count { + state.insert(InitIndex::new(arg_init)); } } +} - fn statement_effect(&self, trans: &mut GenKillSet, location: Location) { - let (_, body, move_data) = (self.tcx, self.body, self.move_data()); - let stmt = &body[location.block].statements[location.statement_index]; +impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { + fn statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + location: Location, + ) { + let move_data = self.move_data(); let init_path_map = &move_data.init_path_map; let init_loc_map = &move_data.init_loc_map; let rev_lookup = &move_data.rev_lookup; @@ -453,7 +512,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { "statement {:?} at loc {:?} initializes move_indexes {:?}", stmt, location, &init_loc_map[location] ); - trans.gen_all(&init_loc_map[location]); + trans.gen_all(init_loc_map[location].iter().copied()); match stmt.kind { mir::StatementKind::StorageDead(local) => { @@ -464,13 +523,18 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { "stmt {:?} at loc {:?} clears the ever initialized status of {:?}", stmt, location, &init_path_map[move_path_index] ); - trans.kill_all(&init_path_map[move_path_index]); + trans.kill_all(init_path_map[move_path_index].iter().copied()); } _ => {} } } - fn terminator_effect(&self, trans: &mut GenKillSet, location: Location) { + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { let (body, move_data) = (self.body, self.move_data()); let term = body[location.block].terminator(); let init_loc_map = &move_data.init_loc_map; @@ -479,28 +543,29 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { term, location, &init_loc_map[location] ); trans.gen_all( - init_loc_map[location].iter().filter(|init_index| { - move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly - }), + init_loc_map[location] + .iter() + .filter(|init_index| { + move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly + }) + .copied(), ); } - fn propagate_call_return( + fn call_return_effect( &self, - in_out: &mut BitSet, - call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill, + block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], _dest_place: &mir::Place<'tcx>, ) { let move_data = self.move_data(); - let bits_per_block = self.bits_per_block(); let init_loc_map = &move_data.init_loc_map; - let call_loc = - Location { block: call_bb, statement_index: self.body[call_bb].statements.len() }; + let call_loc = self.body.terminator_loc(block); for init_index in &init_loc_map[call_loc] { - assert!(init_index.index() < bits_per_block); - in_out.insert(*init_index); + trans.gen(*init_index); } } }