Skip to content

Commit 3fd54d2

Browse files
committed
Cache MIR preorder traversal.
1 parent 75e7cf5 commit 3fd54d2

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

compiler/rustc_middle/src/mir/basic_blocks.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
99
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
1010
use smallvec::SmallVec;
1111

12-
use crate::mir::traversal::Postorder;
12+
use crate::mir::traversal::{Postorder, Preorder};
1313
use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK, Terminator, TerminatorKind};
1414

1515
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
@@ -42,6 +42,7 @@ pub enum SwitchTargetValue {
4242
struct Cache {
4343
predecessors: OnceLock<Predecessors>,
4444
switch_sources: OnceLock<SwitchSources>,
45+
preorder: OnceLock<Vec<BasicBlock>>,
4546
reverse_postorder: OnceLock<Vec<BasicBlock>>,
4647
dominators: OnceLock<Dominators<BasicBlock>>,
4748
}
@@ -72,9 +73,21 @@ impl<'tcx> BasicBlocks<'tcx> {
7273
})
7374
}
7475

76+
/// Returns basic blocks in a preorder.
77+
///
78+
/// See [`traversal::preorder`]'s docs to learn what is preorder traversal.
79+
///
80+
/// [`traversal::preorder`]: crate::mir::traversal::preorder
81+
#[inline]
82+
pub fn preorder(&self) -> &[BasicBlock] {
83+
self.cache.preorder.get_or_init(|| {
84+
Preorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect()
85+
})
86+
}
87+
7588
/// Returns basic blocks in a reverse postorder.
7689
///
77-
/// See [`traversal::reverse_postorder`]'s docs to learn what is preorder traversal.
90+
/// See [`traversal::reverse_postorder`]'s docs to learn what is postorder traversal.
7891
///
7992
/// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder
8093
#[inline]

compiler/rustc_middle/src/mir/traversal.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,20 @@ use super::*;
1919
///
2020
/// A preorder traversal of this graph is either `A B D C` or `A C D B`
2121
#[derive(Clone)]
22-
pub struct Preorder<'a, 'tcx> {
23-
body: &'a Body<'tcx>,
22+
pub(crate) struct Preorder<'a, 'tcx> {
23+
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
2424
visited: DenseBitSet<BasicBlock>,
2525
worklist: Vec<BasicBlock>,
2626
}
2727

2828
impl<'a, 'tcx> Preorder<'a, 'tcx> {
29-
pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> {
29+
pub(crate) fn new(
30+
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
31+
root: BasicBlock,
32+
) -> Preorder<'a, 'tcx> {
3033
let worklist = vec![root];
3134

32-
Preorder { body, visited: DenseBitSet::new_empty(body.basic_blocks.len()), worklist }
35+
Preorder { basic_blocks, visited: DenseBitSet::new_empty(basic_blocks.len()), worklist }
3336
}
3437
}
3538

@@ -39,8 +42,10 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> {
3942
/// returns basic blocks in a preorder.
4043
///
4144
/// See [`Preorder`]'s docs to learn what is preorder traversal.
42-
pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> {
43-
Preorder::new(body, START_BLOCK)
45+
pub fn preorder<'a, 'tcx>(
46+
body: &'a Body<'tcx>,
47+
) -> impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> {
48+
body.basic_blocks.preorder().iter().map(|&bb| (bb, &body.basic_blocks[bb]))
4449
}
4550

4651
impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
@@ -52,7 +57,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
5257
continue;
5358
}
5459

55-
let data = &self.body[idx];
60+
let data = &self.basic_blocks[idx];
5661

5762
if let Some(ref term) = data.terminator {
5863
self.worklist.extend(term.successors());
@@ -69,7 +74,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
6974
let lower = 0;
7075

7176
// This is extremely loose, but it's not worth a popcnt loop to do better.
72-
let upper = self.body.basic_blocks.len();
77+
let upper = self.basic_blocks.len();
7378

7479
(lower, Some(upper))
7580
}
@@ -251,9 +256,11 @@ pub fn reachable<'a, 'tcx>(
251256

252257
/// Returns a `DenseBitSet` containing all basic blocks reachable from the `START_BLOCK`.
253258
pub fn reachable_as_bitset(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
254-
let mut iter = preorder(body);
255-
while let Some(_) = iter.next() {}
256-
iter.visited
259+
let mut reachable = DenseBitSet::new_empty(body.basic_blocks.len());
260+
for &bb in body.basic_blocks.preorder() {
261+
reachable.insert(bb);
262+
}
263+
reachable
257264
}
258265

259266
/// Reverse postorder traversal of a graph.

0 commit comments

Comments
 (0)