luaur_code_gen/functions/
lower_function.rs1use crate::enums::code_gen_compilation_result::CodeGenCompilationResult;
3use crate::enums::ir_block_kind::IrBlockKind;
4use crate::enums::ir_cmd::IrCmd;
5use crate::functions::compute_cfg_block_edges::compute_cfg_block_edges;
6use crate::functions::compute_cfg_info::compute_cfg_info;
7use crate::functions::const_prop_in_block_chains::const_prop_in_block_chains;
8use crate::functions::create_linear_blocks::create_linear_blocks;
9use crate::functions::get_instruction_count_code_gen_lower::get_instruction_count_vector_ir_inst_ir_cmd;
10use crate::functions::get_sorted_block_order::get_sorted_block_order;
11use crate::functions::jit_rng_seed::jit_rng_seed;
12use crate::functions::kill_unused_blocks::kill_unused_blocks;
13use crate::functions::lower_ir_code_gen_lower::lower_ir_x_64_assembly_builder_x_64_ir_builder_vector_u32_module_helpers_proto_assembly_options_lowering_stats;
14use crate::functions::lower_ir_code_gen_lower_alt_b::lower_ir_a_64_assembly_builder_a_64_ir_builder_vector_u32_module_helpers_proto_assembly_options_lowering_stats;
15use crate::functions::mark_dead_stores_in_block_chains::mark_dead_stores_in_block_chains;
16use crate::functions::update_last_use_locations::update_last_use_locations;
17use crate::records::assembly_builder_a_64::AssemblyBuilderA64;
18use crate::records::assembly_builder_x_64::AssemblyBuilderX64;
19use crate::records::assembly_options::AssemblyOptions;
20use crate::records::ir_builder::IrBuilder;
21use crate::records::lowering_stats::LoweringStats;
22use crate::records::module_helpers::ModuleHelpers;
23use luaur_vm::functions::lua_clock::lua_clock;
24use luaur_vm::records::proto::Proto;
25
26pub unsafe fn lower_function_x_64(
27 ir: &mut IrBuilder,
28 build: &mut AssemblyBuilderX64,
29 helpers: &mut ModuleHelpers,
30 proto: *mut Proto,
31 options: AssemblyOptions,
32 stats: *mut LoweringStats,
33 code_gen_compilation_result: &mut CodeGenCompilationResult,
34) -> bool {
35 ir.function.stats = stats;
36 ir.function.record_counters = options.compilation_options.record_counters;
37
38 if options.compilation_options.nop_padding && !proto.is_null() {
39 ir.function.jit_rng_state = jit_rng_seed(proto as usize);
40 }
41
42 kill_unused_blocks(&mut ir.function);
43
44 let mut pre_opt_block_count = 0u32;
45 let mut max_block_instructions = 0u32;
46
47 for block in &ir.function.blocks {
48 if block.kind != IrBlockKind::Dead {
49 pre_opt_block_count += 1;
50 }
51
52 let block_instructions = block.finish.wrapping_sub(block.start);
53 max_block_instructions = max_block_instructions.max(block_instructions);
54 }
55
56 if !stats.is_null() {
57 (*stats).blocks_pre_opt += pre_opt_block_count;
58 (*stats).max_block_instructions = max_block_instructions;
59 }
60
61 if pre_opt_block_count >= luaur_common::FInt::CodegenHeuristicsBlockLimit.get() as u32 {
62 *code_gen_compilation_result = CodeGenCompilationResult::CodeGenOverflowBlockLimit;
63 return false;
64 }
65
66 if max_block_instructions
67 >= luaur_common::FInt::CodegenHeuristicsBlockInstructionLimit.get() as u32
68 {
69 *code_gen_compilation_result =
70 CodeGenCompilationResult::CodeGenOverflowBlockInstructionLimit;
71 return false;
72 }
73
74 compute_cfg_info(&mut ir.function);
75
76 const_prop_in_block_chains(ir);
77
78 if !luaur_common::FFlag::DebugCodegenOptSize.get() {
79 let mut start_time = 0.0;
80 let mut const_prop_instruction_count = 0u32;
81
82 if !stats.is_null() {
83 const_prop_instruction_count = get_instruction_count_vector_ir_inst_ir_cmd(
84 &ir.function.instructions,
85 IrCmd::SUBSTITUTE,
86 );
87 start_time = lua_clock();
88 }
89
90 create_linear_blocks(ir);
91
92 if !stats.is_null() {
93 (*stats).block_linearization_stats.time_seconds += lua_clock() - start_time;
94 const_prop_instruction_count = get_instruction_count_vector_ir_inst_ir_cmd(
95 &ir.function.instructions,
96 IrCmd::SUBSTITUTE,
97 )
98 .wrapping_sub(const_prop_instruction_count);
99 (*stats)
100 .block_linearization_stats
101 .const_prop_instruction_count += const_prop_instruction_count;
102 }
103 }
104
105 mark_dead_stores_in_block_chains(ir);
106
107 compute_cfg_block_edges(&mut ir.function);
108
109 let sorted_blocks = get_sorted_block_order(&mut ir.function);
110
111 update_last_use_locations(&mut ir.function, &sorted_blocks);
112
113 if !stats.is_null() {
114 for block in &ir.function.blocks {
115 if block.kind != IrBlockKind::Dead {
116 (*stats).blocks_post_opt += 1;
117 }
118 }
119 }
120
121 let result = lower_ir_x_64_assembly_builder_x_64_ir_builder_vector_u32_module_helpers_proto_assembly_options_lowering_stats(
122 build,
123 ir,
124 &sorted_blocks,
125 helpers,
126 proto,
127 options,
128 stats,
129 );
130
131 if !result {
132 *code_gen_compilation_result = CodeGenCompilationResult::CodeGenLoweringFailure;
133 }
134
135 result
136}
137
138pub unsafe fn lower_function_a_64(
139 ir: &mut IrBuilder,
140 build: &mut AssemblyBuilderA64,
141 helpers: &mut ModuleHelpers,
142 proto: *mut Proto,
143 options: AssemblyOptions,
144 stats: *mut LoweringStats,
145 code_gen_compilation_result: &mut CodeGenCompilationResult,
146) -> bool {
147 ir.function.stats = stats;
148 ir.function.record_counters = options.compilation_options.record_counters;
149
150 if options.compilation_options.nop_padding && !proto.is_null() {
151 ir.function.jit_rng_state = jit_rng_seed(proto as usize);
152 }
153
154 kill_unused_blocks(&mut ir.function);
155
156 let mut pre_opt_block_count = 0u32;
157 let mut max_block_instructions = 0u32;
158
159 for block in &ir.function.blocks {
160 if block.kind != IrBlockKind::Dead {
161 pre_opt_block_count += 1;
162 }
163
164 let block_instructions = block.finish.wrapping_sub(block.start);
165 max_block_instructions = max_block_instructions.max(block_instructions);
166 }
167
168 if !stats.is_null() {
169 (*stats).blocks_pre_opt += pre_opt_block_count;
170 (*stats).max_block_instructions = max_block_instructions;
171 }
172
173 if pre_opt_block_count >= luaur_common::FInt::CodegenHeuristicsBlockLimit.get() as u32 {
174 *code_gen_compilation_result = CodeGenCompilationResult::CodeGenOverflowBlockLimit;
175 return false;
176 }
177
178 if max_block_instructions
179 >= luaur_common::FInt::CodegenHeuristicsBlockInstructionLimit.get() as u32
180 {
181 *code_gen_compilation_result =
182 CodeGenCompilationResult::CodeGenOverflowBlockInstructionLimit;
183 return false;
184 }
185
186 compute_cfg_info(&mut ir.function);
187
188 const_prop_in_block_chains(ir);
189
190 if !luaur_common::FFlag::DebugCodegenOptSize.get() {
191 let mut start_time = 0.0;
192 let mut const_prop_instruction_count = 0u32;
193
194 if !stats.is_null() {
195 const_prop_instruction_count = get_instruction_count_vector_ir_inst_ir_cmd(
196 &ir.function.instructions,
197 IrCmd::SUBSTITUTE,
198 );
199 start_time = lua_clock();
200 }
201
202 create_linear_blocks(ir);
203
204 if !stats.is_null() {
205 (*stats).block_linearization_stats.time_seconds += lua_clock() - start_time;
206 const_prop_instruction_count = get_instruction_count_vector_ir_inst_ir_cmd(
207 &ir.function.instructions,
208 IrCmd::SUBSTITUTE,
209 )
210 .wrapping_sub(const_prop_instruction_count);
211 (*stats)
212 .block_linearization_stats
213 .const_prop_instruction_count += const_prop_instruction_count;
214 }
215 }
216
217 mark_dead_stores_in_block_chains(ir);
218
219 compute_cfg_block_edges(&mut ir.function);
220
221 let sorted_blocks = get_sorted_block_order(&mut ir.function);
222
223 update_last_use_locations(&mut ir.function, &sorted_blocks);
224
225 if !stats.is_null() {
226 for block in &ir.function.blocks {
227 if block.kind != IrBlockKind::Dead {
228 (*stats).blocks_post_opt += 1;
229 }
230 }
231 }
232
233 let result = lower_ir_a_64_assembly_builder_a_64_ir_builder_vector_u32_module_helpers_proto_assembly_options_lowering_stats(
234 build,
235 ir,
236 &sorted_blocks,
237 helpers,
238 proto,
239 options,
240 stats,
241 );
242
243 if !result {
244 *code_gen_compilation_result = CodeGenCompilationResult::CodeGenLoweringFailure;
245 }
246
247 result
248}