luaur-code-gen 0.1.0

Native (A64/X64) code generation for Luau (Rust).
Documentation
use crate::enums::ir_block_kind::IrBlockKind;
use crate::enums::ir_cmd::IrCmd;
use crate::functions::after_inst_for_n_loop::after_inst_for_n_loop;
use crate::functions::analyze_bytecode_types::analyze_bytecode_types;
use crate::functions::before_inst_for_n_prep::before_inst_for_n_prep;
use crate::functions::build_argument_type_checks::build_argument_type_checks;
use crate::functions::get_op_length::get_op_length;
use crate::functions::has_typed_parameters::has_typed_parameters;
use crate::functions::is_block_terminator::is_block_terminator;
use crate::functions::load_bytecode_type_info::load_bytecode_type_info;
use crate::functions::update_use_counts::update_use_counts;
use crate::records::bytecode_mapping::BytecodeMapping;
use crate::records::ir_builder::IrBuilder;
use crate::records::ir_op::IrOp;
use luaur_common::enums::luau_opcode::LuauOpcode;
use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;

impl IrBuilder {
    pub fn build_function_ir(&mut self, proto: *mut luaur_vm::records::proto::Proto) {
        unsafe {
            self.function.proto = proto;
            self.function.variadic = (*proto).is_vararg != 0;

            load_bytecode_type_info(&mut self.function);

            let generate_type_checks = has_typed_parameters(&self.function.bc_type_info);
            let mut entry = if generate_type_checks {
                self.block(IrBlockKind::Internal)
            } else {
                IrOp::default()
            };

            self.rebuild_bytecode_basic_blocks(proto);
            analyze_bytecode_types(&mut self.function, &*self.host_hooks);

            self.function.bc_mapping.resize(
                (*proto).sizecode as usize,
                BytecodeMapping {
                    ir_location: !0u32,
                    asm_location: !0u32,
                },
            );

            if generate_type_checks {
                self.begin_block(entry);
                build_argument_type_checks(self, entry);

                let block0 = self.block_at_inst(0);
                self.inst_ir_cmd_ir_op(IrCmd::JUMP, block0);
            } else {
                entry = self.block_at_inst(0);
            }

            self.function.entry_block = entry.index();

            let mut i = 0i32;
            while i < (*proto).sizecode {
                let pc = (*proto).code.add(i as usize);
                let op = LuauOpcode::from(LUAU_INSN_OP(*pc) as u8);
                let mut nexti = i + get_op_length(op);
                debug_assert!(nexti <= (*proto).sizecode);

                self.function.bc_mapping[i as usize] = BytecodeMapping {
                    ir_location: self.function.instructions.len() as u32,
                    asm_location: !0u32,
                };

                if self.inst_index_to_block[i as usize] != !0u32 {
                    let block = self.block_at_inst(i as u32);
                    self.begin_block(block);
                    self.function.block_op(block).startpc = i as u32;
                }

                if op == LuauOpcode::LOP_FORNPREP {
                    before_inst_for_n_prep(self, pc, i);
                }

                if !self.in_terminated_block {
                    if self.interrupt_requested {
                        self.interrupt_requested = false;
                        let pcpos = self.const_uint(i as u32);
                        self.inst_ir_cmd_ir_op(IrCmd::INTERRUPT, pcpos);
                    }

                    self.translate_inst(op, pc, i);

                    if self.cmd_skip_target != -1 {
                        nexti = self.cmd_skip_target;
                        self.cmd_skip_target = -1;
                    }
                }

                if op == LuauOpcode::LOP_FORNLOOP {
                    after_inst_for_n_loop(self, pc);
                }

                i = nexti;
                debug_assert!(i <= (*proto).sizecode);

                if (i as usize) < self.inst_index_to_block.len()
                    && self.inst_index_to_block[i as usize] != !0u32
                {
                    if let Some(last) = self.function.instructions.last() {
                        if !is_block_terminator(last.cmd) {
                            let block = self.block_at_inst(i as u32);
                            self.inst_ir_cmd_ir_op(IrCmd::JUMP, block);
                        }
                    }
                }
            }

            update_use_counts(&mut self.function);
        }
    }
}