luaur-code-gen 0.1.1

Native (A64/X64) code generation for Luau (Rust).
Documentation
use crate::enums::condition_x_64::ConditionX64;
use crate::enums::size_x_64::SizeX64;
use crate::functions::emit_update_base_emit_common_x_64::emit_update_base;
use crate::records::assembly_builder_x_64::AssemblyBuilderX64;
use crate::records::ir_call_wrapper_x_64::IrCallWrapperX64;
use crate::records::ir_data::k_invalid_inst_idx;
use crate::records::ir_op::IrOp;
use crate::records::ir_reg_alloc_x_64::IrRegAllocX64;
use crate::records::label::Label;
use crate::records::native_context::NativeContext;
use crate::records::operand_x_64::OperandX64;
use crate::records::register_x_64::RegisterX64;
use crate::records::scoped_reg_x_64::ScopedRegX64;
use crate::records::scoped_spills::ScopedSpills;
use luaur_vm::records::global_state::global_State;
use luaur_vm::records::lua_state::lua_State;

pub fn call_step_gc(regs: &mut IrRegAllocX64, build: &mut AssemblyBuilderX64) {
    let mut skip = Label::default();

    {
        let mut tmp1 = ScopedRegX64 {
            owner: core::ptr::null_mut(),
            reg: RegisterX64::noreg,
        };
        tmp1.scoped_reg_x_64_ir_reg_alloc_x_64_size_x_64(regs, SizeX64::qword);

        let mut tmp2 = ScopedRegX64 {
            owner: core::ptr::null_mut(),
            reg: RegisterX64::noreg,
        };
        tmp2.scoped_reg_x_64_ir_reg_alloc_x_64_size_x_64(regs, SizeX64::qword);

        build.mov(
            OperandX64::reg(tmp1.reg),
            mem(
                SizeX64::qword,
                r_state(),
                core::mem::offset_of!(lua_State, global) as i32,
            ),
        );
        build.mov(
            OperandX64::reg(tmp2.reg),
            mem(
                SizeX64::qword,
                tmp1.reg,
                core::mem::offset_of!(global_State, totalbytes) as i32,
            ),
        );
        build.cmp(
            OperandX64::reg(tmp2.reg),
            mem(
                SizeX64::qword,
                tmp1.reg,
                core::mem::offset_of!(global_State, GCthreshold) as i32,
            ),
        );
        build.jcc(ConditionX64::Below, &mut skip);
    }

    {
        let _spill_guard = {
            let mut guard = ScopedSpills {
                owner: regs as *mut _,
                start_spill_id: 0,
            };
            guard.scoped_spills_scoped_spills_ir_reg_alloc_x_64(regs);
            guard
        };

        let mut call_wrap = IrCallWrapperX64::ir_call_wrapper_x_64_ir_call_wrapper_x_64(
            regs,
            build,
            k_invalid_inst_idx,
        );
        call_wrap.add_argument_size_x_64_operand_x_64_ir_op(
            SizeX64::qword,
            OperandX64::reg(r_state()),
            IrOp::ir_op(),
        );
        call_wrap.add_argument_size_x_64_operand_x_64_ir_op(
            SizeX64::dword,
            OperandX64::imm(1),
            IrOp::ir_op(),
        );
        call_wrap.call(&mem(
            SizeX64::qword,
            r_native_context(),
            core::mem::offset_of!(NativeContext, luaC_step) as i32,
        ));
        emit_update_base(build);
    }

    build.set_label_label(&mut skip);
}

const fn reg(index: u8, size: SizeX64) -> RegisterX64 {
    RegisterX64 {
        bits: (index << RegisterX64::INDEX_SHIFT) | size as u8,
    }
}

const fn r_state() -> RegisterX64 {
    reg(15, SizeX64::qword)
}

const fn r_native_context() -> RegisterX64 {
    reg(13, SizeX64::qword)
}

fn mem(size: SizeX64, base: RegisterX64, disp: i32) -> OperandX64 {
    OperandX64::mem(size, RegisterX64::noreg, 1, base, disp)
}