1
Fork 0

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.
This commit is contained in:
Tomasz Miąsko 2022-07-04 00:00:00 +00:00
parent fac8fa5672
commit c9dd1d9983
21 changed files with 213 additions and 195 deletions

View file

@ -104,22 +104,25 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
///
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
pub struct Postorder<'a, 'tcx> {
body: &'a Body<'tcx>,
basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
visited: BitSet<BasicBlock>,
visit_stack: Vec<(BasicBlock, Successors<'a>)>,
root_is_start_block: bool,
}
impl<'a, 'tcx> Postorder<'a, 'tcx> {
pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
pub fn new(
basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
root: BasicBlock,
) -> Postorder<'a, 'tcx> {
let mut po = Postorder {
body,
visited: BitSet::new_empty(body.basic_blocks().len()),
basic_blocks,
visited: BitSet::new_empty(basic_blocks.len()),
visit_stack: Vec::new(),
root_is_start_block: root == START_BLOCK,
};
let data = &po.body[root];
let data = &po.basic_blocks[root];
if let Some(ref term) = data.terminator {
po.visited.insert(root);
@ -190,7 +193,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
};
if self.visited.insert(bb) {
if let Some(term) = &self.body[bb].terminator {
if let Some(term) = &self.basic_blocks[bb].terminator {
self.visit_stack.push((bb, term.successors()));
}
}
@ -199,7 +202,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
}
pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> {
Postorder::new(body, START_BLOCK)
Postorder::new(&body.basic_blocks, START_BLOCK)
}
impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
@ -211,12 +214,12 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
self.traverse_successor();
}
next.map(|(bb, _)| (bb, &self.body[bb]))
next.map(|(bb, _)| (bb, &self.basic_blocks[bb]))
}
fn size_hint(&self) -> (usize, Option<usize>) {
// All the blocks, minus the number of blocks we've visited.
let upper = self.body.basic_blocks().len() - self.visited.count();
let upper = self.basic_blocks.len() - self.visited.count();
let lower = if self.root_is_start_block {
// We will visit all remaining blocks exactly once.
@ -263,10 +266,8 @@ pub struct ReversePostorder<'a, 'tcx> {
impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> {
let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect();
let blocks: Vec<_> = Postorder::new(&body.basic_blocks, root).map(|(bb, _)| bb).collect();
let len = blocks.len();
ReversePostorder { body, blocks, idx: len }
}
}
@ -334,10 +335,8 @@ impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> {
impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {}
pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> {
let blocks = body.postorder_cache.compute(body);
let blocks = body.basic_blocks.postorder();
let len = blocks.len();
ReversePostorderIter { body, blocks, idx: len }
}
@ -360,7 +359,7 @@ impl PostorderCache {
/// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR.
#[inline]
pub(super) fn compute(&self, body: &Body<'_>) -> &[BasicBlock] {
pub(super) fn compute(&self, body: &IndexVec<BasicBlock, BasicBlockData<'_>>) -> &[BasicBlock] {
self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect())
}
}