luaur_code_gen/methods/
ir_builder_build_function_ir.rs1use 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}