luaur-compiler 0.1.3

Luau source-to-bytecode compiler (Rust).
Documentation
use crate::functions::compute_cost::compute_cost;
use crate::records::compiler::Compiler;
use luaur_ast::records::ast_expr_call::AstExprCall;
use luaur_ast::records::ast_expr_function::AstExprFunction;
use luaur_common::macros::luau_assert::LUAU_ASSERT;

impl Compiler {
    pub fn try_compile_inlined_call(
        &mut self,
        expr: *mut AstExprCall,
        func: *mut AstExprFunction,
        target: u8,
        target_count: u8,
        mult_ret: bool,
        threshold_base: i32,
        threshold_max_boost: i32,
        depth_limit: i32,
    ) -> bool {
        unsafe {
            let fi = self.functions.find(&func);
            LUAU_ASSERT!(fi.is_some());
            let fi = fi.unwrap();
            let fi_stack_size = fi.stack_size;
            let mut call_cost_model = fi.cost_model;
            let fi_cost_model = fi.cost_model;

            if self.reg_top > 128 || fi_stack_size > 32 {
                (*self.bytecode)
                    .add_debug_remark(format_args!("inlining failed: high register pressure"));
                return false;
            }

            if self.inline_frames.len() as i32 >= depth_limit {
                (*self.bytecode)
                    .add_debug_remark(format_args!("inlining failed: too many inlined frames"));
                return false;
            }

            for frame in &self.inline_frames {
                if frame.func == func {
                    (*self.bytecode).add_debug_remark(format_args!(
                        "inlining failed: can't inline recursive calls"
                    ));
                    return false;
                }
            }

            if mult_ret {
                (*self.bytecode).add_debug_remark(format_args!(
                    "inlining failed: can't convert fixed returns to multret"
                ));
                return false;
            }

            let mut varc = [false; 8];
            let mut has_constant = false;

            let mut i = 0usize;
            while i < (*func).args.size && i < (*expr).args.size && i < 8 {
                if self.is_constant(*(*expr).args.data.add(i)) {
                    varc[i] = true;
                    has_constant = true;
                }
                i += 1;
            }

            if (*expr).args.size != 0
                && !self.is_expr_mult_ret(*(*expr).args.data.add((*expr).args.size - 1))
            {
                i = (*expr).args.size;
                while i < (*func).args.size && i < 8 {
                    varc[i] = true;
                    has_constant = true;
                    i += 1;
                }
            }

            if has_constant {
                call_cost_model = self.cost_model_inlined_call(expr, func);
            }

            let inlined_cost = compute_cost(
                call_cost_model,
                varc.as_ptr(),
                core::cmp::min((*func).args.size, 8),
            );
            let baseline_cost = compute_cost(fi_cost_model, core::ptr::null(), 0) + 3;
            let inline_profit = if inlined_cost == 0 {
                threshold_max_boost
            } else {
                core::cmp::min(threshold_max_boost, 100 * baseline_cost / inlined_cost)
            };

            let threshold = threshold_base * inline_profit / 100;

            if inlined_cost > threshold {
                (*self.bytecode).add_debug_remark(format_args!(
                    "inlining failed: too expensive (cost {}, profit {:.2}x)",
                    inlined_cost,
                    inline_profit as f64 / 100.0
                ));
                return false;
            }

            (*self.bytecode).add_debug_remark(format_args!(
                "inlining succeeded (cost {}, profit {:.2}x, depth {})",
                inlined_cost,
                inline_profit as f64 / 100.0,
                self.inline_frames.len() as i32
            ));

            self.compile_inlined_call(expr, func, target, target_count);
            true
        }
    }
}