/* * Released under the terms of the Apache 2.0 license with LLVM * exception. See `LICENSE` for details. */ //! Lightweight CFG analyses. use crate::{domtree, postorder, Block, Function, Inst, OperandKind, ProgPoint, RegAllocError}; #[derive(Clone, Debug)] pub struct CFGInfo { /// Postorder traversal of blocks. pub postorder: Vec, /// Domtree parents, indexed by block. pub domtree: Vec, /// For each instruction, the block it belongs to. pub insn_block: Vec, /// For each vreg, the instruction that defines it, if any. pub vreg_def_inst: Vec, /// For each vreg, the block that defines it as a blockparam, if /// any. (Every vreg must have a valid entry in either /// `vreg_def_inst` or `vreg_def_blockparam`.) pub vreg_def_blockparam: Vec<(Block, u32)>, /// For each block, the first instruction. pub block_entry: Vec, /// For each block, the last instruction. pub block_exit: Vec, /// For each block, what is its position in its successor's preds, /// if it has a single successor? /// /// (Because we require split critical edges, we always either have a single /// successor (which itself may have multiple preds), or we have multiple /// successors but each successor itself has only one pred; so we can store /// just one value per block and always know any block's position in its /// successors' preds lists.) pub pred_pos: Vec, } impl CFGInfo { pub fn new(f: &F) -> Result { let postorder = postorder::calculate(f.blocks(), f.entry_block(), |block| f.block_succs(block)); let domtree = domtree::calculate( f.blocks(), |block| f.block_preds(block), &postorder[..], f.entry_block(), ); let mut insn_block = vec![Block::invalid(); f.insts()]; let mut vreg_def_inst = vec![Inst::invalid(); f.num_vregs()]; let mut vreg_def_blockparam = vec![(Block::invalid(), 0); f.num_vregs()]; let mut block_entry = vec![ProgPoint::before(Inst::invalid()); f.blocks()]; let mut block_exit = vec![ProgPoint::before(Inst::invalid()); f.blocks()]; let mut pred_pos = vec![0; f.blocks()]; for block in 0..f.blocks() { let block = Block::new(block); for (i, param) in f.block_params(block).iter().enumerate() { vreg_def_blockparam[param.vreg()] = (block, i as u32); } for inst in f.block_insns(block).iter() { insn_block[inst.index()] = block; for operand in f.inst_operands(inst) { match operand.kind() { OperandKind::Def => { vreg_def_inst[operand.vreg().vreg()] = inst; } _ => {} } } } block_entry[block.index()] = ProgPoint::before(f.block_insns(block).first()); block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last()); let preds = f.block_preds(block).len() + if block == f.entry_block() { 1 } else { 0 }; if preds > 1 { for (i, &pred) in f.block_preds(block).iter().enumerate() { // Check critical edge condition. let succs = f.block_succs(pred).len(); if succs > 1 { return Err(RegAllocError::CritEdge(pred, block)); } pred_pos[pred.index()] = i; } } } Ok(CFGInfo { postorder, domtree, insn_block, vreg_def_inst, vreg_def_blockparam, block_entry, block_exit, pred_pos, }) } pub fn dominates(&self, a: Block, b: Block) -> bool { domtree::dominates(&self.domtree[..], a, b) } /// Return the position of this block in its successor's predecessor list. /// /// Because the CFG must have split critical edges, we actually do not need /// to know *which* successor: if there is more than one, then each /// successor has only one predecessor (that's this block), so the answer is /// `0` no matter which successor we are considering. pub fn pred_position(&self, block: Block) -> usize { self.pred_pos[block.index()] } }