luaur-code-gen 0.1.3

Native (A64/X64) code generation for Luau (Rust).
Documentation
use crate::enums::builtin_impl_type::BuiltinImplType;
use crate::enums::ir_block_kind::IrBlockKind;
use crate::enums::ir_cmd::IrCmd;
use crate::enums::ir_op_kind::IrOpKind;
use crate::functions::get_op_length::get_op_length;
use crate::functions::translate_builtin::translate_builtin;
use crate::functions::vm_const_op::vm_const_op;
use crate::macros::codegen_assert::CODEGEN_ASSERT;
use crate::records::builtin_impl_result::BuiltinImplResult;
use crate::records::ir_builder::IrBuilder;
use crate::records::ir_op::IrOp;
use crate::type_aliases::instruction_ir_builder::Instruction;
use luaur_common::enums::luau_opcode::LuauOpcode;
use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
use luaur_common::macros::luau_insn_b::LUAU_INSN_B;
use luaur_common::macros::luau_insn_c::LUAU_INSN_C;
use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
use luaur_common::FFlag;
use luaur_vm::enums::lua_type::lua_Type;
use luaur_vm::macros::lua_multret::LUA_MULTRET;

pub fn translate_fast_call_n(
    build: &mut IrBuilder,
    pc: *const Instruction,
    pcpos: i32,
    custom_params: bool,
    custom_param_count: i32,
    custom_args: IrOp,
    custom_arg3: IrOp,
) -> IrOp {
    let opcode = unsafe { LuauOpcode::from(LUAU_INSN_OP(*pc) as u8) };
    let bfid = LUAU_INSN_A(unsafe { *pc }) as i32;
    let skip = LUAU_INSN_C(unsafe { *pc }) as i32;

    let call = unsafe { *pc.add(skip as usize + 1) };
    CODEGEN_ASSERT!(unsafe { LuauOpcode::from(LUAU_INSN_OP(call) as u8) } == LuauOpcode::LOP_CALL);
    let ra = LUAU_INSN_A(call) as i32;

    let nparams = if custom_params {
        custom_param_count
    } else {
        (LUAU_INSN_B(call) as i32) - 1
    };
    let nresults = (LUAU_INSN_C(call) as i32) - 1;
    let arg = if custom_params {
        LUAU_INSN_B(unsafe { *pc }) as i32
    } else {
        ra + 1
    };
    let args = if custom_params {
        custom_args
    } else {
        build.vm_reg((ra + 2) as u8)
    };

    let mut builtin_args = args;

    if args.kind() == IrOpKind::VmConst {
        CODEGEN_ASSERT!(build.function.proto.is_null() == false);
        let protok = unsafe {
            let idx = vm_const_op(args);
            let proto = build.function.proto;
            (*proto).k.add(idx as usize).read()
        };

        if protok.tt == lua_Type::LUA_TNUMBER as i32 {
            builtin_args = build.const_double(unsafe { protok.value.n });
        } else if FFlag::LuauCodegenInteger2.get()
            && FFlag::LuauCodegenIntegerFastcall2k.get()
            && protok.tt == lua_Type::LUA_TINTEGER as i32
        {
            builtin_args = build.const_int_64(unsafe { protok.value.l });
        }
    }

    let builtin_arg3 = if custom_params {
        custom_arg3
    } else {
        build.vm_reg((ra + 3) as u8)
    };

    let fallback = build.fallback_block(pcpos as u32);

    build.check_safe_env(pcpos + get_op_length(opcode));

    let br = translate_builtin(
        build,
        bfid,
        ra,
        arg,
        builtin_args,
        builtin_arg3,
        nparams,
        nresults,
        fallback,
        pcpos + get_op_length(opcode),
    );

    if br.r#type != BuiltinImplType::None {
        CODEGEN_ASSERT!(nparams != LUA_MULTRET);

        if nresults == LUA_MULTRET {
            let reg_ra = build.vm_reg(ra as u8);
            let actual_count = build.const_int(br.actual_result_count);
            build.inst_ir_cmd_ir_op_ir_op(IrCmd::ADJUST_STACK_TO_REG, reg_ra, actual_count);
        } else {
            let reg_ra_next = build.vm_reg((ra + 1) as u8);
            let dead_count = build.const_int(-1);
            build.inst_ir_cmd_ir_op_ir_op(IrCmd::MARK_DEAD, reg_ra_next, dead_count);
        }

        if br.r#type != BuiltinImplType::UsesFallback {
            let block = build.function.block_op(fallback);
            unsafe {
                (*block).kind = IrBlockKind::Dead;
            }

            return build.undef();
        }
    } else {
        let arg3 = if custom_params {
            custom_arg3
        } else {
            build.undef()
        };

        let savedpc = build.const_uint((pcpos + get_op_length(opcode)) as u32);
        build.inst_ir_cmd_ir_op(IrCmd::SET_SAVEDPC, savedpc);

        let bfid_op = build.const_uint(bfid as u32);
        let reg_ra = build.vm_reg(ra as u8);
        let reg_arg = build.vm_reg(arg as u8);
        let nparams_op = build.const_int(nparams);
        let nresults_op = build.const_int(nresults);
        let res = build.inst_ir_cmd_ir_op_ir_op_ir_op_ir_op_ir_op_ir_op_ir_op(
            IrCmd::INVOKE_FASTCALL,
            bfid_op,
            reg_ra,
            reg_arg,
            args,
            arg3,
            nparams_op,
            nresults_op,
        );
        build.inst_ir_cmd_ir_op_ir_op(IrCmd::CHECK_FASTCALL_RES, res, fallback);

        if nresults == LUA_MULTRET {
            let reg_ra = build.vm_reg(ra as u8);
            build.inst_ir_cmd_ir_op_ir_op(IrCmd::ADJUST_STACK_TO_REG, reg_ra, res);
        } else if nparams == LUA_MULTRET {
            build.inst_ir_cmd(IrCmd::ADJUST_STACK_TO_TOP);
        }
    }

    fallback
}