waffle/src/cfg/postorder.rs

59 lines
1.6 KiB
Rust
Raw Normal View History

2021-11-15 01:56:56 -06:00
//! Fast postorder computation.
// Borrowed from regalloc2's postorder.rs, which is also Apache-2.0
// with LLVM-exception.
2022-11-01 22:43:47 -05:00
use crate::entity::PerEntity;
use crate::ir::Block;
2021-11-15 01:56:56 -06:00
use smallvec::{smallvec, SmallVec};
2022-11-01 22:43:47 -05:00
pub fn calculate<'a, SuccFn: Fn(Block) -> &'a [Block]>(
entry: Block,
2021-11-15 01:56:56 -06:00
succ_blocks: SuccFn,
2022-11-01 22:43:47 -05:00
) -> Vec<Block> {
2021-11-15 01:56:56 -06:00
let mut ret = vec![];
// State: visited-block map, and explicit DFS stack.
2022-11-01 22:43:47 -05:00
let mut visited: PerEntity<Block, bool> = PerEntity::default();
2021-11-15 01:56:56 -06:00
#[derive(Debug)]
2021-11-15 01:56:56 -06:00
struct State<'a> {
2022-11-01 22:43:47 -05:00
block: Block,
succs: &'a [Block],
2021-11-15 01:56:56 -06:00
next_succ: usize,
}
let mut stack: SmallVec<[State; 64]> = smallvec![];
visited[entry] = true;
stack.push(State {
block: entry,
succs: succ_blocks(entry),
next_succ: 0,
});
while let Some(ref mut state) = stack.last_mut() {
log::trace!("postorder: TOS is {:?}", state);
2021-11-15 01:56:56 -06:00
// Perform one action: push to new succ, skip an already-visited succ, or pop.
if state.next_succ < state.succs.len() {
let succ = state.succs[state.next_succ];
log::trace!(" -> succ {}", succ);
2021-11-15 01:56:56 -06:00
state.next_succ += 1;
if !visited[succ] {
log::trace!(" -> visiting");
2021-11-15 01:56:56 -06:00
visited[succ] = true;
stack.push(State {
block: succ,
succs: succ_blocks(succ),
next_succ: 0,
});
}
} else {
log::trace!("retreating from {}", state.block);
2021-11-15 01:56:56 -06:00
ret.push(state.block);
stack.pop();
}
}
ret
}