waffle/src/cfg/mod.rs

103 lines
3.1 KiB
Rust
Raw Normal View History

2021-11-15 01:56:56 -06:00
//! Lightweight CFG analyses.
// Borrowed from regalloc2's cfg.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, FunctionBody, Terminator};
2021-11-15 01:56:56 -06:00
use smallvec::SmallVec;
pub mod domtree;
pub mod postorder;
#[derive(Clone, Debug)]
pub struct CFGInfo {
2022-11-01 22:43:47 -05:00
/// Entry block.
pub entry: Block,
2021-11-15 01:56:56 -06:00
/// Predecessors for each block.
2022-11-01 22:43:47 -05:00
pub block_preds: PerEntity<Block, SmallVec<[Block; 4]>>,
2021-11-15 01:56:56 -06:00
/// Successors for each block.
2022-11-01 22:43:47 -05:00
pub block_succs: PerEntity<Block, SmallVec<[Block; 4]>>,
2021-11-15 01:56:56 -06:00
/// Blocks that end in return.
2022-11-01 22:43:47 -05:00
pub return_blocks: Vec<Block>,
2021-11-15 01:56:56 -06:00
/// Postorder traversal of blocks.
2022-11-01 22:43:47 -05:00
pub postorder: Vec<Block>,
2021-11-15 01:56:56 -06:00
/// Position of each block in postorder, if reachable.
2022-11-01 22:43:47 -05:00
pub postorder_pos: PerEntity<Block, Option<usize>>,
2021-11-15 01:56:56 -06:00
/// Domtree parents, indexed by block.
2022-11-01 22:43:47 -05:00
pub domtree: PerEntity<Block, Block>,
2021-11-15 01:56:56 -06:00
}
impl CFGInfo {
pub fn new(f: &FunctionBody) -> CFGInfo {
2022-11-01 22:43:47 -05:00
let mut block_preds: PerEntity<Block, SmallVec<[Block; 4]>> = PerEntity::default();
let mut block_succs: PerEntity<Block, SmallVec<[Block; 4]>> = PerEntity::default();
for (block, block_def) in f.blocks.entries() {
block_def.terminator.visit_successors(|succ| {
2021-11-15 01:56:56 -06:00
block_preds[succ].push(block);
block_succs[block].push(succ);
});
2021-11-15 01:56:56 -06:00
}
let mut return_blocks = vec![];
2022-11-01 22:43:47 -05:00
for (block_id, block) in f.blocks.entries() {
if let Terminator::Return { .. } = &block.terminator {
return_blocks.push(block_id);
2021-11-15 01:56:56 -06:00
}
}
2022-11-01 22:43:47 -05:00
let postorder = postorder::calculate(f.entry, |block| &block_succs[block]);
2021-11-15 01:56:56 -06:00
2022-11-01 22:43:47 -05:00
let mut postorder_pos = PerEntity::default();
2021-11-15 01:56:56 -06:00
for (i, block) in postorder.iter().enumerate() {
postorder_pos[*block] = Some(i);
}
let domtree = domtree::calculate(
|block| &&block_preds[block],
&postorder[..],
2022-11-01 22:43:47 -05:00
f.entry,
2021-11-15 01:56:56 -06:00
);
CFGInfo {
2022-11-01 22:43:47 -05:00
entry: f.entry,
2021-11-15 01:56:56 -06:00
block_preds,
block_succs,
return_blocks,
postorder,
postorder_pos,
domtree,
}
}
2022-11-01 22:43:47 -05:00
pub fn dominates(&self, a: Block, b: Block) -> bool {
domtree::dominates(&self.domtree, a, b)
}
2022-11-01 22:43:47 -05:00
pub fn succs(&self, block: Block) -> &[Block] {
2021-11-15 01:56:56 -06:00
&self.block_succs[block]
}
2022-11-01 22:43:47 -05:00
pub fn preds(&self, block: Block) -> &[Block] {
2021-11-15 01:56:56 -06:00
&self.block_preds[block]
}
2022-11-01 22:43:47 -05:00
pub fn pred_count_with_entry(&self, block: Block) -> usize {
let is_entry = block == self.entry;
2021-11-15 01:56:56 -06:00
self.preds(block).len() + if is_entry { 1 } else { 0 }
}
2022-11-01 22:43:47 -05:00
pub fn succ_count_with_return(&self, block: Block) -> usize {
2021-11-15 01:56:56 -06:00
let is_return = self.return_blocks.binary_search(&block).is_ok();
self.succs(block).len() + if is_return { 1 } else { 0 }
}
2021-11-20 03:29:46 -06:00
2022-11-01 22:43:47 -05:00
pub fn rpo(&self) -> Vec<Block> {
2021-11-20 03:29:46 -06:00
self.postorder.iter().cloned().rev().collect()
}
2022-11-01 22:43:47 -05:00
pub fn rpo_pos(&self, block: Block) -> Option<usize> {
2021-11-20 03:29:46 -06:00
self.postorder_pos[block].map(|fwd_pos| self.postorder.len() - 1 - fwd_pos)
}
2021-11-15 01:56:56 -06:00
}