Skip to main content

luaur_code_gen/methods/
ir_builder_build_function_ir.rs

1use crate::enums::ir_block_kind::IrBlockKind;
2use crate::enums::ir_cmd::IrCmd;
3use crate::functions::after_inst_for_n_loop::after_inst_for_n_loop;
4use crate::functions::analyze_bytecode_types::analyze_bytecode_types;
5use crate::functions::before_inst_for_n_prep::before_inst_for_n_prep;
6use crate::functions::build_argument_type_checks::build_argument_type_checks;
7use crate::functions::get_op_length::get_op_length;
8use crate::functions::has_typed_parameters::has_typed_parameters;
9use crate::functions::is_block_terminator::is_block_terminator;
10use crate::functions::load_bytecode_type_info::load_bytecode_type_info;
11use crate::functions::update_use_counts::update_use_counts;
12use crate::records::bytecode_mapping::BytecodeMapping;
13use crate::records::ir_builder::IrBuilder;
14use crate::records::ir_op::IrOp;
15use luaur_common::enums::luau_opcode::LuauOpcode;
16use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
17
18impl IrBuilder {
19    pub fn build_function_ir(&mut self, proto: *mut luaur_vm::records::proto::Proto) {
20        unsafe {
21            self.function.proto = proto;
22            self.function.variadic = (*proto).is_vararg != 0;
23
24            load_bytecode_type_info(&mut self.function);
25
26            let generate_type_checks = has_typed_parameters(&self.function.bc_type_info);
27            let mut entry = if generate_type_checks {
28                self.block(IrBlockKind::Internal)
29            } else {
30                IrOp::default()
31            };
32
33            self.rebuild_bytecode_basic_blocks(proto);
34            analyze_bytecode_types(&mut self.function, &*self.host_hooks);
35
36            self.function.bc_mapping.resize(
37                (*proto).sizecode as usize,
38                BytecodeMapping {
39                    ir_location: !0u32,
40                    asm_location: !0u32,
41                },
42            );
43
44            if generate_type_checks {
45                self.begin_block(entry);
46                build_argument_type_checks(self, entry);
47
48                let block0 = self.block_at_inst(0);
49                self.inst_ir_cmd_ir_op(IrCmd::JUMP, block0);
50            } else {
51                entry = self.block_at_inst(0);
52            }
53
54            self.function.entry_block = entry.index();
55
56            let mut i = 0i32;
57            while i < (*proto).sizecode {
58                let pc = (*proto).code.add(i as usize);
59                let op = LuauOpcode::from(LUAU_INSN_OP(*pc) as u8);
60                let mut nexti = i + get_op_length(op);
61                debug_assert!(nexti <= (*proto).sizecode);
62
63                self.function.bc_mapping[i as usize] = BytecodeMapping {
64                    ir_location: self.function.instructions.len() as u32,
65                    asm_location: !0u32,
66                };
67
68                if self.inst_index_to_block[i as usize] != !0u32 {
69                    let block = self.block_at_inst(i as u32);
70                    self.begin_block(block);
71                    self.function.block_op(block).startpc = i as u32;
72                }
73
74                if op == LuauOpcode::LOP_FORNPREP {
75                    before_inst_for_n_prep(self, pc, i);
76                }
77
78                if !self.in_terminated_block {
79                    if self.interrupt_requested {
80                        self.interrupt_requested = false;
81                        let pcpos = self.const_uint(i as u32);
82                        self.inst_ir_cmd_ir_op(IrCmd::INTERRUPT, pcpos);
83                    }
84
85                    self.translate_inst(op, pc, i);
86
87                    if self.cmd_skip_target != -1 {
88                        nexti = self.cmd_skip_target;
89                        self.cmd_skip_target = -1;
90                    }
91                }
92
93                if op == LuauOpcode::LOP_FORNLOOP {
94                    after_inst_for_n_loop(self, pc);
95                }
96
97                i = nexti;
98                debug_assert!(i <= (*proto).sizecode);
99
100                if (i as usize) < self.inst_index_to_block.len()
101                    && self.inst_index_to_block[i as usize] != !0u32
102                {
103                    if let Some(last) = self.function.instructions.last() {
104                        if !is_block_terminator(last.cmd) {
105                            let block = self.block_at_inst(i as u32);
106                            self.inst_ir_cmd_ir_op(IrCmd::JUMP, block);
107                        }
108                    }
109                }
110            }
111
112            update_use_counts(&mut self.function);
113        }
114    }
115}