Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c9dd1d9

Browse files
committed
Make MIR basic blocks field public
This makes it possible to mutably borrow different fields of the MIR body without resorting to methods like `basic_blocks_local_decls_mut_and_var_debug_info`. To preserve validity of control flow graph caches in the presence of modifications, a new struct `BasicBlocks` wraps together basic blocks and control flow graph caches. The `BasicBlocks` dereferences to `IndexVec<BasicBlock, BasicBlockData>`. On the other hand a mutable access requires explicit `as_mut()` call.
1 parent fac8fa5 commit c9dd1d9

21 files changed

+213
-195
lines changed

compiler/rustc_const_eval/src/transform/promote_consts.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
856856
literal: ConstantKind::from_const(_const, tcx),
857857
}))
858858
};
859-
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
859+
let blocks = self.source.basic_blocks.as_mut();
860+
let local_decls = &mut self.source.local_decls;
860861
let loc = candidate.location;
861862
let statement = &mut blocks[loc.block].statements[loc.statement_index];
862863
match statement.kind {
@@ -865,7 +866,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
865866
Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
866867
)) => {
867868
// Use the underlying local for this (necessarily interior) borrow.
868-
let ty = local_decls.local_decls()[place.local].ty;
869+
let ty = local_decls[place.local].ty;
869870
let span = statement.source_info.span;
870871

871872
let ref_ty = tcx.mk_ref(
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use crate::mir::graph_cyclic_cache::GraphIsCyclicCache;
2+
use crate::mir::predecessors::{PredecessorCache, Predecessors};
3+
use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources};
4+
use crate::mir::traversal::PostorderCache;
5+
use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK};
6+
7+
use rustc_data_structures::graph;
8+
use rustc_index::vec::IndexVec;
9+
10+
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
11+
pub struct BasicBlocks<'tcx> {
12+
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
13+
predecessor_cache: PredecessorCache,
14+
switch_source_cache: SwitchSourceCache,
15+
is_cyclic: GraphIsCyclicCache,
16+
postorder_cache: PostorderCache,
17+
}
18+
19+
impl<'tcx> BasicBlocks<'tcx> {
20+
#[inline]
21+
pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
22+
BasicBlocks {
23+
basic_blocks,
24+
predecessor_cache: PredecessorCache::new(),
25+
switch_source_cache: SwitchSourceCache::new(),
26+
is_cyclic: GraphIsCyclicCache::new(),
27+
postorder_cache: PostorderCache::new(),
28+
}
29+
}
30+
31+
/// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
32+
#[inline]
33+
pub fn is_cfg_cyclic(&self) -> bool {
34+
self.is_cyclic.is_cyclic(self)
35+
}
36+
37+
/// Returns predecessors for each basic block.
38+
#[inline]
39+
pub fn predecessors(&self) -> &Predecessors {
40+
self.predecessor_cache.compute(&self.basic_blocks)
41+
}
42+
43+
/// Returns basic blocks in a postorder.
44+
#[inline]
45+
pub fn postorder(&self) -> &[BasicBlock] {
46+
self.postorder_cache.compute(&self.basic_blocks)
47+
}
48+
49+
/// `switch_sources()[&(target, switch)]` returns a list of switch
50+
/// values that lead to a `target` block from a `switch` block.
51+
#[inline]
52+
pub fn switch_sources(&self) -> &SwitchSources {
53+
self.switch_source_cache.compute(&self.basic_blocks)
54+
}
55+
56+
/// Returns mutable reference to basic blocks. Invalidates CFG cache.
57+
#[inline]
58+
pub fn as_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
59+
self.invalidate_cfg_cache();
60+
&mut self.basic_blocks
61+
}
62+
63+
/// Get mutable access to basic blocks without invalidating the CFG cache.
64+
///
65+
/// By calling this method instead of e.g. [`BasicBlocks::as_mut`] you promise not to change
66+
/// the CFG. This means that
67+
///
68+
/// 1) The number of basic blocks remains unchanged
69+
/// 2) The set of successors of each terminator remains unchanged.
70+
/// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
71+
/// kind is not changed.
72+
///
73+
/// If any of these conditions cannot be upheld, you should call [`BasicBlocks::invalidate_cfg_cache`].
74+
#[inline]
75+
pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
76+
&mut self.basic_blocks
77+
}
78+
79+
/// Invalidates cached information about the CFG.
80+
///
81+
/// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`].
82+
/// All other methods that allow you to mutate the basic blocks also call this method
83+
/// themselves, thereby avoiding any risk of accidentaly cache invalidation.
84+
pub fn invalidate_cfg_cache(&mut self) {
85+
self.predecessor_cache.invalidate();
86+
self.switch_source_cache.invalidate();
87+
self.is_cyclic.invalidate();
88+
self.postorder_cache.invalidate();
89+
}
90+
}
91+
92+
impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> {
93+
type Target = IndexVec<BasicBlock, BasicBlockData<'tcx>>;
94+
95+
#[inline]
96+
fn deref(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
97+
&self.basic_blocks
98+
}
99+
}
100+
101+
impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> {
102+
type Node = BasicBlock;
103+
}
104+
105+
impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> {
106+
#[inline]
107+
fn num_nodes(&self) -> usize {
108+
self.basic_blocks.len()
109+
}
110+
}
111+
112+
impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
113+
#[inline]
114+
fn start_node(&self) -> Self::Node {
115+
START_BLOCK
116+
}
117+
}
118+
119+
impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> {
120+
#[inline]
121+
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
122+
self.basic_blocks[node].terminator().successors()
123+
}
124+
}
125+
126+
impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> {
127+
type Item = BasicBlock;
128+
type Iter = Successors<'b>;
129+
}
130+
131+
impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> {
132+
type Item = BasicBlock;
133+
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
134+
}
135+
136+
impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
137+
#[inline]
138+
fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
139+
self.predecessors()[node].iter().copied()
140+
}
141+
}

0 commit comments

Comments
 (0)