Skip to main content

luaur_code_gen/functions/
compute_cfg_block_edges.rs

1use crate::enums::ir_block_kind::IrBlockKind;
2use crate::enums::ir_op_kind::IrOpKind;
3use crate::records::cfg_info::CfgInfo;
4use crate::records::ir_block::IrBlock;
5use crate::records::ir_function::IrFunction;
6use crate::records::ir_inst::IrInst;
7use crate::records::ir_op::IrOp;
8
9pub fn compute_cfg_block_edges(function: &mut IrFunction) {
10    let info: &mut CfgInfo = &mut function.cfg;
11
12    // Clear existing data
13    info.predecessors_offsets.clear();
14    info.successors_offsets.clear();
15
16    // Compute predecessors block edges
17    info.predecessors_offsets.reserve(function.blocks.len());
18    info.successors_offsets.reserve(function.blocks.len());
19
20    let mut edge_count: u32 = 0;
21
22    for block in &function.blocks {
23        info.predecessors_offsets.push(edge_count);
24        edge_count = edge_count.wrapping_add(block.use_count as u32);
25    }
26
27    info.predecessors.resize(edge_count as usize, 0);
28    info.successors.resize(edge_count as usize, 0);
29
30    edge_count = 0;
31
32    for (block_idx, block) in function.blocks.iter().enumerate() {
33        info.successors_offsets.push(edge_count);
34
35        if block.kind == IrBlockKind::Dead {
36            continue;
37        }
38
39        for inst_idx in block.start..=block.finish {
40            let inst: &IrInst = &function.instructions[inst_idx as usize];
41
42            let mut check_op = |op: &IrOp| {
43                if op.kind() == IrOpKind::Block {
44                    // Using predecessors list offset as write cursor position (adjusted back later)
45                    let pred_pos = info.predecessors_offsets[op.index() as usize] as usize;
46                    info.predecessors[pred_pos] = block_idx as u32;
47
48                    info.predecessors_offsets[op.index() as usize] += 1;
49
50                    info.successors[edge_count as usize] = op.index();
51                    edge_count += 1;
52                }
53            };
54
55            for op in &inst.ops {
56                check_op(op);
57            }
58        }
59    }
60
61    // Offsets into the predecessor list were used as iterators in the previous loop
62    // Adjust them back by subtracting block use count (predecessor count == block uses)
63    for (block_idx, block) in function.blocks.iter().enumerate() {
64        info.predecessors_offsets[block_idx] -= block.use_count as u32;
65    }
66}