diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index d0dbf64dc5959..168dc45d5983a 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -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)] @@ -42,6 +42,7 @@ pub enum SwitchTargetValue { struct Cache { predecessors: OnceLock, switch_sources: OnceLock, + preorder: OnceLock>, reverse_postorder: OnceLock>, dominators: OnceLock>, } @@ -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] diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 9308570d89d18..ed1c9a8dafafe 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -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>, visited: DenseBitSet, worklist: Vec, } 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>, + 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 } } } @@ -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)> { + body.basic_blocks.preorder().iter().map(|&bb| (bb, &body.basic_blocks[bb])) } impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { @@ -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()); @@ -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)) } @@ -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 { - 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.