luaur_code_gen/methods/
ir_call_wrapper_x_64_call.rs1use crate::enums::category_x_64::CategoryX64;
2use crate::enums::ir_op_kind::IrOpKind;
3use crate::enums::size_x_64::SizeX64;
4use crate::functions::same_underlying_register::same_underlying_register;
5use crate::macros::codegen_assert::CODEGEN_ASSERT;
6use crate::methods::ir_call_wrapper_x_64_find_non_interfering_argument::ir_call_wrapper_x_64_find_non_interfering_argument;
7use crate::records::call_argument::CallArgument;
8use crate::records::ir_call_wrapper_x_64::IrCallWrapperX64;
9use crate::records::ir_data::k_invalid_inst_idx;
10use crate::records::ir_inst::IrInst;
11use crate::records::operand_x_64::OperandX64;
12use crate::records::register_x_64::RegisterX64;
13use crate::records::scoped_reg_x_64::ScopedRegX64;
14
15impl IrCallWrapperX64 {
16 pub fn call(&mut self, func: &OperandX64) {
17 self.func_op = *func;
18
19 if self.result_reg != RegisterX64::noreg {
21 unsafe {
22 (*self.regs).free_reg(self.result_reg);
23 }
24 }
25
26 self.count_register_uses();
27
28 for i in 0..(self.arg_count as usize) {
29 let arg_ptr: *mut CallArgument = &mut self.args[i];
30
31 let source_op = unsafe { (*arg_ptr).source_op };
32
33 if source_op.kind() != IrOpKind::None {
34 let inst: *mut IrInst = unsafe { (*(*self.regs).function).as_inst_op(source_op) };
35
36 if !inst.is_null() {
37 if unsafe { (*self.regs).is_last_use_reg(&*inst, self.inst_idx) } {
40 unsafe {
41 (*inst).reg_x64 = RegisterX64::noreg;
42 }
43 } else {
44 let reg = unsafe { (*inst).reg_x64 };
47 if reg.size() == SizeX64::xmmword
48 || unsafe { (*self.regs).should_free_gpr(reg) }
49 {
50 unsafe {
51 (*self.regs).take_reg(reg, k_invalid_inst_idx);
52 }
53 }
54 }
55 }
56 }
57
58 let source = unsafe { (*arg_ptr).source };
59 let target = unsafe { (*arg_ptr).target };
60
61 if source.cat == CategoryX64::imm {
64 unsafe {
65 (*arg_ptr).candidate = false;
66 }
67 }
68 else if target.cat == CategoryX64::mem {
70 if source.cat == CategoryX64::mem {
71 let mut tmp = ScopedRegX64 {
72 owner: self.regs,
73 reg: RegisterX64::noreg,
74 };
75 tmp.scoped_reg_x_64_ir_reg_alloc_x_64_size_x_64(
76 unsafe { &mut *self.regs },
77 target.memSize,
78 );
79
80 self.free_source_registers(unsafe { &mut *arg_ptr });
81
82 if source.memSize == SizeX64::none {
83 unsafe {
84 (*self.build)
85 .lea_operand_x_64_operand_x_64(OperandX64::reg(tmp.reg), source);
86 }
87 } else {
88 unsafe {
89 (*self.build).mov(OperandX64::reg(tmp.reg), source);
90 }
91 }
92
93 unsafe {
94 (*self.build).mov(target, OperandX64::reg(tmp.reg));
95 }
96
97 tmp.free();
98 } else {
99 self.free_source_registers(unsafe { &mut *arg_ptr });
100
101 unsafe {
102 (*self.build).mov(target, source);
103 }
104 }
105
106 unsafe {
107 (*arg_ptr).candidate = false;
108 }
109 }
110 else if source.cat == CategoryX64::reg
112 && same_underlying_register(target.base, source.base)
113 {
114 self.free_source_registers(unsafe { &mut *arg_ptr });
115
116 if self.get_register_uses(target.base) == 0 {
119 unsafe {
120 (*self.regs).take_reg(target.base, k_invalid_inst_idx);
121 }
122 } else {
123 self.add_register_use(target.base);
125 }
126
127 unsafe {
128 (*arg_ptr).candidate = false;
129 }
130 }
131 }
132
133 loop {
135 let candidate = ir_call_wrapper_x_64_find_non_interfering_argument(self);
137
138 if !candidate.is_null() {
139 CODEGEN_ASSERT!(unsafe { (*candidate).target.cat } == CategoryX64::reg);
141
142 self.free_source_registers(unsafe { &mut *candidate });
143
144 let target_base = unsafe { (*candidate).target.base };
145 CODEGEN_ASSERT!(self.get_register_uses(target_base) == 0);
146 unsafe {
147 (*self.regs).take_reg(target_base, k_invalid_inst_idx);
148 }
149
150 self.move_to_target(unsafe { &mut *candidate });
151
152 unsafe {
153 (*candidate).candidate = false;
154 }
155 } else {
156 let conflict = self.find_conflicting_target();
158 if conflict != RegisterX64::noreg {
159 self.rename_conflicting_register(conflict);
160 } else {
161 for i in 0..(self.arg_count as usize) {
162 CODEGEN_ASSERT!(!self.args[i].candidate);
163 }
164 break;
165 }
166 }
167 }
168
169 for i in 0..(self.arg_count as usize) {
171 let arg_ptr: *mut CallArgument = &mut self.args[i];
172
173 if unsafe { (*arg_ptr).source.cat } == CategoryX64::imm {
174 unsafe {
177 (*arg_ptr).candidate = true;
178 }
179
180 let conflict = self.find_conflicting_target();
181 if conflict != RegisterX64::noreg {
182 self.rename_conflicting_register(conflict);
183 }
184
185 let target = unsafe { (*arg_ptr).target };
186 if target.cat == CategoryX64::reg {
187 unsafe {
188 (*self.regs).take_reg(target.base, k_invalid_inst_idx);
189 }
190 }
191
192 self.move_to_target(unsafe { &mut *arg_ptr });
193
194 unsafe {
195 (*arg_ptr).candidate = false;
196 }
197 }
198 }
199
200 let func_base = self.func_op.base;
202 let func_index = self.func_op.index;
203 self.remove_register_use(func_base);
204 self.remove_register_use(func_index);
205
206 for i in 0..(self.arg_count as usize) {
208 if self.args[i].target.cat == CategoryX64::reg {
209 let target_base = self.args[i].target.base;
210 unsafe {
211 (*self.regs).free_reg(target_base);
212 }
213 }
214 }
215
216 unsafe {
217 (*self.regs).preserve_and_free_inst_values();
218 (*self.regs).assert_all_free();
219 }
220
221 unsafe {
222 (*self.build).call_operand_x_64(self.func_op);
223 }
224
225 if self.result_reg != RegisterX64::noreg {
226 unsafe {
228 (*self.regs).take_reg(self.result_reg, self.result_inst_idx);
229 }
230
231 if self.result_reg.index() != 0 {
233 let return_reg = RegisterX64 {
234 bits: self.result_reg.size() as u8,
235 };
236 unsafe {
237 (*self.build).mov(
238 OperandX64::reg(self.result_reg),
239 OperandX64::reg(return_reg),
240 );
241 }
242 }
243 }
244 }
245}