luaur_code_gen/methods/
ir_reg_alloc_x_64_restore.rs1use 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}