Auto merge of #98872 - JakobDegen:no-invalidate, r=davidtwco
Add method to mutate MIR body without invalidating CFG caches. In addition to adding this method, a handful of passes are updated to use it. There's still quite a few passes that could in principle make use of this as well, but do not at the moment because they use `VisitorMut` or `MirPatch`, which needs additional support for this. The method name is slightly unwieldy, but I don't expect anyone to be writing it a lot, and at least it says what it does. If anyone has a suggestion for a better name though, would be happy to rename. r? rust-lang/mir-opt
This commit is contained in:
commit
880646ca9c
7 changed files with 47 additions and 15 deletions
|
@ -357,10 +357,7 @@ impl<'tcx> Body<'tcx> {
|
||||||
//
|
//
|
||||||
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
|
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
|
||||||
// invalidate the caches.
|
// invalidate the caches.
|
||||||
self.predecessor_cache.invalidate();
|
self.invalidate_cfg_cache();
|
||||||
self.switch_source_cache.invalidate();
|
|
||||||
self.is_cyclic.invalidate();
|
|
||||||
self.postorder_cache.invalidate();
|
|
||||||
&mut self.basic_blocks
|
&mut self.basic_blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,10 +365,7 @@ impl<'tcx> Body<'tcx> {
|
||||||
pub fn basic_blocks_and_local_decls_mut(
|
pub fn basic_blocks_and_local_decls_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
|
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
|
||||||
self.predecessor_cache.invalidate();
|
self.invalidate_cfg_cache();
|
||||||
self.switch_source_cache.invalidate();
|
|
||||||
self.is_cyclic.invalidate();
|
|
||||||
self.postorder_cache.invalidate();
|
|
||||||
(&mut self.basic_blocks, &mut self.local_decls)
|
(&mut self.basic_blocks, &mut self.local_decls)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,11 +377,43 @@ impl<'tcx> Body<'tcx> {
|
||||||
&mut LocalDecls<'tcx>,
|
&mut LocalDecls<'tcx>,
|
||||||
&mut Vec<VarDebugInfo<'tcx>>,
|
&mut Vec<VarDebugInfo<'tcx>>,
|
||||||
) {
|
) {
|
||||||
|
self.invalidate_cfg_cache();
|
||||||
|
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable access to parts of the Body without invalidating the CFG cache.
|
||||||
|
///
|
||||||
|
/// By calling this method instead of eg [`Body::basic_blocks_mut`], you promise not to change
|
||||||
|
/// the CFG. This means that
|
||||||
|
///
|
||||||
|
/// 1) The number of basic blocks remains unchanged
|
||||||
|
/// 2) The set of successors of each terminator remains unchanged.
|
||||||
|
/// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
|
||||||
|
/// kind is not changed.
|
||||||
|
///
|
||||||
|
/// If any of these conditions cannot be upheld, you should call [`Body::invalidate_cfg_cache`].
|
||||||
|
#[inline]
|
||||||
|
pub fn basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate(
|
||||||
|
&mut self,
|
||||||
|
) -> (
|
||||||
|
&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||||
|
&mut LocalDecls<'tcx>,
|
||||||
|
&mut Vec<VarDebugInfo<'tcx>>,
|
||||||
|
) {
|
||||||
|
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidates cached information about the CFG.
|
||||||
|
///
|
||||||
|
/// You will only ever need this if you have also called
|
||||||
|
/// [`Body::basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate`]. All other methods
|
||||||
|
/// that allow you to mutate the body also call this method themselves, thereby avoiding any
|
||||||
|
/// risk of accidentaly cache invalidation.
|
||||||
|
pub fn invalidate_cfg_cache(&mut self) {
|
||||||
self.predecessor_cache.invalidate();
|
self.predecessor_cache.invalidate();
|
||||||
self.switch_source_cache.invalidate();
|
self.switch_source_cache.invalidate();
|
||||||
self.is_cyclic.invalidate();
|
self.is_cyclic.invalidate();
|
||||||
self.postorder_cache.invalidate();
|
self.postorder_cache.invalidate();
|
||||||
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
|
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bbs = body.basic_blocks_mut();
|
let bbs = body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0;
|
||||||
for Location { block, statement_index } in patch {
|
for Location { block, statement_index } in patch {
|
||||||
bbs[block].statements[statement_index].make_nop();
|
bbs[block].statements[statement_index].make_nop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
let (basic_blocks, local_decls, _) =
|
||||||
|
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||||
let local_decls = &*local_decls;
|
let local_decls = &*local_decls;
|
||||||
for bb in basic_blocks {
|
for bb in basic_blocks {
|
||||||
bb.expand_statements(|stmt| {
|
bb.expand_statements(|stmt| {
|
||||||
|
|
|
@ -26,7 +26,9 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
// The one successor remains unchanged, so no need to invalidate
|
||||||
|
let (basic_blocks, local_decls, _) =
|
||||||
|
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||||
|
|
||||||
for block in basic_blocks {
|
for block in basic_blocks {
|
||||||
// lower `<[_]>::len` calls
|
// lower `<[_]>::len` calls
|
||||||
|
|
|
@ -32,7 +32,9 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
// We don't ever touch terminators, so no need to invalidate the CFG cache
|
||||||
|
let (basic_blocks, local_decls, _) =
|
||||||
|
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||||
|
|
||||||
// do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]`
|
// do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]`
|
||||||
let mut interesting_locals = BitSet::new_empty(local_decls.len());
|
let mut interesting_locals = BitSet::new_empty(local_decls.len());
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Running RemoveStorageMarkers on {:?}", body.source);
|
trace!("Running RemoveStorageMarkers on {:?}", body.source);
|
||||||
for data in body.basic_blocks_mut() {
|
for data in body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0 {
|
||||||
data.statements.retain(|statement| match statement.kind {
|
data.statements.retain(|statement| match statement.kind {
|
||||||
StatementKind::StorageLive(..)
|
StatementKind::StorageLive(..)
|
||||||
| StatementKind::StorageDead(..)
|
| StatementKind::StorageDead(..)
|
||||||
|
|
|
@ -18,7 +18,8 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let param_env = tcx.param_env(body.source.def_id());
|
let param_env = tcx.param_env(body.source.def_id());
|
||||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
let (basic_blocks, local_decls, _) =
|
||||||
|
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||||
for block in basic_blocks.iter_mut() {
|
for block in basic_blocks.iter_mut() {
|
||||||
for statement in block.statements.iter_mut() {
|
for statement in block.statements.iter_mut() {
|
||||||
if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
|
if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue