1use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError};
9use smallvec::{smallvec, SmallVec};
10
11#[derive(Clone, Debug)]
12pub struct CFGInfo {
13 pub postorder: Vec<Block>,
15 pub domtree: Vec<Block>,
17 pub insn_block: Vec<Block>,
19 pub block_entry: Vec<ProgPoint>,
21 pub block_exit: Vec<ProgPoint>,
23 pub approx_loop_depth: Vec<u32>,
31}
32
33impl CFGInfo {
34 pub fn new<F: Function>(f: &F) -> Result<CFGInfo, RegAllocError> {
35 let postorder = postorder::calculate(f.num_blocks(), f.entry_block(), |block| {
36 f.block_succs(block)
37 });
38 let domtree = domtree::calculate(
39 f.num_blocks(),
40 |block| f.block_preds(block),
41 &postorder[..],
42 f.entry_block(),
43 );
44 let mut insn_block = vec![Block::invalid(); f.num_insts()];
45 let mut block_entry = vec![ProgPoint::before(Inst::invalid()); f.num_blocks()];
46 let mut block_exit = vec![ProgPoint::before(Inst::invalid()); f.num_blocks()];
47 let mut backedge_in = vec![0; f.num_blocks()];
48 let mut backedge_out = vec![0; f.num_blocks()];
49
50 for block in 0..f.num_blocks() {
51 let block = Block::new(block);
52 for inst in f.block_insns(block).iter() {
53 insn_block[inst.index()] = block;
54 }
55 block_entry[block.index()] = ProgPoint::before(f.block_insns(block).first());
56 block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last());
57
58 let preds = f.block_preds(block).len() + if block == f.entry_block() { 1 } else { 0 };
62 if preds > 1 {
63 for &pred in f.block_preds(block) {
64 let succs = f.block_succs(pred).len();
65 if succs > 1 {
66 return Err(RegAllocError::CritEdge(pred, block));
67 }
68 }
69 }
70
71 let mut require_no_branch_args = false;
77 for &succ in f.block_succs(block) {
78 let preds = f.block_preds(succ).len() + if succ == f.entry_block() { 1 } else { 0 };
79 if preds > 1 {
80 require_no_branch_args = true;
81 }
82 }
83 if require_no_branch_args {
84 let last = f.block_insns(block).last();
85 if !f.inst_operands(last).is_empty() {
86 return Err(RegAllocError::DisallowedBranchArg(last));
87 }
88 }
89
90 for &succ in f.block_succs(block) {
91 if succ.index() <= block.index() {
92 backedge_in[succ.index()] += 1;
93 backedge_out[block.index()] += 1;
94 }
95 }
96 }
97
98 let mut approx_loop_depth = vec![];
99 let mut backedge_stack: SmallVec<[usize; 4]> = smallvec![];
100 let mut cur_depth = 0;
101 for block in 0..f.num_blocks() {
102 if backedge_in[block] > 0 {
103 cur_depth += 1;
104 backedge_stack.push(backedge_in[block]);
105 }
106
107 approx_loop_depth.push(cur_depth);
108
109 while backedge_stack.len() > 0 && backedge_out[block] > 0 {
110 backedge_out[block] -= 1;
111 *backedge_stack.last_mut().unwrap() -= 1;
112 if *backedge_stack.last().unwrap() == 0 {
113 cur_depth -= 1;
114 backedge_stack.pop();
115 }
116 }
117 }
118
119 Ok(CFGInfo {
120 postorder,
121 domtree,
122 insn_block,
123 block_entry,
124 block_exit,
125 approx_loop_depth,
126 })
127 }
128
129 pub fn dominates(&self, a: Block, b: Block) -> bool {
130 domtree::dominates(&self.domtree[..], a, b)
131 }
132}