luaur_code_gen/methods/
ir_value_location_tracking_after_inst_lowering.rs1use crate::enums::ir_cmd::IrCmd;
2use crate::enums::ir_op_kind::IrOpKind;
3use crate::enums::ir_value_kind::IrValueKind;
4use crate::functions::vm_reg_op::vm_reg_op;
5use crate::macros::op_a::op_a;
6use crate::macros::op_b::op_b;
7use crate::macros::op_c::op_c;
8use crate::records::ir_data::k_invalid_inst_idx;
9use crate::records::ir_inst::IrInst;
10use crate::records::ir_value_location_tracking::IrValueLocationTracking;
11use crate::records::value_restore_location::ValueRestoreLocation;
12use luaur_common::FFlag;
13
14impl IrValueLocationTracking {
15 pub fn after_inst_lowering(&mut self, inst: &mut IrInst, inst_idx: u32) {
16 match inst.cmd {
17 IrCmd::LOAD_TAG
18 | IrCmd::LOAD_POINTER
19 | IrCmd::LOAD_DOUBLE
20 | IrCmd::LOAD_INT
21 | IrCmd::LOAD_INT64
22 | IrCmd::LOAD_TVALUE => {
23 if op_a(inst).kind() == IrOpKind::VmReg {
24 self.invalidate_restore_op(op_a(inst), false);
25 }
26
27 self.record_restore_op(inst_idx, op_a(inst));
28 }
29
30 IrCmd::STORE_POINTER
31 | IrCmd::STORE_DOUBLE
32 | IrCmd::STORE_INT
33 | IrCmd::STORE_INT64
34 | IrCmd::STORE_TVALUE => {
35 let source_op = op_b(inst.clone());
36
37 if source_op.kind() == IrOpKind::Inst {
38 let function = unsafe { &mut *self.function };
39 let source = function.instructions[source_op.index() as usize].clone();
40 let can_remat_args =
41 can_rematerialize_arguments_at(function, source_op.index());
42
43 if source.last_use != inst_idx || can_remat_args {
44 self.record_restore_op(source_op.index(), op_a(inst));
45 }
46 }
47 }
48
49 IrCmd::STORE_SPLIT_TVALUE => {
50 let source_op = op_c(inst.clone());
51
52 if source_op.kind() == IrOpKind::Inst {
53 let function = unsafe { &mut *self.function };
54 let source = function.instructions[source_op.index() as usize].clone();
55 let can_remat_args =
56 can_rematerialize_arguments_at(function, source_op.index());
57
58 if source.last_use != inst_idx || can_remat_args {
59 self.record_restore_op(source_op.index(), op_a(inst));
60 }
61 }
62 }
63
64 IrCmd::NUM_TO_UINT | IrCmd::NUM_TO_INT => {
65 let arg = op_a(inst);
66
67 if FFlag::LuauCodegenForwardRematerialize.get() && arg.kind() == IrOpKind::Inst {
68 let function = unsafe { &mut *self.function };
69 let owner_loc = function.find_restore_location_u32_bool(arg.index(), true);
70
71 if owner_loc.op.kind() == IrOpKind::VmReg
72 && owner_loc.kind == IrValueKind::Double
73 && owner_loc.conversion_cmd == IrCmd::NOP
74 && !owner_loc.lazy
75 {
76 let reg = vm_reg_op(owner_loc.op) as usize;
77 let captured =
78 (function.cfg.captured.regs[reg / 64] & (1u64 << (reg % 64))) != 0;
79
80 if !captured && self.vm_reg_dependent[reg] == k_invalid_inst_idx {
81 let forward_cmd = if inst.cmd == IrCmd::NUM_TO_UINT {
82 IrCmd::UINT_TO_NUM
83 } else {
84 IrCmd::INT_TO_NUM
85 };
86
87 function.record_restore_location(
88 inst_idx,
89 ValueRestoreLocation {
90 op: owner_loc.op,
91 kind: IrValueKind::Double,
92 conversion_cmd: forward_cmd,
93 lazy: false,
94 },
95 );
96
97 self.vm_reg_dependent[reg] = inst_idx;
98 }
99 }
100 }
101 }
102
103 _ => {}
104 }
105 }
106}
107
108fn can_rematerialize_arguments_at(
109 function: &mut crate::records::ir_function::IrFunction,
110 inst_idx: u32,
111) -> bool {
112 let mut inst = function.instructions[inst_idx as usize].clone();
113
114 if (inst.cmd == IrCmd::UINT_TO_NUM || inst.cmd == IrCmd::INT_TO_NUM)
115 && op_a(&mut inst).kind() == IrOpKind::Inst
116 {
117 let dep_inst_idx = op_a(&mut inst).index();
118
119 if function.instructions[dep_inst_idx as usize].last_use != inst_idx {
120 return true;
121 }
122 }
123
124 false
125}