Skip to content

Commit de9e08a

Browse files
committed
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.
1 parent cab8e35 commit de9e08a

File tree

7 files changed

+46
-20
lines changed

7 files changed

+46
-20
lines changed

compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ struct TypeChecker<'a, 'tcx> {
9393
param_env: ParamEnv<'tcx>,
9494
mir_phase: MirPhase,
9595
unwind_edge_count: usize,
96-
reachable_blocks: BitSet<BasicBlock>,
96+
reachable_blocks: &'a BitSet<BasicBlock>,
9797
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
9898
place_cache: Vec<PlaceRef<'tcx>>,
9999
value_cache: Vec<u128>,

compiler/rustc_middle/src/mir/basic_blocks.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ use rustc_data_structures::graph;
66
use rustc_data_structures::graph::dominators::{dominators, Dominators};
77
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
88
use rustc_data_structures::sync::OnceCell;
9+
use rustc_index::bit_set::BitSet;
910
use rustc_index::{IndexSlice, IndexVec};
1011
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
1112
use smallvec::SmallVec;
1213

14+
use super::traversal::Preorder;
15+
1316
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
1417
pub struct BasicBlocks<'tcx> {
1518
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
@@ -26,6 +29,7 @@ struct Cache {
2629
predecessors: OnceCell<Predecessors>,
2730
switch_sources: OnceCell<SwitchSources>,
2831
is_cyclic: OnceCell<bool>,
32+
preorder: OnceCell<(Vec<BasicBlock>, BitSet<BasicBlock>)>,
2933
postorder: OnceCell<Vec<BasicBlock>>,
3034
dominators: OnceCell<Dominators<BasicBlock>>,
3135
}
@@ -70,6 +74,18 @@ impl<'tcx> BasicBlocks<'tcx> {
7074
})
7175
}
7276

77+
/// Returns basic blocks in a preorder.
78+
#[inline]
79+
pub fn preorder_and_reachable_bitset(&self) -> (&[BasicBlock], &BitSet<BasicBlock>) {
80+
let (preorder, reachable) = self.cache.preorder.get_or_init(|| {
81+
let mut result = Vec::new();
82+
let mut preorder = Preorder::new(&self.basic_blocks, START_BLOCK);
83+
result.extend(preorder.by_ref().map(|(bb, _)| bb));
84+
(result, preorder.into_visited())
85+
});
86+
(preorder, reachable)
87+
}
88+
7389
/// `switch_sources()[&(target, switch)]` returns a list of switch
7490
/// values that lead to a `target` block from a `switch` block.
7591
#[inline]

compiler/rustc_middle/src/mir/traversal.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,41 @@ use super::*;
2222
/// A preorder traversal of this graph is either `A B D C` or `A C D B`
2323
#[derive(Clone)]
2424
pub struct Preorder<'a, 'tcx> {
25-
body: &'a Body<'tcx>,
25+
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
2626
visited: BitSet<BasicBlock>,
2727
worklist: Vec<BasicBlock>,
2828
root_is_start_block: bool,
2929
}
3030

3131
impl<'a, 'tcx> Preorder<'a, 'tcx> {
32-
pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> {
32+
pub fn new(
33+
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
34+
root: BasicBlock,
35+
) -> Preorder<'a, 'tcx> {
3336
let worklist = vec![root];
3437

3538
Preorder {
36-
body,
37-
visited: BitSet::new_empty(body.basic_blocks.len()),
39+
basic_blocks,
40+
visited: BitSet::new_empty(basic_blocks.len()),
3841
worklist,
3942
root_is_start_block: root == START_BLOCK,
4043
}
4144
}
45+
46+
pub(super) fn into_visited(self) -> BitSet<BasicBlock> {
47+
self.visited
48+
}
4249
}
4350

44-
pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> {
45-
Preorder::new(body, START_BLOCK)
51+
pub type PreorderIter<'a, 'tcx: 'a> =
52+
impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator;
53+
54+
pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> PreorderIter<'a, 'tcx> {
55+
body.basic_blocks
56+
.preorder_and_reachable_bitset()
57+
.0
58+
.iter()
59+
.map(|&bb| (bb, &body.basic_blocks[bb]))
4660
}
4761

4862
impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
@@ -54,7 +68,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
5468
continue;
5569
}
5670

57-
let data = &self.body[idx];
71+
let data = &self.basic_blocks[idx];
5872

5973
if let Some(ref term) = data.terminator {
6074
self.worklist.extend(term.successors());
@@ -68,7 +82,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
6882

6983
fn size_hint(&self) -> (usize, Option<usize>) {
7084
// All the blocks, minus the number of blocks we've visited.
71-
let upper = self.body.basic_blocks.len() - self.visited.count();
85+
let upper = self.basic_blocks.len() - self.visited.count();
7286

7387
let lower = if self.root_is_start_block {
7488
// We will visit all remaining blocks exactly once.
@@ -285,17 +299,13 @@ impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {}
285299
/// order.
286300
///
287301
/// This is clearer than writing `preorder` in cases where the order doesn't matter.
288-
pub fn reachable<'a, 'tcx>(
289-
body: &'a Body<'tcx>,
290-
) -> impl 'a + Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> {
302+
pub fn reachable<'a, 'tcx>(body: &'a Body<'tcx>) -> PreorderIter<'a, 'tcx> {
291303
preorder(body)
292304
}
293305

294306
/// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
295-
pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> {
296-
let mut iter = preorder(body);
297-
(&mut iter).for_each(drop);
298-
iter.visited
307+
pub fn reachable_as_bitset<'a>(body: &'a Body<'_>) -> &'a BitSet<BasicBlock> {
308+
body.basic_blocks.preorder_and_reachable_bitset().1
299309
}
300310

301311
#[derive(Clone)]

compiler/rustc_mir_dataflow/src/framework/cursor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ where
6262
pos: CursorPosition::block_entry(mir::START_BLOCK),
6363

6464
#[cfg(debug_assertions)]
65-
reachable_blocks: mir::traversal::reachable_as_bitset(body),
65+
reachable_blocks: mir::traversal::reachable_as_bitset(body).clone(),
6666
}
6767
}
6868

compiler/rustc_mir_dataflow/src/framework/graphviz.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ where
4343
A: Analysis<'tcx>,
4444
{
4545
pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self {
46-
let reachable = mir::traversal::reachable_as_bitset(body);
46+
let reachable = mir::traversal::reachable_as_bitset(body).clone();
4747
Formatter { body, results, style, reachable }
4848
}
4949
}

compiler/rustc_mir_transform/src/elaborate_drops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> {
297297
drop_flags: IndexVec<MovePathIndex, Option<Local>>,
298298
patch: MirPatch<'tcx>,
299299
un_derefer: UnDerefer<'tcx>,
300-
reachable: BitSet<BasicBlock>,
300+
reachable: &'a BitSet<BasicBlock>,
301301
}
302302

303303
impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {

compiler/rustc_mir_transform/src/simplify.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B
336336
}
337337

338338
pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
339-
let reachable = traversal::reachable_as_bitset(body);
339+
let reachable = traversal::reachable_as_bitset(body).clone();
340340
let num_blocks = body.basic_blocks.len();
341341
if num_blocks == reachable.count() {
342342
return;

0 commit comments

Comments
 (0)