From 67cb824741bfff30e9c2d565d688fdd8fe883e90 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 16 Jun 2025 13:40:18 +0000 Subject: [PATCH 1/2] Cache MIR preorder traversal. --- compiler/rustc_middle/src/mir/basic_blocks.rs | 17 +++++++++-- compiler/rustc_middle/src/mir/traversal.rs | 29 ++++++++++++------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 0d2e23609ce35..73345a04f9a95 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -8,7 +8,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}; #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] @@ -31,6 +31,7 @@ pub enum SwitchTargetValue { #[derive(Clone, Default, Debug)] struct Cache { predecessors: OnceLock, + preorder: OnceLock>, reverse_postorder: OnceLock>, dominators: OnceLock>, } @@ -61,9 +62,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. From 8ab25fc74e15444df82a0473c6f5598e77e7cd72 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 15:53:13 +0000 Subject: [PATCH 2/2] Fix collapse_goto_chain. --- compiler/rustc_mir_transform/src/simplify.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index db933da641371..468ef742dfb73 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -225,6 +225,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { current = target; } let last = current; + *changed |= *start != last; *start = last; while let Some((current, mut terminator)) = terminators.pop() { let Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } = terminator