1use crate::code_bld::CodeBuilder;
6use crate::DetailedLocationResolved;
7use source_map_node::Node;
8use swamp_vm_types::types::{u16_type, BasicTypeKind, Destination, TypedRegister, VmType};
9use swamp_vm_types::{MemoryLocation, COLLECTION_CAPACITY_OFFSET};
10
11impl CodeBuilder<'_> {
12 pub(crate) fn emit_transfer_value_to_register(
22 &mut self,
23 target_reg: &TypedRegister,
24 source: &Destination,
25 node: &Node,
26 comment: &str,
27 ) {
28 match source {
29 Destination::Register(source_reg) => {
30 if target_reg.index != source_reg.index {
31 self.emit_copy_register(target_reg, source_reg, node, comment);
32 }
33 }
34 Destination::Memory(memory_location) => {
35 self.emit_load_value_from_memory_source(target_reg, memory_location, node, comment);
36 }
37 Destination::Unit => panic!("Cannot load from Unit destination"),
38 }
39 }
40
41 pub(crate) fn emit_load_value_from_memory_source(
48 &mut self,
49 target_reg: &TypedRegister,
50 source_memory_location: &MemoryLocation,
51 node: &Node,
52 comment: &str,
53 ) {
54 let source_type = source_memory_location.vm_type();
55 if source_type.is_aggregate() {
56 let source_loc = Destination::Memory(source_memory_location.clone());
59
60 self.emit_compute_effective_address_to_target_register(
61 target_reg,
62 &source_loc,
63 node,
64 "copy aggregate pointer to target register",
65 );
66 } else {
67 self.emit_load_scalar_from_memory_offset_instruction(
68 target_reg,
69 source_memory_location,
70 node,
71 &format!("emit primitive value. ptr to primitive reg {comment}"),
72 );
73 }
74 }
75
76 pub(crate) fn emit_load_scalar_or_absolute_aggregate_pointer(
96 &mut self,
97 destination: &Destination,
98 node: &Node,
99 comment: &str,
100 ) -> Option<TypedRegister> {
101 if matches!(destination, Destination::Unit) {
102 None
103 } else {
104 let vm_type = destination.vm_type().unwrap();
105
106 if vm_type.is_scalar() {
107 match destination {
109 Destination::Register(reg) => {
110 Some(reg.clone())
112 }
113 Destination::Memory(memory_location) => {
114 let scalar_temp = self.temp_registers.allocate(
116 memory_location.ty.clone(),
117 &format!("load scalar from memory for intrinsic: {comment}"),
118 );
119
120 self.emit_load_scalar_from_memory_offset_instruction(
121 scalar_temp.register(),
122 memory_location,
123 node,
124 &format!("load scalar value from memory for intrinsic: {comment}"),
125 );
126
127 Some(scalar_temp.register)
128 }
129 Destination::Unit => unreachable!(), }
131 } else {
132 Some(self.emit_compute_effective_address_to_register(
134 destination,
135 node,
136 &format!("flatten aggregate for intrinsic: {comment}"),
137 ))
138 }
139 }
140 }
141
142 pub(crate) fn emit_load_or_calculate_address_from_memory(
150 &mut self,
151 target_reg: &TypedRegister,
152 source_memory_location: &MemoryLocation,
153 node: &Node,
154 comment: &str,
155 ) {
156 let source_type = source_memory_location.vm_type();
157 if source_type.is_aggregate() {
158 self.emit_compute_effective_address_to_target_register(
159 target_reg,
160 &Destination::Memory(source_memory_location.clone()),
161 node,
162 comment,
163 );
164 } else {
165 self.emit_load_scalar_from_memory_offset_instruction(
167 target_reg,
168 source_memory_location,
169 node,
170 &format!("load scalar value {comment}"),
171 );
172 }
173 }
174
175 pub(crate) fn emit_materialize_value_to_register(
186 &mut self,
187 location: &Destination,
188 node: &Node,
189 comment: &str,
190 ) -> DetailedLocationResolved {
191 match location {
192 Destination::Register(reg) => DetailedLocationResolved::Register(reg.clone()),
193 Destination::Memory(memory_location) => {
194 let temp_reg_target = self.temp_registers.allocate(
195 memory_location.ty.clone(),
196 "emit load primitive from location",
197 );
198 self.emit_load_value_from_memory_source(
199 temp_reg_target.register(),
200 memory_location,
201 node,
202 &format!("load primitive from detailed location {comment}"),
203 );
204 DetailedLocationResolved::TempRegister(temp_reg_target)
205 }
206 Destination::Unit => {
207 panic!("")
208 }
209 }
210 }
211
212 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 if matches!(
332 source_memory_location.ty.basic_type.kind,
333 BasicTypeKind::StringView { byte: _, char: _ }
334 ) && matches!(
335 destination_memory_location.ty.basic_type.kind,
336 BasicTypeKind::StringStorage {
337 element_type: _,
338 char: _,
339 capacity: _
340 }
341 ) {
342 self.emit_copy_vec_like_value_helper(
344 destination_memory_location,
345 source_memory_location,
346 node,
347 &format!("copy StringView to StringStorage {comment}"),
348 );
349 return;
350 }
351
352 let ty = &source_memory_location.ty;
353 if ty.is_collection_like() {
354 if ty.basic_type.is_vec_like() {
355 if let (Some(_element_size), Some(_header_size)) = (
356 source_memory_location
357 .ty
358 .basic_type
359 .bucket_size_for_vec_like(),
360 source_memory_location
361 .ty
362 .basic_type
363 .header_size_for_vec_like(),
364 ) {
365 self.emit_copy_vec_like_value_helper(
366 destination_memory_location,
367 source_memory_location,
368 node,
369 comment,
370 );
371 } else {
372 self.emit_block_copy_with_size_from_location(
374 destination_memory_location,
375 source_memory_location,
376 node,
377 &format!("block copy {comment} (vec-like fallback) to memory pointed by register {destination_memory_location} <- {source_memory_location}"),
378 );
379 }
380 } else {
381 self.emit_compute_effective_address_from_location_to_register(
382 destination_memory_location,
383 node,
384 comment,
385 );
386 self.emit_copy_map_like_value_helper(
387 destination_memory_location,
388 source_memory_location,
389 node,
390 comment,
391 );
392 }
393 } else {
394 self.emit_block_copy_with_size_from_location(
395 destination_memory_location,
396 source_memory_location,
397 node,
398 &format!("block copy {comment} to memory pointed by register {destination_memory_location} <- {source_memory_location}"),
399 );
400 }
401 }
402
403 pub fn emit_copy_value_between_destinations(
404 &mut self,
405 output_destination: &Destination,
406 value_source: &Destination,
407 node: &Node,
408 comment: &str,
409 ) {
410 match output_destination {
411 Destination::Register(reg) => {
412 self.emit_transfer_value_to_register(reg, value_source, node, comment);
413 }
414 Destination::Memory(_) => {
415 self.emit_store_value_to_memory_destination(
416 output_destination,
417 value_source,
418 node,
419 comment,
420 );
421 }
422 Destination::Unit => {
423 panic!("Cannot copy to Unit destination")
424 }
425 }
426 }
427
428 pub(crate) fn emit_copy_value_from_memory_location(
429 &mut self,
430 destination: &Destination,
431 source_memory_location: &MemoryLocation,
432 node: &Node,
433 comment: &str,
434 ) {
435 if let Some(_mem_loc) = destination.memory_location() {
436 let source_loc = Destination::Memory(source_memory_location.clone());
437 self.emit_store_value_to_memory_destination(destination, &source_loc, node, comment);
438 } else if let Some(output_target_reg) = destination.register() {
439 self.emit_load_value_from_memory_source(
440 output_target_reg,
441 source_memory_location,
442 node,
443 comment,
444 );
445 } else {
446 panic!("it was unit, not supported");
447 }
448 }
449
450 pub(crate) fn emit_store_value_to_memory_destination(
459 &mut self,
460 output_destination: &Destination,
461 value_source: &Destination,
462 node: &Node,
463 comment: &str,
464 ) {
465 let output_mem_loc = output_destination.grab_memory_location(); match value_source {
468 Destination::Register(value_reg) => {
469 if matches!(
471 value_reg.ty.basic_type.kind,
472 BasicTypeKind::StringView { byte: _, char: _ }
473 ) && matches!(
474 output_mem_loc.ty.basic_type.kind,
475 BasicTypeKind::StringStorage {
476 element_type: _,
477 char: _,
478 capacity: _
479 }
480 ) {
481 let source_memory_location =
483 MemoryLocation::new_copy_over_whole_type_with_zero_offset(
484 value_reg.clone(),
485 );
486 self.emit_copy_aggregate_value_helper(
488 output_destination.grab_memory_location(),
489 &source_memory_location,
490 node,
491 &format!("copy StringView to StringStorage {comment}"),
492 );
493 } else if value_reg.ty.is_scalar() {
494 self.emit_store_scalar_to_memory_offset_instruction(
495 output_mem_loc,
496 value_reg,
497 node,
498 &format!("store {comment} to memory pointed by register {output_destination} <- {value_reg}"),
499 );
500 } else {
501 let source_memory_location =
502 MemoryLocation::new_copy_over_whole_type_with_zero_offset(
503 value_reg.clone(),
504 );
505 self.emit_copy_aggregate_value_helper(
506 output_destination.grab_memory_location(),
507 &source_memory_location,
508 node,
509 "copy aggregate",
510 );
511 }
512 }
513 Destination::Memory(source_mem_loc) => {
514 let temp_reg = self
515 .temp_registers
516 .allocate(source_mem_loc.ty.clone(), "temp_for_memory_to_memory_store");
517
518 self.emit_load_value_from_memory_source(
519 temp_reg.register(),
520 source_mem_loc,
521 node,
522 &format!("load {comment} from memory for store"),
523 );
524
525 if source_mem_loc.ty.is_scalar() {
526 self.emit_store_scalar_to_memory_offset_instruction(
527 output_mem_loc,
528 temp_reg.register(),
529 node,
530 &format!("store {comment} from temp to memory pointed by register"),
531 );
532 } else {
533 self.emit_copy_aggregate_value_helper(
534 output_destination.grab_memory_location(),
535 source_mem_loc,
536 node,
537 "copy aggregate",
538 );
539 }
540 }
541 Destination::Unit => panic!("Cannot store from Unit source"),
542 }
543 }
544}