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-02 23:26:22 -05:00
|
|
|
use crate::entity::{EntityRef, PerEntity};
|
2022-11-01 22:43:47 -05:00
|
|
|
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>,
|
2022-11-02 23:26:22 -05:00
|
|
|
/// Domtree children.
|
|
|
|
pub domtree_children: PerEntity<Block, DomtreeChildren>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
|
|
pub struct DomtreeChildren {
|
|
|
|
pub child: Block,
|
|
|
|
pub next: Block,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DomtreeChildIter<'a> {
|
|
|
|
domtree_children: &'a PerEntity<Block, DomtreeChildren>,
|
|
|
|
block: Block,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for DomtreeChildIter<'a> {
|
|
|
|
type Item = Block;
|
|
|
|
fn next(&mut self) -> Option<Block> {
|
|
|
|
if self.block.is_invalid() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let block = self.block;
|
|
|
|
self.block = self.domtree_children[block].next;
|
|
|
|
Some(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-12-11 23:46:14 -06:00
|
|
|
});
|
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);
|
|
|
|
}
|
|
|
|
|
2022-11-02 23:26:22 -05:00
|
|
|
let domtree = domtree::calculate(|block| &&block_preds[block], &postorder[..], f.entry);
|
|
|
|
|
|
|
|
let mut domtree_children: PerEntity<Block, DomtreeChildren> = PerEntity::default();
|
|
|
|
for block in f.blocks.iter().rev() {
|
|
|
|
let idom = domtree[block];
|
|
|
|
if idom.is_valid() {
|
|
|
|
let next = domtree_children[idom].child;
|
|
|
|
domtree_children[block].next = next;
|
|
|
|
domtree_children[idom].child = block;
|
|
|
|
}
|
|
|
|
}
|
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-02 23:26:22 -05:00
|
|
|
domtree_children,
|
2021-11-15 01:56:56 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-01 22:43:47 -05:00
|
|
|
pub fn dominates(&self, a: Block, b: Block) -> bool {
|
|
|
|
domtree::dominates(&self.domtree, a, b)
|
2021-12-16 01:21:24 -06:00
|
|
|
}
|
|
|
|
|
2022-11-02 23:26:22 -05:00
|
|
|
pub fn dom_children<'a>(&'a self, block: Block) -> DomtreeChildIter<'a> {
|
|
|
|
DomtreeChildIter {
|
|
|
|
domtree_children: &self.domtree_children,
|
|
|
|
block: self.domtree_children[block].child,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|