Skip to main content

luaur_code_gen/functions/
lower_function.rs

1//! @interface-stub
2use 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}