From eab621da0d6a9a2691d85c37c1a49d9a7ef8f645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 16 Jan 2023 00:00:00 +0000 Subject: [PATCH 1/2] Refactor basic blocks control flow caches --- compiler/rustc_middle/src/mir/basic_blocks.rs | 98 ++++++++++++++----- .../src/mir/graph_cyclic_cache.rs | 63 ------------ compiler/rustc_middle/src/mir/mod.rs | 3 - compiler/rustc_middle/src/mir/predecessors.rs | 78 --------------- .../rustc_middle/src/mir/switch_sources.rs | 78 --------------- compiler/rustc_middle/src/mir/traversal.rs | 50 ---------- 6 files changed, 74 insertions(+), 296 deletions(-) delete mode 100644 compiler/rustc_middle/src/mir/graph_cyclic_cache.rs delete mode 100644 compiler/rustc_middle/src/mir/predecessors.rs delete mode 100644 compiler/rustc_middle/src/mir/switch_sources.rs diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 752cbdeae6b25..b3354e6e9d2a2 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -1,38 +1,44 @@ -use crate::mir::graph_cyclic_cache::GraphIsCyclicCache; -use crate::mir::predecessors::{PredecessorCache, Predecessors}; -use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources}; -use crate::mir::traversal::PostorderCache; -use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK}; +use crate::mir::traversal::Postorder; +use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorKind, START_BLOCK}; +use rustc_data_structures::fx::FxHashMap; 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::vec::IndexVec; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use smallvec::SmallVec; #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct BasicBlocks<'tcx> { basic_blocks: IndexVec>, - predecessor_cache: PredecessorCache, - switch_source_cache: SwitchSourceCache, - is_cyclic: GraphIsCyclicCache, - postorder_cache: PostorderCache, + cache: Cache, +} + +// Typically 95%+ of basic blocks have 4 or fewer predecessors. +pub type Predecessors = IndexVec>; + +pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option; 1]>>; + +#[derive(Clone, Default, Debug)] +struct Cache { + predecessors: OnceCell, + switch_sources: OnceCell, + is_cyclic: OnceCell, + postorder: OnceCell>, } impl<'tcx> BasicBlocks<'tcx> { #[inline] pub fn new(basic_blocks: IndexVec>) -> Self { - BasicBlocks { - basic_blocks, - predecessor_cache: PredecessorCache::new(), - switch_source_cache: SwitchSourceCache::new(), - is_cyclic: GraphIsCyclicCache::new(), - postorder_cache: PostorderCache::new(), - } + BasicBlocks { basic_blocks, cache: Cache::default() } } /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`. #[inline] pub fn is_cfg_cyclic(&self) -> bool { - self.is_cyclic.is_cyclic(self) + *self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self)) } #[inline] @@ -43,20 +49,46 @@ impl<'tcx> BasicBlocks<'tcx> { /// Returns predecessors for each basic block. #[inline] pub fn predecessors(&self) -> &Predecessors { - self.predecessor_cache.compute(&self.basic_blocks) + self.cache.predecessors.get_or_init(|| { + let mut preds = IndexVec::from_elem(SmallVec::new(), &self.basic_blocks); + for (bb, data) in self.basic_blocks.iter_enumerated() { + if let Some(term) = &data.terminator { + for succ in term.successors() { + preds[succ].push(bb); + } + } + } + preds + }) } /// Returns basic blocks in a postorder. #[inline] pub fn postorder(&self) -> &[BasicBlock] { - self.postorder_cache.compute(&self.basic_blocks) + self.cache.postorder.get_or_init(|| { + Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect() + }) } /// `switch_sources()[&(target, switch)]` returns a list of switch /// values that lead to a `target` block from a `switch` block. #[inline] pub fn switch_sources(&self) -> &SwitchSources { - self.switch_source_cache.compute(&self.basic_blocks) + self.cache.switch_sources.get_or_init(|| { + let mut switch_sources: SwitchSources = FxHashMap::default(); + for (bb, data) in self.basic_blocks.iter_enumerated() { + if let Some(Terminator { + kind: TerminatorKind::SwitchInt { targets, .. }, .. + }) = &data.terminator + { + for (value, target) in targets.iter() { + switch_sources.entry((target, bb)).or_default().push(Some(value)); + } + switch_sources.entry((targets.otherwise(), bb)).or_default().push(None); + } + } + switch_sources + }) } /// Returns mutable reference to basic blocks. Invalidates CFG cache. @@ -88,10 +120,7 @@ impl<'tcx> BasicBlocks<'tcx> { /// All other methods that allow you to mutate the basic blocks also call this method /// themselves, thereby avoiding any risk of accidentally cache invalidation. pub fn invalidate_cfg_cache(&mut self) { - self.predecessor_cache.invalidate(); - self.switch_source_cache.invalidate(); - self.is_cyclic.invalidate(); - self.postorder_cache.invalidate(); + self.cache = Cache::default(); } } @@ -145,3 +174,24 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { self.predecessors()[node].iter().copied() } } + +TrivialTypeTraversalAndLiftImpls! { + Cache, +} + +impl Encodable for Cache { + #[inline] + fn encode(&self, _s: &mut S) {} +} + +impl Decodable for Cache { + #[inline] + fn decode(_: &mut D) -> Self { + Default::default() + } +} + +impl HashStable for Cache { + #[inline] + fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {} +} diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs deleted file mode 100644 index f97bf2883b369..0000000000000 --- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs +++ /dev/null @@ -1,63 +0,0 @@ -use rustc_data_structures::graph::{ - self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors, -}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; - -/// Helper type to cache the result of `graph::is_cyclic`. -#[derive(Clone, Debug)] -pub(super) struct GraphIsCyclicCache { - cache: OnceCell, -} - -impl GraphIsCyclicCache { - #[inline] - pub(super) fn new() -> Self { - GraphIsCyclicCache { cache: OnceCell::new() } - } - - pub(super) fn is_cyclic(&self, graph: &G) -> bool - where - G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, - { - *self.cache.get_or_init(|| graph::is_cyclic(graph)) - } - - /// Invalidates the cache. - #[inline] - pub(super) fn invalidate(&mut self) { - // Invalidating the cache requires mutating the MIR, which in turn requires a unique - // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all - // callers of `invalidate` have a unique reference to the MIR and thus to the - // cache. This means we never need to do synchronization when `invalidate` is called, - // we can simply reinitialize the `OnceCell`. - self.cache = OnceCell::new(); - } -} - -impl Encodable for GraphIsCyclicCache { - #[inline] - fn encode(&self, s: &mut S) { - Encodable::encode(&(), s); - } -} - -impl Decodable for GraphIsCyclicCache { - #[inline] - fn decode(d: &mut D) -> Self { - let () = Decodable::decode(d); - Self::new() - } -} - -impl HashStable for GraphIsCyclicCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - GraphIsCyclicCache, -} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e52b243ecf635..d833286dc33f0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -47,18 +47,15 @@ mod basic_blocks; pub mod coverage; mod generic_graph; pub mod generic_graphviz; -mod graph_cyclic_cache; pub mod graphviz; pub mod interpret; pub mod mono; pub mod patch; -mod predecessors; pub mod pretty; mod query; pub mod spanview; mod syntax; pub use syntax::*; -mod switch_sources; pub mod tcx; pub mod terminator; pub use terminator::*; diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs deleted file mode 100644 index 5f1fadaf3bc4c..0000000000000 --- a/compiler/rustc_middle/src/mir/predecessors.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Lazily compute the reverse control-flow graph for the MIR. - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; -use rustc_index::vec::IndexVec; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use smallvec::SmallVec; - -use crate::mir::{BasicBlock, BasicBlockData}; - -// Typically 95%+ of basic blocks have 4 or fewer predecessors. -pub type Predecessors = IndexVec>; - -#[derive(Clone, Debug)] -pub(super) struct PredecessorCache { - cache: OnceCell, -} - -impl PredecessorCache { - #[inline] - pub(super) fn new() -> Self { - PredecessorCache { cache: OnceCell::new() } - } - - /// Invalidates the predecessor cache. - #[inline] - pub(super) fn invalidate(&mut self) { - // Invalidating the predecessor cache requires mutating the MIR, which in turn requires a - // unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all - // callers of `invalidate` have a unique reference to the MIR and thus to the predecessor - // cache. This means we never need to do synchronization when `invalidate` is called, we can - // simply reinitialize the `OnceCell`. - self.cache = OnceCell::new(); - } - - /// Returns the predecessor graph for this MIR. - #[inline] - pub(super) fn compute( - &self, - basic_blocks: &IndexVec>, - ) -> &Predecessors { - self.cache.get_or_init(|| { - let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks); - for (bb, data) in basic_blocks.iter_enumerated() { - if let Some(term) = &data.terminator { - for succ in term.successors() { - preds[succ].push(bb); - } - } - } - - preds - }) - } -} - -impl Encodable for PredecessorCache { - #[inline] - fn encode(&self, _s: &mut S) {} -} - -impl Decodable for PredecessorCache { - #[inline] - fn decode(_: &mut D) -> Self { - Self::new() - } -} - -impl HashStable for PredecessorCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - PredecessorCache, -} diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs deleted file mode 100644 index b91c0c25782f4..0000000000000 --- a/compiler/rustc_middle/src/mir/switch_sources.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after -//! `Predecessors`/`PredecessorCache`. - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; -use rustc_index::vec::IndexVec; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use smallvec::SmallVec; - -use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind}; - -pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option; 1]>>; - -#[derive(Clone, Debug)] -pub(super) struct SwitchSourceCache { - cache: OnceCell, -} - -impl SwitchSourceCache { - #[inline] - pub(super) fn new() -> Self { - SwitchSourceCache { cache: OnceCell::new() } - } - - /// Invalidates the switch source cache. - #[inline] - pub(super) fn invalidate(&mut self) { - self.cache = OnceCell::new(); - } - - /// Returns the switch sources for this MIR. - #[inline] - pub(super) fn compute( - &self, - basic_blocks: &IndexVec>, - ) -> &SwitchSources { - self.cache.get_or_init(|| { - let mut switch_sources: SwitchSources = FxHashMap::default(); - for (bb, data) in basic_blocks.iter_enumerated() { - if let Some(Terminator { - kind: TerminatorKind::SwitchInt { targets, .. }, .. - }) = &data.terminator - { - for (value, target) in targets.iter() { - switch_sources.entry((target, bb)).or_default().push(Some(value)); - } - switch_sources.entry((targets.otherwise(), bb)).or_default().push(None); - } - } - - switch_sources - }) - } -} - -impl Encodable for SwitchSourceCache { - #[inline] - fn encode(&self, _s: &mut S) {} -} - -impl Decodable for SwitchSourceCache { - #[inline] - fn decode(_: &mut D) -> Self { - Self::new() - } -} - -impl HashStable for SwitchSourceCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - SwitchSourceCache, -} diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 0b461d1ce41c5..f37222cb29758 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -1,7 +1,4 @@ -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; use rustc_index::bit_set::BitSet; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use super::*; @@ -339,50 +336,3 @@ pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter let len = blocks.len(); ReversePostorderIter { body, blocks, idx: len } } - -#[derive(Clone, Debug)] -pub(super) struct PostorderCache { - cache: OnceCell>, -} - -impl PostorderCache { - #[inline] - pub(super) fn new() -> Self { - PostorderCache { cache: OnceCell::new() } - } - - /// Invalidates the postorder cache. - #[inline] - pub(super) fn invalidate(&mut self) { - self.cache = OnceCell::new(); - } - - /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR. - #[inline] - pub(super) fn compute(&self, body: &IndexVec>) -> &[BasicBlock] { - self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect()) - } -} - -impl Encodable for PostorderCache { - #[inline] - fn encode(&self, _s: &mut S) {} -} - -impl Decodable for PostorderCache { - #[inline] - fn decode(_: &mut D) -> Self { - Self::new() - } -} - -impl HashStable for PostorderCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - PostorderCache, -} From a705ccb9e9c9f99bf7eec3b779766dbc8f30743b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 17 Jan 2023 00:00:00 +0000 Subject: [PATCH 2/2] MIR dominators: computed on-demand and cached Cached inside MIR body - motivated by potential reuse opportunity when code generating different instantiations of the same generic code. --- .../src/diagnostics/conflict_errors.rs | 4 ++-- compiler/rustc_borrowck/src/invalidation.rs | 17 ++++------------- compiler/rustc_borrowck/src/lib.rs | 16 ++-------------- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 2 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 5 +++-- 5 files changed, 12 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e5a36259fa495..d088aee5c2d19 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2193,7 +2193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut back_edge_stack = Vec::new(); predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, self.dominators()) { + if location.dominates(predecessor, self.body.basic_blocks.dominators()) { back_edge_stack.push(predecessor) } else { stack.push(predecessor); @@ -2305,7 +2305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut has_predecessor = false; predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, self.dominators()) { + if location.dominates(predecessor, self.body.basic_blocks.dominators()) { back_edge_stack.push(predecessor) } else { stack.push(predecessor); diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 6fd9290058c36..1e4fb3b59a267 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -1,8 +1,7 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue}; +use rustc_middle::mir::{self, Body, Location, NonDivergingIntrinsic, Place, Rvalue}; use rustc_middle::mir::{BorrowKind, Mutability, Operand}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{Statement, StatementKind}; @@ -28,15 +27,8 @@ pub(super) fn generate_invalidates<'tcx>( if let Some(all_facts) = all_facts { let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); - let dominators = body.basic_blocks.dominators(); - let mut ig = InvalidationGenerator { - all_facts, - borrow_set, - tcx, - location_table, - body: &body, - dominators, - }; + let mut ig = + InvalidationGenerator { all_facts, borrow_set, tcx, location_table, body: &body }; ig.visit_body(body); } } @@ -46,7 +38,6 @@ struct InvalidationGenerator<'cx, 'tcx> { all_facts: &'cx mut AllFacts, location_table: &'cx LocationTable, body: &'cx Body<'tcx>, - dominators: Dominators, borrow_set: &'cx BorrowSet<'tcx>, } @@ -389,7 +380,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { (Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, location) { + if !is_active(this.body.basic_blocks.dominators(), borrow, location) { // If the borrow isn't active yet, reads don't invalidate it assert!(allow_two_phase_borrow(borrow.kind)); return Control::Continue; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 73ea7314b75cc..cd757b5b85d81 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -5,7 +5,6 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(never_type)] -#![feature(once_cell)] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] @@ -18,7 +17,6 @@ extern crate rustc_middle; extern crate tracing; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::vec_map::VecMap; use rustc_errors::{Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; @@ -30,7 +28,7 @@ use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, }; -use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; +use rustc_middle::mir::{AggregateKind, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::ty::query::Providers; @@ -40,7 +38,6 @@ use rustc_span::{Span, Symbol}; use either::Either; use smallvec::SmallVec; -use std::cell::OnceCell; use std::cell::RefCell; use std::collections::BTreeMap; use std::rc::Rc; @@ -335,7 +332,6 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - dominators: Default::default(), upvars: Vec::new(), local_names: IndexVec::from_elem(None, &promoted_body.local_decls), region_names: RefCell::default(), @@ -364,7 +360,6 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - dominators: Default::default(), upvars, local_names, region_names: RefCell::default(), @@ -533,9 +528,6 @@ struct MirBorrowckCtxt<'cx, 'tcx> { /// The set of borrows extracted from the MIR borrow_set: Rc>, - /// Dominators for MIR - dominators: OnceCell>, - /// Information about upvars not necessarily preserved in types or MIR upvars: Vec>, @@ -1051,7 +1043,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. - if !is_active(this.dominators(), borrow, location) { + if !is_active(this.body.basic_blocks.dominators(), borrow, location) { assert!(allow_two_phase_borrow(borrow.kind)); return Control::Continue; } @@ -2219,10 +2211,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option { path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body()) } - - fn dominators(&self) -> &Dominators { - self.dominators.get_or_init(|| self.body.basic_blocks.dominators()) - } } mod error { diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index dd1ac2c74aed4..d577ee63b7813 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -69,7 +69,7 @@ enum LocalKind { struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { fx: &'mir FunctionCx<'a, 'tcx, Bx>, - dominators: Dominators, + dominators: &'mir Dominators, locals: IndexVec, } diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index b3354e6e9d2a2..fa95695d80787 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -23,6 +23,7 @@ pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option>, predecessors: OnceCell, switch_sources: OnceCell, is_cyclic: OnceCell, @@ -42,8 +43,8 @@ impl<'tcx> BasicBlocks<'tcx> { } #[inline] - pub fn dominators(&self) -> Dominators { - dominators(&self) + pub fn dominators(&self) -> &Dominators { + self.cache.dominators.get_or_init(|| dominators(self)) } /// Returns predecessors for each basic block.