use crate::enums::ir_block_kind::IrBlockKind;
use crate::enums::ir_cmd::IrCmd;
use crate::enums::ir_op_kind::IrOpKind;
use crate::functions::collect_direct_block_jump_path::collect_direct_block_jump_path;
use crate::functions::const_prop_in_block::const_prop_in_block;
use crate::functions::replace_ir_utils::replace_ir_function_ir_op_ir_op;
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::op_a::op_a;
use crate::records::const_prop_state::ConstPropState;
use crate::records::ir_block::IrBlock;
use crate::records::ir_builder::IrBuilder;
use crate::records::ir_function::IrFunction;
use alloc::vec::Vec;
pub fn try_create_linear_block(
build: &mut IrBuilder,
visited: &mut Vec<u8>,
starting_block: *mut IrBlock,
state: &mut ConstPropState,
) {
let function: *mut IrFunction = &mut build.function;
unsafe {
let block_idx = (&*function).get_block_index(&*starting_block);
crate::macros::codegen_assert::CODEGEN_ASSERT!(visited[block_idx as usize] == 0);
visited[block_idx as usize] = 1;
let term_inst_idx = (*starting_block).finish;
let term_inst = (&mut (*function).instructions)[term_inst_idx as usize].clone();
if term_inst.cmd != IrCmd::JUMP {
return;
}
let target_op = op_a(&mut term_inst.clone());
if target_op.kind() != IrOpKind::Block {
return;
}
if (&(*function).blocks)[target_op.index() as usize].use_count == 1 {
return;
}
let target_block_idx = target_op.index();
let path = collect_direct_block_jump_path(&mut *function, visited, starting_block);
if (path.len() as i32) < luaur_common::FInt::LuauCodeGenMinLinearBlockPath.get() {
return;
}
state.clear();
if luaur_common::FFlag::LuauCodegenLinearSetupEntryState3.get() {
setup_block_entry_state_ir_builder_ir_function_ir_block_const_prop_state(
build,
&mut *function,
&*starting_block,
state,
);
}
const_prop_in_block(build, &mut *starting_block, state);
if luaur_common::FFlag::LuauCodegenLinearSetupEntryState3.get() {
let current_target = {
let inst = &mut (&mut (*function).instructions)[term_inst_idx as usize].clone();
op_a(inst).index()
};
if (*starting_block).finish != term_inst_idx || current_target != target_block_idx {
return;
}
if (&(*function).blocks)[target_block_idx as usize].use_count == 1 {
return;
}
} else {
let current_target = {
let inst =
&mut (&mut (*function).instructions)[(*starting_block).finish as usize].clone();
op_a(inst).index()
};
if current_target != target_block_idx {
crate::macros::codegen_assert::CODEGEN_ASSERT!(false);
return;
}
}
let starting_sort_key = (*starting_block).sortkey;
let starting_chain_key = (*starting_block).chainkey;
let new_block = build.block(IrBlockKind::Linearized);
visited.push(0);
build.begin_block(new_block);
build.function.blocks[new_block.index() as usize].sortkey = starting_sort_key;
build.function.blocks[new_block.index() as usize].chainkey = starting_chain_key + 1;
build.function.blocks[block_idx as usize].expected_next_block = new_block.index();
let op_ptr = {
let inst = &mut build.function.instructions[term_inst_idx as usize];
&mut inst.ops.as_mut_slice()[0] as *mut _
};
replace_ir_function_ir_op_ir_op(&mut build.function, &mut *op_ptr, new_block);
build.clone(path.clone(), true);
if build.function.cfg.r#in.len() == new_block.index() as usize {
crate::macros::codegen_assert::CODEGEN_ASSERT!(
build.function.cfg.r#in.len() == build.function.cfg.out.len()
);
crate::macros::codegen_assert::CODEGEN_ASSERT!(
build.function.cfg.r#in.len() == build.function.cfg.def.len()
);
build
.function
.cfg
.r#in
.push(build.function.cfg.r#in[path[0] as usize]);
build
.function
.cfg
.out
.push(build.function.cfg.out[*path.last().unwrap() as usize]);
build.function.cfg.def.push(Default::default());
let out_vararg_seq = build.function.cfg.out.last().unwrap().vararg_seq;
let def_idx = build.function.cfg.def.len() - 1;
for &path_block_idx in &path {
let path_def = build.function.cfg.def[path_block_idx as usize];
for i in 0..build.function.cfg.def[def_idx].regs.len() {
build.function.cfg.def[def_idx].regs[i] |= path_def.regs[i];
}
if path_def.vararg_seq && out_vararg_seq {
build.function.cfg.def[def_idx].vararg_seq = true;
build.function.cfg.def[def_idx].vararg_start = path_def.vararg_start;
}
}
build
.function
.cfg
.predecessors_offsets
.push(build.function.cfg.predecessors.len() as u32);
build.function.cfg.predecessors.push(block_idx);
}
let linear_block = &mut build.function.blocks[new_block.index() as usize] as *mut IrBlock;
const_prop_in_block(build, &mut *linear_block, state);
}
}