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.
|
|
|
|
|
|
|
|
use crate::ir::BlockId;
|
|
|
|
use smallvec::{smallvec, SmallVec};
|
|
|
|
|
|
|
|
pub fn calculate<'a, SuccFn: Fn(BlockId) -> &'a [BlockId]>(
|
|
|
|
num_blocks: usize,
|
|
|
|
entry: BlockId,
|
|
|
|
succ_blocks: SuccFn,
|
|
|
|
) -> Vec<BlockId> {
|
|
|
|
let mut ret = vec![];
|
|
|
|
|
|
|
|
// State: visited-block map, and explicit DFS stack.
|
|
|
|
let mut visited = vec![];
|
|
|
|
visited.resize(num_blocks, false);
|
|
|
|
|
2021-12-16 01:21:24 -06:00
|
|
|
#[derive(Debug)]
|
2021-11-15 01:56:56 -06:00
|
|
|
struct State<'a> {
|
|
|
|
block: BlockId,
|
|
|
|
succs: &'a [BlockId],
|
|
|
|
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() {
|
2021-12-16 01:21:24 -06:00
|
|
|
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];
|
2021-12-16 01:21:24 -06:00
|
|
|
log::trace!(" -> succ {}", succ);
|
2021-11-15 01:56:56 -06:00
|
|
|
state.next_succ += 1;
|
|
|
|
if !visited[succ] {
|
2021-12-16 01:21:24 -06:00
|
|
|
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 {
|
2021-12-16 01:21:24 -06:00
|
|
|
log::trace!("retreating from {}", state.block);
|
2021-11-15 01:56:56 -06:00
|
|
|
ret.push(state.block);
|
|
|
|
stack.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret
|
|
|
|
}
|