Skip to main content

luaur_code_gen/methods/
ir_reg_alloc_x_64_restore.rs

1use crate::enums::ir_cmd::IrCmd;
2use crate::enums::ir_value_kind::IrValueKind;
3use crate::enums::size_x_64::SizeX64;
4use crate::functions::qword_reg::qword_reg;
5use crate::macros::codegen_assert::CODEGEN_ASSERT;
6use crate::records::ir_inst::IrInst;
7use crate::records::ir_reg_alloc_x_64::IrRegAllocX64;
8use crate::records::ir_spill_x_64::IrSpillX64;
9use crate::records::operand_x_64::OperandX64;
10use crate::records::register_x_64::RegisterX64;
11
12const S_TEMPORARY_SLOT: i32 = 64;
13const S_SPILL_AREA: i32 = 72;
14
15fn r_state() -> RegisterX64 {
16    RegisterX64 {
17        bits: (15u8 << RegisterX64::INDEX_SHIFT) | SizeX64::qword as u8,
18    }
19}
20
21fn mem(size: SizeX64, base: RegisterX64, disp: i32) -> OperandX64 {
22    OperandX64::mem(size, RegisterX64::noreg, 1, base, disp)
23}
24
25fn temp_qword() -> OperandX64 {
26    mem(SizeX64::qword, RegisterX64::rsp, S_TEMPORARY_SLOT)
27}
28
29impl IrRegAllocX64 {
30    pub fn restore(&mut self, inst: &mut IrInst, into_original_location: bool) {
31        let inst_idx = unsafe { (&*self.function).get_inst_index(inst) };
32
33        let mut i = 0;
34        while i < self.spills.len() {
35            if self.spills[i].inst_idx == inst_idx {
36                let original_loc = self.spills[i].original_loc;
37                let reg = if into_original_location {
38                    self.take_reg(original_loc, inst_idx)
39                } else {
40                    self.alloc_reg(original_loc.size(), inst_idx)
41                };
42
43                let restore_location =
44                    unsafe { (&*self.function).find_restore_location_ir_inst_bool(inst, false) };
45                let emergency_temp = if reg.size() == SizeX64::xmmword {
46                    RegisterX64::r11
47                } else {
48                    qword_reg(reg)
49                };
50                let spill = self.spills[i].clone();
51
52                let mut restore_addr;
53
54                if spill.stack_slot != IrSpillX64::kNoStackSlot {
55                    if self.is_extra_spill_slot(spill.stack_slot as u32) {
56                        let extra_offset =
57                            self.get_extra_spill_address_offset(spill.stack_slot as u32);
58
59                        let build = unsafe { &mut *self.build };
60                        if reg.size() == SizeX64::xmmword {
61                            build.mov(temp_qword(), OperandX64::reg(emergency_temp));
62                        }
63
64                        build.mov(
65                            OperandX64::reg(emergency_temp),
66                            mem(
67                                SizeX64::qword,
68                                r_state(),
69                                core::mem::offset_of!(
70                                    luaur_vm::records::lua_state::lua_State,
71                                    global
72                                ) as i32,
73                            ),
74                        );
75                        build.lea_operand_x_64_operand_x_64(
76                            OperandX64::reg(emergency_temp),
77                            mem(
78                                SizeX64::none,
79                                emergency_temp,
80                                core::mem::offset_of!(
81                                    luaur_vm::records::global_state::global_State,
82                                    ecbdata
83                                ) as i32
84                                    + extra_offset,
85                            ),
86                        );
87
88                        restore_addr = mem(reg.size(), emergency_temp, 0);
89                    } else {
90                        restore_addr = mem(
91                            SizeX64::none,
92                            RegisterX64::rsp,
93                            S_SPILL_AREA + spill.stack_slot as i32 * 4,
94                        );
95                        restore_addr.memSize = reg.size();
96                    }
97
98                    if spill.value_kind == IrValueKind::Double
99                        || spill.value_kind == IrValueKind::Int64
100                    {
101                        restore_addr.memSize = SizeX64::qword;
102                    } else if spill.value_kind == IrValueKind::Float {
103                        restore_addr.memSize = SizeX64::dword;
104                    }
105
106                    let end = spill.stack_slot as u32
107                        + crate::enums::ir_value_kind::K_VALUE_DWORD_SIZE
108                            [spill.value_kind as usize];
109
110                    for pos in spill.stack_slot as u32..end {
111                        self.used_spill_slot_halfs[(pos / 64) as usize] &= !(1u64 << (pos % 64));
112                    }
113                } else {
114                    restore_addr = self.get_restore_address(inst, restore_location);
115                }
116
117                let build = unsafe { &mut *self.build };
118                match spill.value_kind {
119                    IrValueKind::Tvalue => build.vmovups(OperandX64::reg(reg), restore_addr),
120                    IrValueKind::Double => {
121                        build.vmovsd_operand_x_64_operand_x_64(OperandX64::reg(reg), restore_addr)
122                    }
123                    IrValueKind::Int if restore_location.kind == IrValueKind::Double => {
124                        if restore_location.conversion_cmd == IrCmd::INT_TO_NUM {
125                            build.vcvttsd2si(OperandX64::reg(reg), restore_addr);
126                        } else if restore_location.conversion_cmd == IrCmd::UINT_TO_NUM {
127                            build.vcvttsd2si(OperandX64::reg(qword_reg(reg)), restore_addr);
128                        } else {
129                            CODEGEN_ASSERT!(
130                                false,
131                                "re-materialization not supported for this conversion command"
132                            );
133                        }
134                    }
135                    IrValueKind::Tag
136                    | IrValueKind::Int
137                    | IrValueKind::Int64
138                    | IrValueKind::Pointer => {
139                        build.mov(OperandX64::reg(reg), restore_addr);
140                    }
141                    IrValueKind::Float => {
142                        build.vmovss_operand_x_64_operand_x_64(OperandX64::reg(reg), restore_addr)
143                    }
144                    _ => CODEGEN_ASSERT!(false, "value kind not supported for restore"),
145                }
146
147                if spill.stack_slot != IrSpillX64::kNoStackSlot
148                    && self.is_extra_spill_slot(spill.stack_slot as u32)
149                {
150                    if reg.size() == SizeX64::xmmword {
151                        let build = unsafe { &mut *self.build };
152                        build.mov(OperandX64::reg(emergency_temp), temp_qword());
153                    }
154                }
155
156                inst.reg_x64 = reg;
157                inst.spilled = false;
158                inst.needs_reload = false;
159
160                self.spills[i] = self.spills[self.spills.len() - 1].clone();
161                self.spills.pop();
162                return;
163            }
164            i += 1;
165        }
166    }
167}