Skip to main content

luaur_code_gen/methods/
ir_value_location_tracking_after_inst_lowering.rs

1use 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}