luaur-code-gen 0.1.3

Native (A64/X64) code generation for Luau (Rust).
Documentation
use crate::enums::ir_block_kind::IrBlockKind;
use crate::enums::ir_op_kind::IrOpKind;
use crate::functions::is_pseudo::is_pseudo;
use crate::records::ir_block::IrBlock;
use crate::records::ir_function::IrFunction;
use crate::records::ir_op::IrOp;
use luaur_common::FFlag;

pub fn update_last_use_locations(function: &mut IrFunction, sorted_blocks: &Vec<u32>) {
    for block_idx in sorted_blocks {
        let block: IrBlock = function.blocks[*block_idx as usize];

        if block.kind == IrBlockKind::Dead {
            continue;
        }

        let mut sync_arg_ops: Option<Vec<IrOp>> = None;

        if FFlag::LuauCodegenVmExitSync.get() && block.kind == IrBlockKind::ExitSync {
            if let Some(key) = function.block_to_vm_exit_map.find(block_idx) {
                if let Some(sync_info) = function.vm_exit_info.find(key) {
                    sync_arg_ops = Some(sync_info.arg_ops.as_slice().to_vec());
                }
            }

            crate::macros::codegen_assert::CODEGEN_ASSERT!(sync_arg_ops.is_some());
        }

        crate::macros::codegen_assert::CODEGEN_ASSERT!(block.start != !0u32);
        crate::macros::codegen_assert::CODEGEN_ASSERT!(block.finish != !0u32);

        for inst_idx in block.start..=block.finish {
            crate::macros::codegen_assert::CODEGEN_ASSERT!(
                (inst_idx as usize) < function.instructions.len()
            );

            let inst = function.instructions[inst_idx as usize].clone();

            if is_pseudo(inst.cmd) {
                continue;
            }

            if FFlag::LuauCodegenVmExitSync.get() {
                for op in inst.ops.as_slice() {
                    if let Some(sync_arg_ops) = &sync_arg_ops {
                        if sync_arg_ops.iter().any(|arg_op| arg_op == op) {
                            continue;
                        }
                    }

                    update_last_use_for_op(function, inst_idx, *op);
                }
            } else {
                for op in inst.ops.as_slice() {
                    if op.kind() == IrOpKind::Inst {
                        function.instructions[op.index() as usize].last_use = inst_idx;
                    }
                }
            }
        }
    }
}

fn update_last_use_for_op(function: &mut IrFunction, inst_idx: u32, op: IrOp) {
    if op.kind() == IrOpKind::Inst {
        function.instructions[op.index() as usize].last_use = inst_idx;
    } else if op.kind() == IrOpKind::Block
        && function.blocks[op.index() as usize].kind == IrBlockKind::ExitSync
    {
        let arg_ops = function
            .vm_exit_info
            .find(&inst_idx)
            .map(|sync_info| sync_info.arg_ops.as_slice().to_vec());

        if let Some(arg_ops) = arg_ops {
            for arg_op in arg_ops {
                update_last_use_for_op(function, inst_idx, arg_op);
            }
        }
    }
}