Skip to content

Commit

Permalink
Use traversal::{preorder, reachable_as_bitset} from basic block cache
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Noratrieb committed Jun 4, 2023
1 parent cab8e35 commit de9e08a
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 20 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ struct TypeChecker<'a, 'tcx> {
param_env: ParamEnv<'tcx>,
mir_phase: MirPhase,
unwind_edge_count: usize,
reachable_blocks: BitSet<BasicBlock>,
reachable_blocks: &'a BitSet<BasicBlock>,
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
place_cache: Vec<PlaceRef<'tcx>>,
value_cache: Vec<u128>,
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_middle/src/mir/basic_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ use rustc_data_structures::graph;
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::OnceCell;
use rustc_index::bit_set::BitSet;
use rustc_index::{IndexSlice, IndexVec};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use smallvec::SmallVec;

use super::traversal::Preorder;

#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct BasicBlocks<'tcx> {
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
Expand All @@ -26,6 +29,7 @@ struct Cache {
predecessors: OnceCell<Predecessors>,
switch_sources: OnceCell<SwitchSources>,
is_cyclic: OnceCell<bool>,
preorder: OnceCell<(Vec<BasicBlock>, BitSet<BasicBlock>)>,
postorder: OnceCell<Vec<BasicBlock>>,
dominators: OnceCell<Dominators<BasicBlock>>,
}
Expand Down Expand Up @@ -70,6 +74,18 @@ impl<'tcx> BasicBlocks<'tcx> {
})
}

/// Returns basic blocks in a preorder.
#[inline]
pub fn preorder_and_reachable_bitset(&self) -> (&[BasicBlock], &BitSet<BasicBlock>) {
let (preorder, reachable) = self.cache.preorder.get_or_init(|| {
let mut result = Vec::new();
let mut preorder = Preorder::new(&self.basic_blocks, START_BLOCK);
result.extend(preorder.by_ref().map(|(bb, _)| bb));
(result, preorder.into_visited())
});
(preorder, reachable)
}

/// `switch_sources()[&(target, switch)]` returns a list of switch
/// values that lead to a `target` block from a `switch` block.
#[inline]
Expand Down
40 changes: 25 additions & 15 deletions compiler/rustc_middle/src/mir/traversal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,41 @@ 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>,
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
visited: BitSet<BasicBlock>,
worklist: Vec<BasicBlock>,
root_is_start_block: bool,
}

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

Preorder {
body,
visited: BitSet::new_empty(body.basic_blocks.len()),
basic_blocks,
visited: BitSet::new_empty(basic_blocks.len()),
worklist,
root_is_start_block: root == START_BLOCK,
}
}

pub(super) fn into_visited(self) -> BitSet<BasicBlock> {
self.visited
}
}

pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> {
Preorder::new(body, START_BLOCK)
pub type PreorderIter<'a, 'tcx: 'a> =
impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator;

pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> PreorderIter<'a, 'tcx> {
body.basic_blocks
.preorder_and_reachable_bitset()
.0
.iter()
.map(|&bb| (bb, &body.basic_blocks[bb]))
}

impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
Expand All @@ -54,7 +68,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 @@ -68,7 +82,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {

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

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

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

#[derive(Clone)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/framework/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ where
pos: CursorPosition::block_entry(mir::START_BLOCK),

#[cfg(debug_assertions)]
reachable_blocks: mir::traversal::reachable_as_bitset(body),
reachable_blocks: mir::traversal::reachable_as_bitset(body).clone(),
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/framework/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ where
A: Analysis<'tcx>,
{
pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self {
let reachable = mir::traversal::reachable_as_bitset(body);
let reachable = mir::traversal::reachable_as_bitset(body).clone();
Formatter { body, results, style, reachable }
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> {
drop_flags: IndexVec<MovePathIndex, Option<Local>>,
patch: MirPatch<'tcx>,
un_derefer: UnDerefer<'tcx>,
reachable: BitSet<BasicBlock>,
reachable: &'a BitSet<BasicBlock>,
}

impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B
}

pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let reachable = traversal::reachable_as_bitset(body);
let reachable = traversal::reachable_as_bitset(body).clone();
let num_blocks = body.basic_blocks.len();
if num_blocks == reachable.count() {
return;
Expand Down

0 comments on commit de9e08a

Please sign in to comment.