1use crate::DetailedLocationResolved;
6use crate::code_bld::CodeBuilder;
7use source_map_node::Node;
8use swamp_vm_isa::COLLECTION_CAPACITY_OFFSET;
9use swamp_vm_types::MemoryLocation;
10use swamp_vm_types::types::{Place, TypedRegister, VmType, u16_type};
11
12impl CodeBuilder<'_> {
13 pub(crate) fn emit_transfer_value_to_register(
23 &mut self,
24 target_reg: &TypedRegister,
25 source: &Place,
26 node: &Node,
27 comment: &str,
28 ) {
29 match source {
30 Place::Register(source_reg) => {
31 if target_reg.index != source_reg.index {
32 self.emit_copy_register(target_reg, source_reg, node, comment);
33 }
34 }
35 Place::Memory(memory_location) => {
36 self.emit_load_value_from_memory_source(target_reg, memory_location, node, comment);
37 }
38 Place::Discard => panic!("Cannot load from Unit destination"),
39 }
40 }
41
42 pub(crate) fn emit_load_value_from_memory_source(
49 &mut self,
50 target_reg: &TypedRegister,
51 source_memory_location: &MemoryLocation,
52 node: &Node,
53 comment: &str,
54 ) {
55 let source_type = source_memory_location.vm_type();
56 if source_type.is_reg_copy() {
57 self.emit_load_scalar_from_memory_offset_instruction(
58 target_reg,
59 source_memory_location,
60 node,
61 &format!("emit primitive value. ptr to primitive reg {comment}"),
62 );
63 } else {
64 let source_loc = Place::Memory(source_memory_location.clone());
67
68 self.emit_compute_effective_address_to_target_register(
69 target_reg,
70 &source_loc,
71 node,
72 "copy aggregate pointer to target register",
73 );
74 }
75 }
76
77 pub(crate) fn emit_load_scalar_or_absolute_aggregate_pointer(
97 &mut self,
98 destination: &Place,
99 node: &Node,
100 comment: &str,
101 ) -> Option<TypedRegister> {
102 if matches!(destination, Place::Discard) {
103 None
104 } else {
105 let vm_type = destination.vm_type().unwrap();
106
107 if vm_type.is_scalar() {
108 match destination {
110 Place::Register(reg) => {
111 Some(reg.clone())
113 }
114 Place::Memory(memory_location) => {
115 let scalar_temp = self.temp_registers.allocate(
117 memory_location.ty.clone(),
118 &format!("load scalar from memory for intrinsic: {comment}"),
119 );
120
121 self.emit_load_scalar_from_memory_offset_instruction(
122 scalar_temp.register(),
123 memory_location,
124 node,
125 &format!("load scalar value from memory for intrinsic: {comment}"),
126 );
127
128 Some(scalar_temp.register)
129 }
130 Place::Discard => unreachable!(), }
132 } else {
133 Some(self.emit_compute_effective_address_to_register(
135 destination,
136 node,
137 &format!("flatten aggregate for intrinsic: {comment}"),
138 ))
139 }
140 }
141 }
142
143 pub(crate) fn emit_load_or_calculate_address_from_memory(
151 &mut self,
152 target_reg: &TypedRegister,
153 source_memory_location: &MemoryLocation,
154 node: &Node,
155 comment: &str,
156 ) {
157 let source_type = source_memory_location.vm_type();
158 if source_type.is_aggregate() {
159 self.emit_compute_effective_address_to_target_register(
160 target_reg,
161 &Place::Memory(source_memory_location.clone()),
162 node,
163 comment,
164 );
165 } else {
166 self.emit_load_scalar_from_memory_offset_instruction(
168 target_reg,
169 source_memory_location,
170 node,
171 &format!("load scalar value {comment}"),
172 );
173 }
174 }
175
176 pub(crate) fn emit_materialize_value_to_register(
187 &mut self,
188 location: &Place,
189 node: &Node,
190 comment: &str,
191 ) -> DetailedLocationResolved {
192 match location {
193 Place::Register(reg) => DetailedLocationResolved::Register(reg.clone()),
194 Place::Memory(memory_location) => {
195 let temp_reg_target = self.temp_registers.allocate(
196 memory_location.ty.clone(),
197 "emit load primitive from location",
198 );
199 self.emit_load_value_from_memory_source(
200 temp_reg_target.register(),
201 memory_location,
202 node,
203 &format!("load primitive from detailed location {comment}"),
204 );
205 DetailedLocationResolved::TempRegister(temp_reg_target)
206 }
207 Place::Discard => {
208 panic!("")
209 }
210 }
211 }
212
213 pub fn emit_check_that_known_len_is_less_or_equal_to_capacity(
216 &mut self,
217 destination_memory_location: &MemoryLocation,
218 len: usize,
219 node: &Node,
220 comment: &str,
221 ) -> TypedRegister {
222 let destination_capacity_reg = self.temp_registers.allocate(
226 VmType::new_contained_in_register(u16_type()),
227 "destination capacity",
228 );
229 self.builder.add_ld16_from_pointer_from_memory_location(
230 destination_capacity_reg.register(),
231 &destination_memory_location.unsafe_add_offset(COLLECTION_CAPACITY_OFFSET),
232 node,
233 &format!("{comment} - load capacity for destination"),
234 );
235
236 let source_length_reg = self.temp_registers.allocate(
237 VmType::new_contained_in_register(u16_type()),
238 "source capacity",
239 );
240
241 self.builder.add_mov_16_immediate_value(
242 source_length_reg.register(),
243 len as u16,
244 node,
245 "known length size",
246 );
247
248 self.builder.add_trap_if_lt(
249 destination_capacity_reg.register(),
250 source_length_reg.register(),
251 node,
252 &format!("{comment} - verify that we are within bounds"),
253 );
254
255 source_length_reg.register
256 }
257 pub(crate) fn emit_copy_vec_like_value_helper(
258 &mut self,
259 destination_memory_location: &MemoryLocation,
260 source_memory_location: &MemoryLocation,
261 node: &Node,
262 comment: &str,
263 ) {
264 let destination_pointer = self.emit_compute_effective_address_from_location_to_register(
265 destination_memory_location,
266 node,
267 "get the destination vec",
268 );
269 let source_pointer = self.emit_compute_effective_address_from_location_to_register(
270 source_memory_location,
271 node,
272 "get vector source address",
273 );
274
275 self.builder.add_vec_copy(
276 &destination_pointer,
277 &source_pointer,
278 node,
279 "copy over, but leave the capacity on the destination",
280 );
281 }
282
283 pub(crate) fn emit_copy_map_like_value_helper(
298 &mut self,
299 destination_memory_location: &MemoryLocation,
300 source_memory_location: &MemoryLocation,
301 node: &Node,
302 comment: &str,
303 ) {
304 let destination_ptr_location = self
305 .emit_compute_effective_address_from_location_to_register(
306 destination_memory_location,
307 node,
308 comment,
309 );
310 let source_ptr_location = self.emit_compute_effective_address_from_location_to_register(
311 source_memory_location,
312 node,
313 comment,
314 );
315 self.builder.add_map_overwrite(
316 &destination_ptr_location,
317 &source_ptr_location,
318 node,
319 comment,
320 );
321 }
322
323 pub(crate) fn emit_copy_aggregate_value_helper(
324 &mut self,
325 destination_memory_location: &MemoryLocation,
326 source_memory_location: &MemoryLocation,
327 node: &Node,
328 comment: &str,
329 ) {
330 let ty = &source_memory_location.ty;
331 if ty.is_collection_like() {
332 if ty.basic_type.is_vec_like() {
333 if let (Some(_element_size), Some(_header_size)) = (
334 source_memory_location
335 .ty
336 .basic_type
337 .bucket_size_for_vec_like(),
338 source_memory_location
339 .ty
340 .basic_type
341 .header_size_for_vec_like(),
342 ) {
343 self.emit_copy_vec_like_value_helper(
344 destination_memory_location,
345 source_memory_location,
346 node,
347 comment,
348 );
349 } else {
350 self.emit_block_copy_with_size_from_location(
352 destination_memory_location,
353 source_memory_location,
354 node,
355 &format!("block copy {comment} (vec-like fallback) to memory pointed by register {destination_memory_location} <- {source_memory_location}"),
356 );
357 }
358 } else {
359 self.emit_compute_effective_address_from_location_to_register(
360 destination_memory_location,
361 node,
362 comment,
363 );
364 self.emit_copy_map_like_value_helper(
365 destination_memory_location,
366 source_memory_location,
367 node,
368 comment,
369 );
370 }
371 } else {
372 self.emit_block_copy_with_size_from_location(
373 destination_memory_location,
374 source_memory_location,
375 node,
376 &format!("block copy {comment} to memory pointed by register {destination_memory_location} <- {source_memory_location}"),
377 );
378 }
379 }
380
381 pub fn emit_copy_value_between_places(
382 &mut self,
383 output_place: &Place,
384 value_source: &Place,
385 node: &Node,
386 comment: &str,
387 ) {
388 match output_place {
389 Place::Register(reg) => {
390 self.emit_transfer_value_to_register(reg, value_source, node, comment);
391 }
392 Place::Memory(_) => {
393 self.emit_store_value_to_memory_place(output_place, value_source, node, comment);
394 }
395 Place::Discard => {
396 panic!("Cannot copy to Unit destination")
397 }
398 }
399 }
400
401 pub(crate) fn emit_copy_value_from_memory_location(
402 &mut self,
403 destination: &Place,
404 source_memory_location: &MemoryLocation,
405 node: &Node,
406 comment: &str,
407 ) {
408 if let Some(_mem_loc) = destination.memory_location() {
409 let source_loc = Place::Memory(source_memory_location.clone());
410 self.emit_store_value_to_memory_place(destination, &source_loc, node, comment);
411 } else if let Some(output_target_reg) = destination.register() {
412 self.emit_load_value_from_memory_source(
413 output_target_reg,
414 source_memory_location,
415 node,
416 comment,
417 );
418 } else {
419 panic!("it was unit, not supported");
420 }
421 }
422
423 pub(crate) fn emit_store_value_to_memory_place(
432 &mut self,
433 output_place: &Place,
434 value_source: &Place,
435 node: &Node,
436 comment: &str,
437 ) {
438 let output_mem_loc = output_place.grab_memory_location(); match value_source {
441 Place::Register(value_reg) => {
442 if value_reg.ty.is_reg_copy() {
443 self.emit_store_scalar_to_memory_offset_instruction(
444 output_mem_loc,
445 value_reg,
446 node,
447 &format!("store {comment} to memory pointed by register {output_place} <- {value_reg}"),
448 );
449 } else {
450 let source_memory_location =
451 MemoryLocation::new_copy_over_whole_type_with_zero_offset(
452 value_reg.clone(),
453 );
454 self.emit_copy_aggregate_value_helper(
455 output_place.grab_memory_location(),
456 &source_memory_location,
457 node,
458 "copy aggregate",
459 );
460 }
461 }
462 Place::Memory(source_mem_loc) => {
463 let temp_reg = self
464 .temp_registers
465 .allocate(source_mem_loc.ty.clone(), "temp_for_memory_to_memory_store");
466
467 self.emit_load_value_from_memory_source(
468 temp_reg.register(),
469 source_mem_loc,
470 node,
471 &format!("load {comment} from memory for store"),
472 );
473
474 if source_mem_loc.ty.is_reg_copy() {
475 self.emit_store_scalar_to_memory_offset_instruction(
476 output_mem_loc,
477 temp_reg.register(),
478 node,
479 &format!("store {comment} from temp to memory pointed by register"),
480 );
481 } else {
482 self.emit_copy_aggregate_value_helper(
483 output_place.grab_memory_location(),
484 source_mem_loc,
485 node,
486 "copy aggregate",
487 );
488 }
489 }
490 Place::Discard => panic!("Cannot store from Unit source"),
491 }
492 }
493}