Skip to main content

luaur_code_gen/functions/
try_create_linear_block.rs

1use crate::enums::ir_block_kind::IrBlockKind;
2use crate::enums::ir_cmd::IrCmd;
3use crate::enums::ir_op_kind::IrOpKind;
4use crate::functions::collect_direct_block_jump_path::collect_direct_block_jump_path;
5use crate::functions::const_prop_in_block::const_prop_in_block;
6use crate::functions::replace_ir_utils::replace_ir_function_ir_op_ir_op;
7use crate::functions::setup_block_entry_state_optimize_const_prop::setup_block_entry_state_ir_builder_ir_function_ir_block_const_prop_state;
8use crate::macros::op_a::op_a;
9use crate::records::const_prop_state::ConstPropState;
10use crate::records::ir_block::IrBlock;
11use crate::records::ir_builder::IrBuilder;
12use crate::records::ir_function::IrFunction;
13use alloc::vec::Vec;
14
15pub fn try_create_linear_block(
16    build: &mut IrBuilder,
17    visited: &mut Vec<u8>,
18    starting_block: *mut IrBlock,
19    state: &mut ConstPropState,
20) {
21    let function: *mut IrFunction = &mut build.function;
22
23    unsafe {
24        let block_idx = (&*function).get_block_index(&*starting_block);
25        crate::macros::codegen_assert::CODEGEN_ASSERT!(visited[block_idx as usize] == 0);
26        visited[block_idx as usize] = 1;
27
28        let term_inst_idx = (*starting_block).finish;
29        let term_inst = (&mut (*function).instructions)[term_inst_idx as usize].clone();
30
31        if term_inst.cmd != IrCmd::JUMP {
32            return;
33        }
34
35        let target_op = op_a(&mut term_inst.clone());
36        if target_op.kind() != IrOpKind::Block {
37            return;
38        }
39
40        if (&(*function).blocks)[target_op.index() as usize].use_count == 1 {
41            return;
42        }
43
44        let target_block_idx = target_op.index();
45        let path = collect_direct_block_jump_path(&mut *function, visited, starting_block);
46
47        if (path.len() as i32) < luaur_common::FInt::LuauCodeGenMinLinearBlockPath.get() {
48            return;
49        }
50
51        state.clear();
52
53        if luaur_common::FFlag::LuauCodegenLinearSetupEntryState3.get() {
54            setup_block_entry_state_ir_builder_ir_function_ir_block_const_prop_state(
55                build,
56                &mut *function,
57                &*starting_block,
58                state,
59            );
60        }
61
62        const_prop_in_block(build, &mut *starting_block, state);
63
64        if luaur_common::FFlag::LuauCodegenLinearSetupEntryState3.get() {
65            let current_target = {
66                let inst = &mut (&mut (*function).instructions)[term_inst_idx as usize].clone();
67                op_a(inst).index()
68            };
69
70            if (*starting_block).finish != term_inst_idx || current_target != target_block_idx {
71                return;
72            }
73
74            if (&(*function).blocks)[target_block_idx as usize].use_count == 1 {
75                return;
76            }
77        } else {
78            let current_target = {
79                let inst =
80                    &mut (&mut (*function).instructions)[(*starting_block).finish as usize].clone();
81                op_a(inst).index()
82            };
83
84            if current_target != target_block_idx {
85                crate::macros::codegen_assert::CODEGEN_ASSERT!(false);
86                return;
87            }
88        }
89
90        let starting_sort_key = (*starting_block).sortkey;
91        let starting_chain_key = (*starting_block).chainkey;
92
93        let new_block = build.block(IrBlockKind::Linearized);
94        visited.push(0);
95
96        build.begin_block(new_block);
97
98        build.function.blocks[new_block.index() as usize].sortkey = starting_sort_key;
99        build.function.blocks[new_block.index() as usize].chainkey = starting_chain_key + 1;
100        build.function.blocks[block_idx as usize].expected_next_block = new_block.index();
101
102        let op_ptr = {
103            let inst = &mut build.function.instructions[term_inst_idx as usize];
104            &mut inst.ops.as_mut_slice()[0] as *mut _
105        };
106        replace_ir_function_ir_op_ir_op(&mut build.function, &mut *op_ptr, new_block);
107
108        build.clone(path.clone(), true);
109
110        if build.function.cfg.r#in.len() == new_block.index() as usize {
111            crate::macros::codegen_assert::CODEGEN_ASSERT!(
112                build.function.cfg.r#in.len() == build.function.cfg.out.len()
113            );
114            crate::macros::codegen_assert::CODEGEN_ASSERT!(
115                build.function.cfg.r#in.len() == build.function.cfg.def.len()
116            );
117
118            build
119                .function
120                .cfg
121                .r#in
122                .push(build.function.cfg.r#in[path[0] as usize]);
123            build
124                .function
125                .cfg
126                .out
127                .push(build.function.cfg.out[*path.last().unwrap() as usize]);
128            build.function.cfg.def.push(Default::default());
129
130            let out_vararg_seq = build.function.cfg.out.last().unwrap().vararg_seq;
131            let def_idx = build.function.cfg.def.len() - 1;
132
133            for &path_block_idx in &path {
134                let path_def = build.function.cfg.def[path_block_idx as usize];
135                for i in 0..build.function.cfg.def[def_idx].regs.len() {
136                    build.function.cfg.def[def_idx].regs[i] |= path_def.regs[i];
137                }
138
139                if path_def.vararg_seq && out_vararg_seq {
140                    build.function.cfg.def[def_idx].vararg_seq = true;
141                    build.function.cfg.def[def_idx].vararg_start = path_def.vararg_start;
142                }
143            }
144
145            build
146                .function
147                .cfg
148                .predecessors_offsets
149                .push(build.function.cfg.predecessors.len() as u32);
150            build.function.cfg.predecessors.push(block_idx);
151        }
152
153        let linear_block = &mut build.function.blocks[new_block.index() as usize] as *mut IrBlock;
154        const_prop_in_block(build, &mut *linear_block, state);
155    }
156}