Skip to content

Commit 880646c

Browse files
committed
Auto merge of rust-lang#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
2 parents 4008dd8 + 26d153a commit 880646c

File tree

7 files changed

+47
-15
lines changed

7 files changed

+47
-15
lines changed

compiler/rustc_middle/src/mir/mod.rs

+35-9
Original file line numberDiff line numberDiff line change
@@ -357,21 +357,15 @@ impl<'tcx> Body<'tcx> {
357357
//
358358
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
359359
// invalidate the caches.
360-
self.predecessor_cache.invalidate();
361-
self.switch_source_cache.invalidate();
362-
self.is_cyclic.invalidate();
363-
self.postorder_cache.invalidate();
360+
self.invalidate_cfg_cache();
364361
&mut self.basic_blocks
365362
}
366363

367364
#[inline]
368365
pub fn basic_blocks_and_local_decls_mut(
369366
&mut self,
370367
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
371-
self.predecessor_cache.invalidate();
372-
self.switch_source_cache.invalidate();
373-
self.is_cyclic.invalidate();
374-
self.postorder_cache.invalidate();
368+
self.invalidate_cfg_cache();
375369
(&mut self.basic_blocks, &mut self.local_decls)
376370
}
377371

@@ -383,11 +377,43 @@ impl<'tcx> Body<'tcx> {
383377
&mut LocalDecls<'tcx>,
384378
&mut Vec<VarDebugInfo<'tcx>>,
385379
) {
380+
self.invalidate_cfg_cache();
381+
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
382+
}
383+
384+
/// Get mutable access to parts of the Body without invalidating the CFG cache.
385+
///
386+
/// By calling this method instead of eg [`Body::basic_blocks_mut`], you promise not to change
387+
/// the CFG. This means that
388+
///
389+
/// 1) The number of basic blocks remains unchanged
390+
/// 2) The set of successors of each terminator remains unchanged.
391+
/// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
392+
/// kind is not changed.
393+
///
394+
/// If any of these conditions cannot be upheld, you should call [`Body::invalidate_cfg_cache`].
395+
#[inline]
396+
pub fn basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate(
397+
&mut self,
398+
) -> (
399+
&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
400+
&mut LocalDecls<'tcx>,
401+
&mut Vec<VarDebugInfo<'tcx>>,
402+
) {
403+
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
404+
}
405+
406+
/// Invalidates cached information about the CFG.
407+
///
408+
/// You will only ever need this if you have also called
409+
/// [`Body::basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate`]. All other methods
410+
/// that allow you to mutate the body also call this method themselves, thereby avoiding any
411+
/// risk of accidentaly cache invalidation.
412+
pub fn invalidate_cfg_cache(&mut self) {
386413
self.predecessor_cache.invalidate();
387414
self.switch_source_cache.invalidate();
388415
self.is_cyclic.invalidate();
389416
self.postorder_cache.invalidate();
390-
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
391417
}
392418

393419
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the

compiler/rustc_mir_transform/src/dead_store_elimination.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
6666
return;
6767
}
6868

69-
let bbs = body.basic_blocks_mut();
69+
let bbs = body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0;
7070
for Location { block, statement_index } in patch {
7171
bbs[block].statements[statement_index].make_nop();
7272
}

compiler/rustc_mir_transform/src/deaggregator.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
1111
}
1212

1313
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
14-
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
14+
let (basic_blocks, local_decls, _) =
15+
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
1516
let local_decls = &*local_decls;
1617
for bb in basic_blocks {
1718
bb.expand_statements(|stmt| {

compiler/rustc_mir_transform/src/lower_slice_len.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
2626
return;
2727
};
2828

29-
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
29+
// The one successor remains unchanged, so no need to invalidate
30+
let (basic_blocks, local_decls, _) =
31+
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
3032

3133
for block in basic_blocks {
3234
// lower `<[_]>::len` calls

compiler/rustc_mir_transform/src/normalize_array_len.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
3232
}
3333

3434
pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
35-
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
35+
// We don't ever touch terminators, so no need to invalidate the CFG cache
36+
let (basic_blocks, local_decls, _) =
37+
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
3638

3739
// do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]`
3840
let mut interesting_locals = BitSet::new_empty(local_decls.len());

compiler/rustc_mir_transform/src/remove_storage_markers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
1717
}
1818

1919
trace!("Running RemoveStorageMarkers on {:?}", body.source);
20-
for data in body.basic_blocks_mut() {
20+
for data in body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0 {
2121
data.statements.retain(|statement| match statement.kind {
2222
StatementKind::StorageLive(..)
2323
| StatementKind::StorageDead(..)

compiler/rustc_mir_transform/src/remove_zsts.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
1818
return;
1919
}
2020
let param_env = tcx.param_env(body.source.def_id());
21-
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
21+
let (basic_blocks, local_decls, _) =
22+
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
2223
for block in basic_blocks.iter_mut() {
2324
for statement in block.statements.iter_mut() {
2425
if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =

0 commit comments

Comments
 (0)