Skip to content

Commit

Permalink
Deduplicate Postorder logic
Browse files Browse the repository at this point in the history
  • Loading branch information
saethlin committed Sep 20, 2024
1 parent 04f2f63 commit 9ba0ca9
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 64 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/basic_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl<'tcx> BasicBlocks<'tcx> {
#[inline]
pub fn reverse_postorder(&self) -> &[BasicBlock] {
self.cache.reverse_postorder.get_or_init(|| {
let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK).collect();
let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, ()).collect();
rpo.reverse();
rpo
})
Expand Down
101 changes: 38 additions & 63 deletions compiler/rustc_middle/src/mir/traversal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,36 +104,46 @@ 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> {
pub struct Postorder<'a, 'tcx, C> {
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
visited: BitSet<BasicBlock>,
visit_stack: Vec<(BasicBlock, Successors<'a>)>,
root_is_start_block: bool,
extra: C,
}

impl<'a, 'tcx> Postorder<'a, 'tcx> {
impl<'a, 'tcx, C> Postorder<'a, 'tcx, C>
where
C: Customization<'tcx>,
{
pub fn new(
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
root: BasicBlock,
) -> Postorder<'a, 'tcx> {
extra: C,
) -> Postorder<'a, 'tcx, C> {
let mut po = Postorder {
basic_blocks,
visited: BitSet::new_empty(basic_blocks.len()),
visit_stack: Vec::new(),
root_is_start_block: root == START_BLOCK,
extra,
};

let data = &po.basic_blocks[root];

if let Some(ref term) = data.terminator {
po.visited.insert(root);
po.visit_stack.push((root, term.successors()));
po.traverse_successor();
}
po.visit(root);
po.traverse_successor();

po
}

fn visit(&mut self, bb: BasicBlock) {
if !self.visited.insert(bb) {
return;
}
let data = &self.basic_blocks[bb];
let successors = C::successors(data, self.extra);
self.visit_stack.push((bb, successors));
}

fn traverse_successor(&mut self) {
// This is quite a complex loop due to 1. the borrow checker not liking it much
// and 2. what exactly is going on is not clear
Expand Down Expand Up @@ -183,16 +193,15 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
// since we've already visited `E`, that child isn't added to the stack. The last
// two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A]
while let Some(bb) = self.visit_stack.last_mut().and_then(|(_, iter)| iter.next_back()) {
if self.visited.insert(bb) {
if let Some(term) = &self.basic_blocks[bb].terminator {
self.visit_stack.push((bb, term.successors()));
}
}
self.visit(bb);
}
}
}

impl<'tcx> Iterator for Postorder<'_, 'tcx> {
impl<'tcx, C> Iterator for Postorder<'_, 'tcx, C>
where
C: Customization<'tcx>,
{
type Item = BasicBlock;

fn next(&mut self) -> Option<BasicBlock> {
Expand Down Expand Up @@ -232,57 +241,23 @@ pub fn postorder<'a, 'tcx>(
reverse_postorder(body).rev()
}

struct MonoReachablePostorder<'a, 'tcx> {
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
visited: BitSet<BasicBlock>,
visit_stack: Vec<(BasicBlock, Successors<'a>)>,
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
/// Lets us plug in some additional logic and data into a Postorder traversal. Or not.
pub trait Customization<'tcx>: Copy {
fn successors<'a>(_: &'a BasicBlockData<'tcx>, _: Self) -> Successors<'a>;
}

impl<'a, 'tcx> MonoReachablePostorder<'a, 'tcx> {
fn new(
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
) -> MonoReachablePostorder<'a, 'tcx> {
let basic_blocks = &body.basic_blocks;
let mut po = MonoReachablePostorder {
basic_blocks,
visited: BitSet::new_empty(basic_blocks.len()),
visit_stack: Vec::new(),
tcx,
instance,
};

po.visit(START_BLOCK);
po.traverse_successor();
po
}

fn visit(&mut self, bb: BasicBlock) {
if !self.visited.insert(bb) {
return;
}
let data = &self.basic_blocks[bb];
let successors = data.mono_successors(self.tcx, self.instance);
self.visit_stack.push((bb, successors));
}

fn traverse_successor(&mut self) {
while let Some(bb) = self.visit_stack.last_mut().and_then(|(_, iter)| iter.next_back()) {
self.visit(bb);
}
impl<'tcx> Customization<'tcx> for () {
fn successors<'a>(data: &'a BasicBlockData<'tcx>, _: ()) -> Successors<'a> {
data.terminator().successors()
}
}

impl<'tcx> Iterator for MonoReachablePostorder<'_, 'tcx> {
type Item = BasicBlock;

fn next(&mut self) -> Option<BasicBlock> {
let (bb, _) = self.visit_stack.pop()?;
self.traverse_successor();
Some(bb)
impl<'tcx> Customization<'tcx> for (TyCtxt<'tcx>, Instance<'tcx>) {
fn successors<'a>(
data: &'a BasicBlockData<'tcx>,
(tcx, instance): (TyCtxt<'tcx>, Instance<'tcx>),
) -> Successors<'a> {
data.mono_successors(tcx, instance)
}
}

Expand All @@ -291,7 +266,7 @@ pub fn mono_reachable_reverse_postorder<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
) -> Vec<BasicBlock> {
let mut iter = MonoReachablePostorder::new(body, tcx, instance);
let mut iter = Postorder::new(&body.basic_blocks, START_BLOCK, (tcx, instance));
let mut items = Vec::with_capacity(body.basic_blocks.len());
while let Some(block) = iter.next() {
items.push(block);
Expand Down

0 comments on commit 9ba0ca9

Please sign in to comment.