Skip to main content

luaur_code_gen/functions/
collect_direct_block_jump_path.rs

1use crate::enums::ir_block_kind::IrBlockKind;
2use crate::enums::ir_cmd::IrCmd;
3use crate::enums::ir_op_kind::IrOpKind;
4use crate::functions::get_live_in_out_value_count::get_live_in_out_value_count;
5use crate::functions::get_live_out_value_count::get_live_out_value_count;
6use crate::functions::try_get_next_block_in_chain::try_get_next_block_in_chain;
7use crate::macros::codegen_assert::CODEGEN_ASSERT;
8use crate::macros::op_a::op_a;
9use crate::records::ir_block::IrBlock;
10use crate::records::ir_function::IrFunction;
11use alloc::vec::Vec;
12
13pub fn collect_direct_block_jump_path(
14    function: &mut IrFunction,
15    visited: &mut Vec<u8>,
16    mut block: *mut IrBlock,
17) -> Vec<u32> {
18    CODEGEN_ASSERT!(get_live_out_value_count(function, unsafe { &mut *block }) == 0);
19
20    let mut path = Vec::new();
21
22    while !block.is_null() {
23        let mut next_block: *mut IrBlock = core::ptr::null_mut();
24
25        let (is_jump, target_op) = {
26            let term_inst = &mut function.instructions[unsafe { (*block).finish } as usize];
27            (term_inst.cmd == IrCmd::JUMP, op_a(term_inst))
28        };
29
30        if is_jump && target_op.kind() == IrOpKind::Block {
31            let target_block = function.block_op(target_op) as *mut IrBlock;
32            let target_idx = function.get_block_index(unsafe { &*target_block });
33
34            if visited[target_idx as usize] == 0
35                && unsafe { (*target_block).kind } == IrBlockKind::Internal
36            {
37                let (live_ins, live_outs) =
38                    get_live_in_out_value_count(function, unsafe { &mut *target_block }, true);
39
40                if live_ins == 0 && live_outs == 0 {
41                    visited[target_idx as usize] = 1;
42                    path.push(target_idx);
43
44                    next_block = target_block;
45
46                    loop {
47                        let next_in_chain =
48                            try_get_next_block_in_chain(function, unsafe { &mut *next_block });
49                        if !next_in_chain.is_null() {
50                            let next_in_chain_idx =
51                                function.get_block_index(unsafe { &*next_in_chain });
52                            visited[next_in_chain_idx as usize] = 1;
53                            path.push(next_in_chain_idx);
54                            next_block = next_in_chain;
55                        } else {
56                            break;
57                        }
58                    }
59                }
60            }
61        }
62
63        block = next_block;
64    }
65
66    path
67}