From cab8e355631abe19340cc3f59ba7681ca14313df Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 4 Jun 2023 21:48:17 +0200 Subject: [PATCH 1/3] Use the postorder cache in `traversal::postorder`. --- compiler/rustc_middle/src/mir/traversal.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 99ead14139aec..38a8eba568637 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -188,8 +188,11 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { } } -pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> { - Postorder::new(&body.basic_blocks, START_BLOCK) +pub type PostorderIter<'a, 'tcx: 'a> = + impl Iterator)> + ExactSizeIterator; + +pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> PostorderIter<'a, 'tcx> { + body.basic_blocks.postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb])) } impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { From de9e08a78b77912337a33408566885b1bacacb0e Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 4 Jun 2023 21:48:53 +0200 Subject: [PATCH 2/3] Use `traversal::{preorder, reachable_as_bitset}` from basic block cache This ensures that traversal does only have to be computed once per basic block setup. `reachable_as_bitset` was computed from `preorder`, so they are cached together. --- .../src/transform/validate.rs | 2 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 16 ++++++++ compiler/rustc_middle/src/mir/traversal.rs | 40 ++++++++++++------- .../src/framework/cursor.rs | 2 +- .../src/framework/graphviz.rs | 2 +- .../src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/simplify.rs | 2 +- 7 files changed, 46 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 3c350e25ba6ec..78be848f381e4 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -93,7 +93,7 @@ struct TypeChecker<'a, 'tcx> { param_env: ParamEnv<'tcx>, mir_phase: MirPhase, unwind_edge_count: usize, - reachable_blocks: BitSet, + reachable_blocks: &'a BitSet, storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>, place_cache: Vec>, value_cache: Vec, diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 9d70dbfa07221..79a4b9cb72d7e 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -6,10 +6,13 @@ use rustc_data_structures::graph; use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::OnceCell; +use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use smallvec::SmallVec; +use super::traversal::Preorder; + #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct BasicBlocks<'tcx> { basic_blocks: IndexVec>, @@ -26,6 +29,7 @@ struct Cache { predecessors: OnceCell, switch_sources: OnceCell, is_cyclic: OnceCell, + preorder: OnceCell<(Vec, BitSet)>, postorder: OnceCell>, dominators: OnceCell>, } @@ -70,6 +74,18 @@ impl<'tcx> BasicBlocks<'tcx> { }) } + /// Returns basic blocks in a preorder. + #[inline] + pub fn preorder_and_reachable_bitset(&self) -> (&[BasicBlock], &BitSet) { + let (preorder, reachable) = self.cache.preorder.get_or_init(|| { + let mut result = Vec::new(); + let mut preorder = Preorder::new(&self.basic_blocks, START_BLOCK); + result.extend(preorder.by_ref().map(|(bb, _)| bb)); + (result, preorder.into_visited()) + }); + (preorder, reachable) + } + /// `switch_sources()[&(target, switch)]` returns a list of switch /// values that lead to a `target` block from a `switch` block. #[inline] diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 38a8eba568637..fa92c96851c8b 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -22,27 +22,41 @@ use super::*; /// A preorder traversal of this graph is either `A B D C` or `A C D B` #[derive(Clone)] pub struct Preorder<'a, 'tcx> { - body: &'a Body<'tcx>, + basic_blocks: &'a IndexSlice>, visited: BitSet, worklist: Vec, root_is_start_block: bool, } impl<'a, 'tcx> Preorder<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> { + pub fn new( + basic_blocks: &'a IndexSlice>, + root: BasicBlock, + ) -> Preorder<'a, 'tcx> { let worklist = vec![root]; Preorder { - body, - visited: BitSet::new_empty(body.basic_blocks.len()), + basic_blocks, + visited: BitSet::new_empty(basic_blocks.len()), worklist, root_is_start_block: root == START_BLOCK, } } + + pub(super) fn into_visited(self) -> BitSet { + self.visited + } } -pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> { - Preorder::new(body, START_BLOCK) +pub type PreorderIter<'a, 'tcx: 'a> = + impl Iterator)> + ExactSizeIterator; + +pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> PreorderIter<'a, 'tcx> { + body.basic_blocks + .preorder_and_reachable_bitset() + .0 + .iter() + .map(|&bb| (bb, &body.basic_blocks[bb])) } impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { @@ -54,7 +68,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { continue; } - let data = &self.body[idx]; + let data = &self.basic_blocks[idx]; if let Some(ref term) = data.terminator { self.worklist.extend(term.successors()); @@ -68,7 +82,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { fn size_hint(&self) -> (usize, Option) { // All the blocks, minus the number of blocks we've visited. - let upper = self.body.basic_blocks.len() - self.visited.count(); + let upper = self.basic_blocks.len() - self.visited.count(); let lower = if self.root_is_start_block { // We will visit all remaining blocks exactly once. @@ -285,17 +299,13 @@ impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {} /// order. /// /// This is clearer than writing `preorder` in cases where the order doesn't matter. -pub fn reachable<'a, 'tcx>( - body: &'a Body<'tcx>, -) -> impl 'a + Iterator)> { +pub fn reachable<'a, 'tcx>(body: &'a Body<'tcx>) -> PreorderIter<'a, 'tcx> { preorder(body) } /// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`. -pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet { - let mut iter = preorder(body); - (&mut iter).for_each(drop); - iter.visited +pub fn reachable_as_bitset<'a>(body: &'a Body<'_>) -> &'a BitSet { + body.basic_blocks.preorder_and_reachable_bitset().1 } #[derive(Clone)] diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index f3b5544aa8b9d..33724a73fa1b0 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -62,7 +62,7 @@ where pos: CursorPosition::block_entry(mir::START_BLOCK), #[cfg(debug_assertions)] - reachable_blocks: mir::traversal::reachable_as_bitset(body), + reachable_blocks: mir::traversal::reachable_as_bitset(body).clone(), } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 707729f8f21b7..3ecc4cab1ed60 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -43,7 +43,7 @@ where A: Analysis<'tcx>, { pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self { - let reachable = mir::traversal::reachable_as_bitset(body); + let reachable = mir::traversal::reachable_as_bitset(body).clone(); Formatter { body, results, style, reachable } } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index fda0e1023f7c5..de0b83c8c4a1b 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -297,7 +297,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> { drop_flags: IndexVec>, patch: MirPatch<'tcx>, un_derefer: UnDerefer<'tcx>, - reachable: BitSet, + reachable: &'a BitSet, } impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index e59219321b7ff..53efcf24a9465 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -336,7 +336,7 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B } pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let reachable = traversal::reachable_as_bitset(body); + let reachable = traversal::reachable_as_bitset(body).clone(); let num_blocks = body.basic_blocks.len(); if num_blocks == reachable.count() { return; From 7fbc8d47e3f66190b9597b614093ad3acc9e3e2e Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 5 Jun 2023 07:39:14 +0200 Subject: [PATCH 3/3] Revert "Use `traversal::{preorder, reachable_as_bitset}` from basic block cache" This reverts commit de9e08a78b77912337a33408566885b1bacacb0e. --- .../src/transform/validate.rs | 2 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 16 -------- compiler/rustc_middle/src/mir/traversal.rs | 40 +++++++------------ .../src/framework/cursor.rs | 2 +- .../src/framework/graphviz.rs | 2 +- .../src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/simplify.rs | 2 +- 7 files changed, 20 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 78be848f381e4..3c350e25ba6ec 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -93,7 +93,7 @@ struct TypeChecker<'a, 'tcx> { param_env: ParamEnv<'tcx>, mir_phase: MirPhase, unwind_edge_count: usize, - reachable_blocks: &'a BitSet, + reachable_blocks: BitSet, storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>, place_cache: Vec>, value_cache: Vec, diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 79a4b9cb72d7e..9d70dbfa07221 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -6,13 +6,10 @@ use rustc_data_structures::graph; use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::OnceCell; -use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use smallvec::SmallVec; -use super::traversal::Preorder; - #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct BasicBlocks<'tcx> { basic_blocks: IndexVec>, @@ -29,7 +26,6 @@ struct Cache { predecessors: OnceCell, switch_sources: OnceCell, is_cyclic: OnceCell, - preorder: OnceCell<(Vec, BitSet)>, postorder: OnceCell>, dominators: OnceCell>, } @@ -74,18 +70,6 @@ impl<'tcx> BasicBlocks<'tcx> { }) } - /// Returns basic blocks in a preorder. - #[inline] - pub fn preorder_and_reachable_bitset(&self) -> (&[BasicBlock], &BitSet) { - let (preorder, reachable) = self.cache.preorder.get_or_init(|| { - let mut result = Vec::new(); - let mut preorder = Preorder::new(&self.basic_blocks, START_BLOCK); - result.extend(preorder.by_ref().map(|(bb, _)| bb)); - (result, preorder.into_visited()) - }); - (preorder, reachable) - } - /// `switch_sources()[&(target, switch)]` returns a list of switch /// values that lead to a `target` block from a `switch` block. #[inline] diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index fa92c96851c8b..38a8eba568637 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -22,41 +22,27 @@ use super::*; /// A preorder traversal of this graph is either `A B D C` or `A C D B` #[derive(Clone)] pub struct Preorder<'a, 'tcx> { - basic_blocks: &'a IndexSlice>, + body: &'a Body<'tcx>, visited: BitSet, worklist: Vec, root_is_start_block: bool, } impl<'a, 'tcx> Preorder<'a, 'tcx> { - pub fn new( - basic_blocks: &'a IndexSlice>, - root: BasicBlock, - ) -> Preorder<'a, 'tcx> { + pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> { let worklist = vec![root]; Preorder { - basic_blocks, - visited: BitSet::new_empty(basic_blocks.len()), + body, + visited: BitSet::new_empty(body.basic_blocks.len()), worklist, root_is_start_block: root == START_BLOCK, } } - - pub(super) fn into_visited(self) -> BitSet { - self.visited - } } -pub type PreorderIter<'a, 'tcx: 'a> = - impl Iterator)> + ExactSizeIterator; - -pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> PreorderIter<'a, 'tcx> { - body.basic_blocks - .preorder_and_reachable_bitset() - .0 - .iter() - .map(|&bb| (bb, &body.basic_blocks[bb])) +pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> { + Preorder::new(body, START_BLOCK) } impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { @@ -68,7 +54,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { continue; } - let data = &self.basic_blocks[idx]; + let data = &self.body[idx]; if let Some(ref term) = data.terminator { self.worklist.extend(term.successors()); @@ -82,7 +68,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { fn size_hint(&self) -> (usize, Option) { // All the blocks, minus the number of blocks we've visited. - let upper = self.basic_blocks.len() - self.visited.count(); + let upper = self.body.basic_blocks.len() - self.visited.count(); let lower = if self.root_is_start_block { // We will visit all remaining blocks exactly once. @@ -299,13 +285,17 @@ impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {} /// order. /// /// This is clearer than writing `preorder` in cases where the order doesn't matter. -pub fn reachable<'a, 'tcx>(body: &'a Body<'tcx>) -> PreorderIter<'a, 'tcx> { +pub fn reachable<'a, 'tcx>( + body: &'a Body<'tcx>, +) -> impl 'a + Iterator)> { preorder(body) } /// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`. -pub fn reachable_as_bitset<'a>(body: &'a Body<'_>) -> &'a BitSet { - body.basic_blocks.preorder_and_reachable_bitset().1 +pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet { + let mut iter = preorder(body); + (&mut iter).for_each(drop); + iter.visited } #[derive(Clone)] diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 33724a73fa1b0..f3b5544aa8b9d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -62,7 +62,7 @@ where pos: CursorPosition::block_entry(mir::START_BLOCK), #[cfg(debug_assertions)] - reachable_blocks: mir::traversal::reachable_as_bitset(body).clone(), + reachable_blocks: mir::traversal::reachable_as_bitset(body), } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 3ecc4cab1ed60..707729f8f21b7 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -43,7 +43,7 @@ where A: Analysis<'tcx>, { pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self { - let reachable = mir::traversal::reachable_as_bitset(body).clone(); + let reachable = mir::traversal::reachable_as_bitset(body); Formatter { body, results, style, reachable } } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index de0b83c8c4a1b..fda0e1023f7c5 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -297,7 +297,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> { drop_flags: IndexVec>, patch: MirPatch<'tcx>, un_derefer: UnDerefer<'tcx>, - reachable: &'a BitSet, + reachable: BitSet, } impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 53efcf24a9465..e59219321b7ff 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -336,7 +336,7 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B } pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let reachable = traversal::reachable_as_bitset(body).clone(); + let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks.len(); if num_blocks == reachable.count() { return;