use crate::enums::ir_cmd::IrCmd;
use crate::enums::ir_op_kind::IrOpKind;
use crate::functions::add_use::add_use;
use crate::functions::visit_arguments::visit_arguments;
use crate::functions::vm_exit_op::vm_exit_op;
use crate::macros::codegen_assert::CODEGEN_ASSERT;
use crate::records::ir_function::IrFunction;
use crate::records::ir_inst::IrInst;
use crate::records::ir_op::IrOp;
use crate::records::remove_dead_store_state::RemoveDeadStoreState;
use crate::records::vm_exit_store_info::VmExitStoreInfo;
use crate::records::vm_exit_store_record::VmExitStoreRecord;
use crate::records::vm_exit_sync_info::VmExitSyncInfo;
use luaur_vm::enums::lua_type::lua_Type;
const K_VM_EXIT_ENTRY_GUARD_PC: u32 = (1u32 << 28) - 1;
fn record_store(function: *mut IrFunction, store_info: &mut VmExitStoreInfo, inst_idx: u32) {
let backup = unsafe { (&(*function).instructions)[inst_idx as usize].clone() };
store_info
.stores
.push_back(VmExitStoreRecord { inst_idx, backup });
let inst_ptr: *mut IrInst = unsafe { &mut (&mut (*function).instructions)[inst_idx as usize] };
visit_arguments(unsafe { &mut *inst_ptr }, |op| {
add_use(unsafe { &mut *function }, op);
});
}
impl RemoveDeadStoreState {
pub fn check_live_ins(&mut self, op: IrOp, inst_idx: u32, record_vm_exit_sync: bool) {
let function: *mut IrFunction = self.function;
if op.kind() == IrOpKind::VmExit {
if luaur_common::FFlag::LuauCodegenVmExitSync.get()
&& record_vm_exit_sync
&& vm_exit_op(op) != K_VM_EXIT_ENTRY_GUARD_PC
{
let sync_info: *mut VmExitSyncInfo =
unsafe { (*function).vm_exit_info.get_or_insert(inst_idx) };
CODEGEN_ASSERT!(unsafe { (*sync_info).reg_stores.is_empty() });
unsafe {
(*sync_info).vm_exit = op;
}
self.recorded_vm_exit_syncs.push(inst_idx);
let max_reg = self.max_reg;
let mut i = max_reg;
while i >= 0 {
let tag_idx = self.info[i as usize].tag_inst_idx;
let value_idx = self.info[i as usize].value_inst_idx;
let tvalue_idx = self.info[i as usize].tvalue_inst_idx;
let ignore_at_exit = self.info[i as usize].ignore_at_exit;
let maybe_gco = self.info[i as usize].maybe_gco;
if (tag_idx != !0u32 && self.non_propagating_store.contains(&tag_idx))
|| (value_idx != !0u32 && self.non_propagating_store.contains(&value_idx))
|| (tvalue_idx != !0u32 && self.non_propagating_store.contains(&tvalue_idx))
{
self.use_reg(i as u8);
i -= 1;
continue;
}
if ignore_at_exit && !maybe_gco {
i -= 1;
continue;
}
if unsafe { (*sync_info).reg_stores.len() } >= 16 {
self.use_reg(i as u8);
i -= 1;
continue;
}
let has_partial_overlap =
(tag_idx != !0u32 || value_idx != !0u32) && tvalue_idx != !0u32;
if has_partial_overlap {
self.use_reg(i as u8);
i -= 1;
continue;
}
let mut store_info = VmExitStoreInfo::default();
store_info.reg = i as u8;
if tag_idx != !0u32 {
CODEGEN_ASSERT!(tvalue_idx == !0u32);
record_store(function, &mut store_info, tag_idx);
}
if value_idx != !0u32 {
CODEGEN_ASSERT!(tvalue_idx == !0u32);
record_store(function, &mut store_info, value_idx);
}
if tvalue_idx != !0u32 {
CODEGEN_ASSERT!(tag_idx == !0u32 && value_idx == !0u32);
let store_cmd =
unsafe { (&(*function).instructions)[tvalue_idx as usize].cmd };
let nil_tag_store = store_cmd == IrCmd::STORE_TAG && {
let tag_op =
unsafe { (&(*function).instructions)[tvalue_idx as usize].ops[1] };
let t = unsafe { (*function).tag_op(tag_op) };
t == lua_Type::LUA_TNIL as u8
};
CODEGEN_ASSERT!(
store_cmd == IrCmd::STORE_SPLIT_TVALUE
|| store_cmd == IrCmd::STORE_TVALUE
|| store_cmd == IrCmd::STORE_VECTOR
|| nil_tag_store
);
record_store(function, &mut store_info, tvalue_idx);
}
if !store_info.stores.empty() {
unsafe {
(*sync_info).reg_stores.push(store_info);
}
}
i -= 1;
}
} else {
let max_reg = self.max_reg;
for i in 0..=max_reg {
let ignore_at_exit = self.info[i as usize].ignore_at_exit;
let maybe_gco = self.info[i as usize].maybe_gco;
if ignore_at_exit && !maybe_gco {
continue;
}
self.use_reg(i as u8);
}
self.has_gco_to_clear = false;
}
} else if op.kind() == IrOpKind::Block {
if (op.index() as usize) < unsafe { (*function).cfg.r#in.len() } {
let max_reg = self.max_reg;
for i in 0..=max_reg {
let in_ref = unsafe { &(&(*function).cfg.r#in)[op.index() as usize] };
let is_in = (in_ref.regs[i as usize / 64] & (1u64 << (i as usize % 64))) != 0
|| (in_ref.vararg_seq && i >= in_ref.vararg_start as i32);
if is_in {
self.use_reg(i as u8);
}
}
} else {
self.read_all_regs();
}
} else if op.kind() == IrOpKind::Undef {
} else {
CODEGEN_ASSERT!(false); }
}
}