luaur-code-gen 0.1.1

Native (A64/X64) code generation for Luau (Rust).
Documentation
use crate::enums::ir_block_kind::IrBlockKind;
use crate::enums::ir_cmd::IrCmd;
use crate::enums::ir_op_kind::IrOpKind;
use crate::functions::const_prop_in_block::const_prop_in_block;
use crate::functions::get_live_out_value_count::get_live_out_value_count;
use crate::functions::save_block_exit_state::save_block_exit_state;
use crate::functions::setup_block_entry_state_optimize_const_prop::setup_block_entry_state_ir_builder_ir_function_ir_block_const_prop_state;
use crate::macros::codegen_assert::CODEGEN_ASSERT;
use crate::macros::op_a::op_a;
use crate::records::const_prop_state::ConstPropState;
use crate::records::ir_block::IrBlock;
use crate::records::ir_builder::IrBuilder;
use luaur_common::FFlag;

pub fn const_prop_in_block_chain(
    build: &mut IrBuilder,
    visited: &mut Vec<u8>,
    mut block: *mut IrBlock,
    state: &mut ConstPropState,
) {
    let function = &mut build.function as *mut _;

    state.clear();

    unsafe {
        setup_block_entry_state_ir_builder_ir_function_ir_block_const_prop_state(
            build,
            &mut *function,
            &*block,
            state,
        );
    }

    let start_sortkey = unsafe { (*block).sortkey };
    let mut chain_pos = 0u32;
    let mut last_block: *mut IrBlock = core::ptr::null_mut();

    while !block.is_null() {
        let block_idx = unsafe { (&*function).get_block_index(&*block) };
        CODEGEN_ASSERT!(visited[block_idx as usize] == 0);
        visited[block_idx as usize] = 1;

        unsafe {
            if state.in_safe_env && ((*block).flags & (1 << 0)) != 0 {
                (*block).flags &= !(1 << 0);
            }

            const_prop_in_block(build, &mut *block, state);

            if (*block).kind == IrBlockKind::Dead {
                break;
            }

            (*block).sortkey = start_sortkey;
            (*block).chainkey = chain_pos;
            chain_pos += 1;

            let term = (&mut (*function).instructions)[(*block).finish as usize].clone();
            let mut next_block: *mut IrBlock = core::ptr::null_mut();

            if term.cmd == IrCmd::JUMP {
                let target_op = op_a(&mut term.clone());
                if target_op.kind() == IrOpKind::Block {
                    let target_idx = target_op.index();
                    let target =
                        &mut (&mut (*function).blocks)[target_idx as usize] as *mut IrBlock;

                    if (*target).use_count == 1
                        && visited[target_idx as usize] == 0
                        && (*target).kind != IrBlockKind::Fallback
                    {
                        if get_live_out_value_count(&mut *function, &mut *target) != 0 {
                            if FFlag::LuauCodegenRecordAllBlockExitInfo.get() {
                                save_block_exit_state(&mut *function, &*block, state);
                            } else {
                                last_block = block;
                            }
                            break;
                        }

                        (*block).expected_next_block = target_idx;
                        next_block = target;
                    }
                }
            }

            if FFlag::LuauCodegenRecordAllBlockExitInfo.get() {
                save_block_exit_state(&mut *function, &*block, state);
            } else {
                last_block = block;
            }

            block = next_block;
        }
    }

    if !FFlag::LuauCodegenRecordAllBlockExitInfo.get() && !last_block.is_null() {
        unsafe {
            save_block_exit_state(&mut *function, &*last_block, state);
        }
    }
}