Skip to content

Commit acc4be4

Browse files
committed
Cache MIR preorder traversal.
1 parent a857d06 commit acc4be4

2 files changed

Lines changed: 32 additions & 12 deletions

File tree

compiler/rustc_middle/src/mir/basic_blocks.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
88
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
99
use smallvec::SmallVec;
1010

11-
use crate::mir::traversal::Postorder;
11+
use crate::mir::traversal::{Postorder, Preorder};
1212
use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK};
1313

1414
#[derive(Clone, TyEncodable, TyDecodable, Debug, StableHash, TypeFoldable, TypeVisitable)]
@@ -24,6 +24,7 @@ type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
2424
#[derive(Clone, Default, Debug)]
2525
struct Cache {
2626
predecessors: OnceLock<Predecessors>,
27+
preorder: OnceLock<Vec<BasicBlock>>,
2728
reverse_postorder: OnceLock<Vec<BasicBlock>>,
2829
dominators: OnceLock<Dominators<BasicBlock>>,
2930
}
@@ -55,6 +56,18 @@ impl<'tcx> BasicBlocks<'tcx> {
5556
})
5657
}
5758

59+
/// Returns basic blocks in a preorder.
60+
///
61+
/// See [`traversal::preorder`]'s docs to learn what is preorder traversal.
62+
///
63+
/// [`traversal::preorder`]: crate::mir::traversal::preorder
64+
#[inline]
65+
pub fn preorder(&self) -> &[BasicBlock] {
66+
self.cache.preorder.get_or_init(|| {
67+
Preorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect()
68+
})
69+
}
70+
5871
/// Returns basic blocks in a reverse postorder.
5972
///
6073
/// See [`traversal::reverse_postorder`]'s docs to learn what is postorder traversal.

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)