Skip to content

Cache MIR preorder traversal. #142578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions compiler/rustc_middle/src/mir/basic_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use smallvec::SmallVec;

use crate::mir::traversal::Postorder;
use crate::mir::traversal::{Postorder, Preorder};
use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK, Terminator, TerminatorKind};

#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
Expand Down Expand Up @@ -42,6 +42,7 @@ pub enum SwitchTargetValue {
struct Cache {
predecessors: OnceLock<Predecessors>,
switch_sources: OnceLock<SwitchSources>,
preorder: OnceLock<Vec<BasicBlock>>,
reverse_postorder: OnceLock<Vec<BasicBlock>>,
dominators: OnceLock<Dominators<BasicBlock>>,
}
Expand Down Expand Up @@ -72,9 +73,21 @@ impl<'tcx> BasicBlocks<'tcx> {
})
}

/// Returns basic blocks in a preorder.
///
/// See [`traversal::preorder`]'s docs to learn what is preorder traversal.
///
/// [`traversal::preorder`]: crate::mir::traversal::preorder
#[inline]
pub fn preorder(&self) -> &[BasicBlock] {
self.cache.preorder.get_or_init(|| {
Preorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect()
})
}

/// Returns basic blocks in a reverse postorder.
///
/// See [`traversal::reverse_postorder`]'s docs to learn what is preorder traversal.
/// See [`traversal::reverse_postorder`]'s docs to learn what is postorder traversal.
///
/// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder
#[inline]
Expand Down
29 changes: 18 additions & 11 deletions compiler/rustc_middle/src/mir/traversal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@ 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>,
pub(crate) struct Preorder<'a, 'tcx> {
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
visited: DenseBitSet<BasicBlock>,
worklist: Vec<BasicBlock>,
}

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

Preorder { body, visited: DenseBitSet::new_empty(body.basic_blocks.len()), worklist }
Preorder { basic_blocks, visited: DenseBitSet::new_empty(basic_blocks.len()), worklist }
}
}

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

impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
Expand All @@ -52,7 +57,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());
Expand All @@ -69,7 +74,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
let lower = 0;

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

(lower, Some(upper))
}
Expand Down Expand Up @@ -251,9 +256,11 @@ pub fn reachable<'a, 'tcx>(

/// Returns a `DenseBitSet` containing all basic blocks reachable from the `START_BLOCK`.
pub fn reachable_as_bitset(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
let mut iter = preorder(body);
while let Some(_) = iter.next() {}
iter.visited
let mut reachable = DenseBitSet::new_empty(body.basic_blocks.len());
for &bb in body.basic_blocks.preorder() {
reachable.insert(bb);
}
reachable
}

/// Reverse postorder traversal of a graph.
Expand Down
Loading