Skip to content

Commit 2c59cbe

Browse files
committed
Auto merge of #142578 - cjgillot:cache-preorder, r=<try>
Cache MIR preorder traversal. r? `@ghost`
2 parents 915e535 + 8ab25fc commit 2c59cbe

File tree

3 files changed

+34
-13
lines changed

3 files changed

+34
-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
@@ -8,7 +8,7 @@ use rustc_macros::{HashStable, 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, HashStable, TypeFoldable, TypeVisitable)]
@@ -31,6 +31,7 @@ pub enum SwitchTargetValue {
3131
#[derive(Clone, Default, Debug)]
3232
struct Cache {
3333
predecessors: OnceLock<Predecessors>,
34+
preorder: OnceLock<Vec<BasicBlock>>,
3435
reverse_postorder: OnceLock<Vec<BasicBlock>>,
3536
dominators: OnceLock<Dominators<BasicBlock>>,
3637
}
@@ -61,9 +62,21 @@ impl<'tcx> BasicBlocks<'tcx> {
6162
})
6263
}
6364

65+
/// Returns basic blocks in a preorder.
66+
///
67+
/// See [`traversal::preorder`]'s docs to learn what is preorder traversal.
68+
///
69+
/// [`traversal::preorder`]: crate::mir::traversal::preorder
70+
#[inline]
71+
pub fn preorder(&self) -> &[BasicBlock] {
72+
self.cache.preorder.get_or_init(|| {
73+
Preorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect()
74+
})
75+
}
76+
6477
/// Returns basic blocks in a reverse postorder.
6578
///
66-
/// See [`traversal::reverse_postorder`]'s docs to learn what is preorder traversal.
79+
/// See [`traversal::reverse_postorder`]'s docs to learn what is postorder traversal.
6780
///
6881
/// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder
6982
#[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.

compiler/rustc_mir_transform/src/simplify.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
225225
current = target;
226226
}
227227
let last = current;
228+
*changed |= *start != last;
228229
*start = last;
229230
while let Some((current, mut terminator)) = terminators.pop() {
230231
let Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } = terminator

0 commit comments

Comments
 (0)