Skip to content

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)