-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Mir predecessors cache invalidate on terminators #64841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
187cd2a
948328a
bea419e
e20d1f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,6 @@ use rustc_data_structures::graph::dominators::{dominators, Dominators}; | |
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; | ||
use rustc_data_structures::indexed_vec::{Idx, IndexVec}; | ||
use rustc_data_structures::sync::Lrc; | ||
use rustc_data_structures::sync::MappedReadGuard; | ||
use rustc_macros::HashStable; | ||
use rustc_serialize::{Encodable, Decodable}; | ||
use smallvec::SmallVec; | ||
|
@@ -42,7 +41,6 @@ use syntax_pos::{Span, DUMMY_SP}; | |
|
||
pub use crate::mir::interpret::AssertMessage; | ||
|
||
mod cache; | ||
pub mod interpret; | ||
pub mod mono; | ||
pub mod tcx; | ||
|
@@ -162,7 +160,7 @@ pub struct Body<'tcx> { | |
pub span: Span, | ||
|
||
/// A cache for various calculations. | ||
cache: cache::Cache, | ||
predecessors_cache: Option<IndexVec<BasicBlock, Vec<BasicBlock>>>, | ||
} | ||
|
||
impl<'tcx> Body<'tcx> { | ||
|
@@ -200,7 +198,7 @@ impl<'tcx> Body<'tcx> { | |
__upvar_debuginfo_codegen_only_do_not_use, | ||
spread_arg: None, | ||
span, | ||
cache: cache::Cache::new(), | ||
predecessors_cache: None, | ||
control_flow_destroyed, | ||
} | ||
} | ||
|
@@ -212,26 +210,73 @@ impl<'tcx> Body<'tcx> { | |
|
||
#[inline] | ||
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { | ||
self.cache.invalidate(); | ||
&mut self.basic_blocks | ||
} | ||
|
||
pub fn basic_block_terminator_opt_mut(&mut self, bb: BasicBlock) -> &mut Option<Terminator<'tcx>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this could just be called |
||
self.predecessors_cache = None; | ||
&mut self.basic_blocks[bb].terminator | ||
} | ||
|
||
pub fn basic_block_terminator_mut(&mut self, bb: BasicBlock) -> &mut Terminator<'tcx> { | ||
self.predecessors_cache = None; | ||
/* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was my first attempt at "smart" invalidation, though I doubted it quickly after writing it. I don't get the feeling that this will be faster than just wiping the whole cache since the recreation still has to re-walk everything. Maybe if we have a way to mark some basic blocks as "dirty" then the recreation could be faster. I'll either update this or remove it before moving the PR out of draft. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should be doing smart invalidation for now. We can leave that to the user and make them choose the appropriate function for their use case (thus not invalidating so much) |
||
let data = &mut self.basic_blocks[bb]; | ||
if let Some(cache) = self.predecessors_cache.as_mut() { | ||
for successor in data.terminator().successors() { | ||
let successor_vec = &mut cache[*successor]; | ||
for i in (0..successor_vec.len()).rev() { | ||
if successor_vec[i] == bb { | ||
successor_vec.swap_remove(i); | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
*/ | ||
|
||
self.basic_blocks[bb].terminator_mut() | ||
} | ||
|
||
#[inline] | ||
pub fn basic_blocks_and_local_decls_mut( | ||
&mut self, | ||
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { | ||
self.cache.invalidate(); | ||
(&mut self.basic_blocks, &mut self.local_decls) | ||
} | ||
|
||
#[inline] | ||
pub fn predecessors(&self) -> MappedReadGuard<'_, IndexVec<BasicBlock, Vec<BasicBlock>>> { | ||
self.cache.predecessors(self) | ||
pub fn unwrap_predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> { | ||
assert!(self.predecessors_cache.is_some()); | ||
self.predecessors_cache.as_ref().unwrap() | ||
} | ||
|
||
#[inline] | ||
pub fn predecessors_for(&self, bb: BasicBlock) -> MappedReadGuard<'_, Vec<BasicBlock>> { | ||
MappedReadGuard::map(self.predecessors(), |p| &p[bb]) | ||
pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> { | ||
if self.predecessors_cache.is_none() { | ||
self.predecessors_cache = Some(self.calculate_predecessors()) | ||
} | ||
|
||
self.predecessors_cache.as_ref().unwrap() | ||
} | ||
|
||
fn calculate_predecessors(&self) -> IndexVec<BasicBlock, Vec<BasicBlock>> { | ||
let mut result = IndexVec::from_elem(vec![], self.basic_blocks()); | ||
for (bb, data) in self.basic_blocks().iter_enumerated() { | ||
if let Some(ref term) = data.terminator { | ||
for &tgt in term.successors() { | ||
result[tgt].push(bb); | ||
} | ||
} | ||
} | ||
|
||
result | ||
} | ||
|
||
#[inline] | ||
pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] { | ||
// TODO(nashenas88) could this be predecessors sometimes too? | ||
&self.unwrap_predecessors()[bb] | ||
} | ||
|
||
#[inline] | ||
|
@@ -422,7 +467,7 @@ impl_stable_hash_for!(struct Body<'tcx> { | |
spread_arg, | ||
control_flow_destroyed, | ||
span, | ||
cache | ||
predecessors_cache | ||
}); | ||
|
||
impl<'tcx> Index<BasicBlock> for Body<'tcx> { | ||
|
@@ -1006,6 +1051,8 @@ impl BasicBlock { | |
} | ||
} | ||
|
||
CloneTypeFoldableAndLiftImpls!{ BasicBlock, } | ||
|
||
/////////////////////////////////////////////////////////////////////////// | ||
// BasicBlockData and Terminator | ||
|
||
|
@@ -1336,6 +1383,10 @@ impl<'tcx> BasicBlockData<'tcx> { | |
BasicBlockData { statements: vec![], terminator, is_cleanup: false } | ||
} | ||
|
||
pub fn terminator_opt(&self) -> &Option<Terminator<'tcx>> { | ||
&self.terminator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since I can't leave a comment outside of my changes... I really wanted to make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea, seems fine to makeit private and create a |
||
} | ||
|
||
/// Accessor for terminator. | ||
/// | ||
/// Terminator may not be None after construction of the basic block is complete. This accessor | ||
|
@@ -1344,10 +1395,17 @@ impl<'tcx> BasicBlockData<'tcx> { | |
self.terminator.as_ref().expect("invalid terminator state") | ||
} | ||
|
||
pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { | ||
// This cannot be public since changing the terminator will break the predecessors cache in Body | ||
// To do so outside of this module, use Body::basic_block_terminator_mut(BasicBlock) | ||
fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { | ||
self.terminator.as_mut().expect("invalid terminator state") | ||
} | ||
|
||
// This can be public since changing the kind will not break the predecessors cache in Body | ||
pub fn terminator_kind_mut(&mut self) -> &mut TerminatorKind<'tcx> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this safe to do? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
&mut self.terminator_mut().kind | ||
} | ||
|
||
pub fn retain_statements<F>(&mut self, mut f: F) | ||
where | ||
F: FnMut(&mut Statement<'_>) -> bool, | ||
|
@@ -2625,7 +2683,7 @@ impl<'tcx> graph::WithPredecessors for Body<'tcx> { | |
&self, | ||
node: Self::Node, | ||
) -> <Self as GraphPredecessors<'_>>::Iter { | ||
self.predecessors_for(node).clone().into_iter() | ||
self.predecessors_for(node).to_vec().into_iter() | ||
} | ||
} | ||
|
||
|
@@ -2685,13 +2743,13 @@ impl Location { | |
} | ||
|
||
// If we're in another block, then we want to check that block is a predecessor of `other`. | ||
let mut queue: Vec<BasicBlock> = body.predecessors_for(other.block).clone(); | ||
let mut queue: Vec<BasicBlock> = body.predecessors_for(other.block).to_vec(); | ||
let mut visited = FxHashSet::default(); | ||
|
||
while let Some(block) = queue.pop() { | ||
// If we haven't visited this block before, then make sure we visit it's predecessors. | ||
if visited.insert(block) { | ||
queue.append(&mut body.predecessors_for(block).clone()); | ||
queue.extend(body.predecessors_for(block).iter().cloned()); | ||
} else { | ||
continue; | ||
} | ||
|
@@ -2964,7 +3022,7 @@ BraceStructTypeFoldableImpl! { | |
spread_arg, | ||
control_flow_destroyed, | ||
span, | ||
cache, | ||
predecessors_cache, | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should still invalidate, or better not exist at all anymore