1use crate::code_bld::CodeBuilder;
6use crate::ctx::Context;
7
8use crate::transformer::{Collection, Transformer};
9use source_map_node::Node;
10use swamp_semantic::intr::IntrinsicFunction;
11use swamp_semantic::{ArgumentExpression, Expression, ExpressionKind, VariableRef};
12use swamp_vm_types::types::{
13 float_type, int_type, pointer_type, u16_type, u32_type, u8_type, Destination, TypedRegister,
14 VmType,
15};
16use swamp_vm_types::{
17 AggregateMemoryLocation, MemoryLocation, MemoryOffset,
18 PointerLocation, COLLECTION_CAPACITY_OFFSET, COLLECTION_ELEMENT_COUNT_OFFSET, GRID_HEADER_HEIGHT_OFFSET,
19 GRID_HEADER_WIDTH_OFFSET,
20};
21
22impl CodeBuilder<'_> {
23 #[allow(clippy::too_many_lines)]
24 #[allow(clippy::single_match_else)]
25 pub fn emit_single_intrinsic_call(
26 &mut self,
27 target_reg: &Destination,
28 node: &Node,
29 intrinsic_fn: &IntrinsicFunction,
30 arguments: &[ArgumentExpression],
31 ctx: &Context,
32 ) {
33 {
34 let self_reg = if arguments.is_empty() {
36 None
37 } else {
38 let ArgumentExpression::Expression(self_expr) = &arguments[0] else {
39 panic!("Expected expression for self argument");
40 };
41 Some(self.emit_scalar_rvalue(self_expr, ctx))
42 };
43
44 let rest_args = if arguments.len() > 1 {
45 &arguments[1..]
46 } else {
47 &vec![]
48 };
49 self.emit_single_intrinsic_call_with_self(
50 target_reg,
51 node,
52 intrinsic_fn,
53 self_reg.as_ref(),
54 rest_args,
55 ctx,
56 "single intrinsic call",
57 );
58 }
59 }
60
61 pub fn emit_intrinsic_map(
62 &mut self,
63 output_destination: &Destination,
64 intrinsic_fn: &IntrinsicFunction,
65 self_ptr_reg: &PointerLocation,
66 arguments: &[Expression],
67 node: &Node,
68 comment: &str,
69 ctx: &Context,
70 ) {
71 match intrinsic_fn {
72 IntrinsicFunction::MapHas => {
73 let key_argument = &arguments[0];
74 let key_temp_storage_reg =
76 self.emit_aggregate_pointer_or_pointer_to_scalar_memory(key_argument, ctx);
77
78 self.builder.add_map_has(
79 output_destination.register().unwrap(),
80 self_ptr_reg,
81 &key_temp_storage_reg,
82 node,
83 "map_has",
84 );
85 }
86 IntrinsicFunction::MapRemove => {
87 let key_argument = &arguments[0];
88 self.emit_intrinsic_map_remove(self_ptr_reg, key_argument, ctx);
89 }
90 _ => todo!("missing intrinsic_map {intrinsic_fn}"),
91 }
92 }
93
94 pub fn emit_intrinsic_sparse(
95 &mut self,
96 output_destination: &Destination,
97 intrinsic_fn: &IntrinsicFunction,
98 self_ptr_reg: &PointerLocation,
99 arguments: &[Expression],
100 node: &Node,
101 comment: &str,
102 ctx: &Context,
103 ) {
104 match intrinsic_fn {
105 IntrinsicFunction::SparseAdd => {
106 let element_to_add_expression = &arguments[0];
107 self.emit_sparse_add(
108 &output_destination.register().unwrap().clone(),
109 self_ptr_reg,
110 element_to_add_expression,
111 node,
112 ctx,
113 );
114 }
115
116 IntrinsicFunction::SparseRemove => {
117 let sparse_id_int_expression = &arguments[0];
118 self.emit_sparse_remove(self_ptr_reg, sparse_id_int_expression, node, ctx);
119 }
120
121 IntrinsicFunction::SparseIsAlive => {
122 let sparse_id_int_expression = &arguments[0];
123 self.emit_sparse_is_alive(
124 &output_destination.register().unwrap().clone(),
125 self_ptr_reg,
126 sparse_id_int_expression,
127 node,
128 ctx,
129 );
130 }
131 _ => todo!("unknown sparse {intrinsic_fn}"),
132 }
133 }
134 pub fn emit_intrinsic_grid(
135 &mut self,
136 target_destination: &Destination,
137 intrinsic_fn: &IntrinsicFunction,
138 self_ptr_reg: &PointerLocation,
139 arguments: &[Expression],
140 node: &Node,
141 comment: &str,
142 ctx: &Context,
143 ) {
144 let (temp_reg, dest_reg) = if target_destination.is_register() {
145 (None, target_destination.register().unwrap().clone())
146 } else {
147 let temp_reg = self.temp_registers.allocate(
148 VmType::new_contained_in_register(float_type()),
149 "temporary destination for low level intrinsic",
150 );
151
152 (Some(temp_reg.register.clone()), temp_reg.register)
153 };
154 match intrinsic_fn {
155 IntrinsicFunction::GridSet => {
156 let x_expr = &arguments[0];
157 let y_expr = &arguments[1];
158 let value_expr = &arguments[2];
159
160 let x_reg = self.emit_scalar_rvalue(x_expr, ctx);
161 let y_reg = self.emit_scalar_rvalue(y_expr, ctx);
162 let element_gen_type = self_ptr_reg.ptr_reg.ty.basic_type.element().unwrap();
163
164 let temp_element_ptr = self.temp_registers.allocate(
165 VmType::new_contained_in_register(element_gen_type.clone()),
166 "temporary scalar",
167 );
168
169 self.builder.add_grid_get_entry_addr(
170 &temp_element_ptr.register,
171 self_ptr_reg,
172 &x_reg,
173 &y_reg,
174 element_gen_type.total_size,
175 node,
176 comment,
177 );
178
179 let location = AggregateMemoryLocation {
180 location: MemoryLocation {
181 base_ptr_reg: temp_element_ptr.register,
182 offset: MemoryOffset(0),
183 ty: VmType::new_unknown_placement(element_gen_type.clone()),
184 },
185 };
186
187 if element_gen_type.is_aggregate() {
189 self.emit_initialize_memory_for_any_type(
190 &location.location,
191 node,
192 "initialize grid set allocated space",
193 );
194 }
195
196 self.emit_expression_into_target_memory(
197 &location.location,
198 value_expr,
199 "grid set",
200 ctx,
201 );
202 }
203 IntrinsicFunction::GridGet => {
204 let x_expr = &arguments[0];
205 let y_expr = &arguments[1];
206
207 let x_reg = self.emit_scalar_rvalue(x_expr, ctx);
208 let y_reg = self.emit_scalar_rvalue(y_expr, ctx);
209
210 let element_type = self_ptr_reg.ptr_reg.ty.basic_type.element().unwrap();
211
212 let temp_element_ptr = self.temp_registers.allocate(
214 VmType::new_contained_in_register(pointer_type()),
215 "temp for grid element address",
216 );
217
218 self.builder.add_grid_get_entry_addr(
220 &temp_element_ptr.register,
221 self_ptr_reg,
222 &x_reg,
223 &y_reg,
224 element_type.total_size,
225 node,
226 comment,
227 );
228
229 let element_memory_location = MemoryLocation {
231 base_ptr_reg: temp_element_ptr.register,
232 offset: MemoryOffset(0),
233 ty: VmType::new_unknown_placement(element_type),
234 };
235
236 self.emit_copy_value_from_memory_location(
239 target_destination,
240 &element_memory_location,
241 node,
242 "copy grid element value to destination",
243 );
244 }
245
246 IntrinsicFunction::GridWidth => {
247 let temp = self.temp_registers.allocate(
249 VmType::new_contained_in_register(u16_type()),
250 "temp for grid width",
251 );
252
253 let self_memory_location = AggregateMemoryLocation::new(
255 MemoryLocation::new_copy_over_whole_type_with_zero_offset(
256 self_ptr_reg.ptr_reg.clone(),
257 ),
258 );
259 let width_location =
260 self_memory_location.offset(GRID_HEADER_WIDTH_OFFSET, int_type());
261
262 self.builder.add_ld16_from_pointer_from_memory_location(
264 &temp.register,
265 &width_location.location,
266 node,
267 comment,
268 );
269
270 let value_source = Destination::Register(temp.register);
272
273 self.emit_copy_value_between_destinations(
275 target_destination,
276 &value_source,
277 node,
278 "store grid width to destination",
279 );
280 }
281 IntrinsicFunction::GridHeight => {
282 let temp = self.temp_registers.allocate(
284 VmType::new_contained_in_register(u16_type()),
285 "temp for grid height",
286 );
287
288 let self_memory_location = AggregateMemoryLocation::new(
290 MemoryLocation::new_copy_over_whole_type_with_zero_offset(
291 self_ptr_reg.ptr_reg.clone(),
292 ),
293 );
294 let height_location =
295 self_memory_location.offset(GRID_HEADER_HEIGHT_OFFSET, int_type());
296
297 self.builder.add_ld16_from_pointer_from_memory_location(
299 &temp.register,
300 &height_location.location,
301 node,
302 comment,
303 );
304
305 let value_source = Destination::Register(temp.register);
307
308 self.emit_copy_value_between_destinations(
310 target_destination,
311 &value_source,
312 node,
313 "store grid height to destination",
314 );
315 }
316 _ => todo!("wrong grid {intrinsic_fn}"),
317 }
318 }
319
320 #[allow(clippy::too_many_lines)]
321 fn emit_intrinsic_call_vec(
322 &mut self,
323 output_destination: &Destination,
324 intrinsic_fn: &IntrinsicFunction,
325 self_ptr_reg: &PointerLocation,
326 arguments: &[Expression],
327 node: &Node,
328 ctx: &Context,
329 ) {
330 let self_basic_type = &self_ptr_reg.ptr_reg.ty.basic_type;
331 match intrinsic_fn {
332 IntrinsicFunction::VecPush => {
333 let element_expr = &arguments[0];
334
335 let element_gen_type = self.state.layout_cache.layout(&element_expr.ty);
336
337 let temp_element_ptr = self.temp_registers.allocate(
338 VmType::new_contained_in_register(pointer_type()),
339 "pointer to new element",
340 );
341
342 self.builder.add_vec_push_addr(
343 temp_element_ptr.register(),
344 &self_ptr_reg.ptr_reg,
345 node,
346 "set pointer to new element",
347 );
348
349 let location = AggregateMemoryLocation {
350 location: MemoryLocation {
351 base_ptr_reg: temp_element_ptr.register,
352 offset: MemoryOffset(0),
353 ty: VmType::new_unknown_placement(element_gen_type.clone()),
354 },
355 };
356
357 if element_gen_type.is_aggregate() {
359 self.emit_initialize_memory_for_any_type(
360 &location.location,
361 node,
362 "initialize vec.push allocated space",
363 );
364 }
365
366 self.emit_expression_into_target_memory(
367 &location.location,
368 element_expr,
369 "vec push",
370 ctx,
371 );
372 }
373
374 IntrinsicFunction::VecPop => {
375 let element_type = self_basic_type.element().unwrap();
376 let pop_target_reg = if let Some(found_target_reg) = output_destination.register() {
377 found_target_reg.clone()
378 } else {
379 let temp = self.temp_registers.allocate(
380 VmType::new_contained_in_register(element_type.clone()),
381 "temp for vec pop",
382 );
383 temp.register
384 };
385 self.builder.add_vec_pop(
386 &pop_target_reg,
387 &self_ptr_reg.ptr_reg, element_type.total_size,
389 node,
390 "vec pop",
391 );
392 let source_memory_location = MemoryLocation {
393 base_ptr_reg: pop_target_reg,
394 offset: MemoryOffset(0),
395 ty: VmType::new_unknown_placement(element_type),
396 };
397
398 self.emit_copy_value_from_memory_location(
399 output_destination,
400 &source_memory_location,
401 node,
402 "copy from vec pop",
403 );
404 }
405 IntrinsicFunction::VecRemoveIndex => {
406 let index_region_expr = &arguments[0];
407 let index_region = self.emit_scalar_rvalue(index_region_expr, ctx);
408
409 let element_type = self_basic_type.element().unwrap();
410
411 self.builder.add_vec_remove_index(
412 &self_ptr_reg.ptr_reg,
413 &index_region,
414 node,
415 "remove index",
416 );
417 }
418 IntrinsicFunction::VecRemoveIndexGetValue => {
419 let key_expr = &arguments[0];
420 let key_region = self.emit_scalar_rvalue(key_expr, ctx);
421 let element_type = self_basic_type.element().unwrap();
422
423 if let Some(target_reg) = output_destination.register() {
425 self.builder.add_vec_remove_index_get_value(
427 target_reg,
428 &self_ptr_reg.ptr_reg, &key_region,
430 node,
431 "vec remove index get value to register",
432 );
433 } else {
434 let temp_reg = self.temp_registers.allocate(
436 VmType::new_contained_in_register(element_type),
437 "temp for vec remove index get value",
438 );
439
440 self.builder.add_vec_remove_index_get_value(
441 &temp_reg.register,
442 &self_ptr_reg.ptr_reg,
443 &key_region,
444 node,
445 "vec remove index get value to temp",
446 );
447
448 let source = Destination::Register(temp_reg.register);
450 self.emit_copy_value_between_destinations(
451 output_destination,
452 &source,
453 node,
454 "copy vec element to destination",
455 );
456 }
457 }
458 IntrinsicFunction::VecRemoveFirstIndexGetValue => {
459 let zero_reg = self.temp_registers.allocate(
460 VmType::new_contained_in_register(u8_type()),
461 "vec remove first. set index 0",
462 );
463 self.builder
464 .add_mov8_immediate(zero_reg.register(), 0, node, "zero index");
465 let value_addr_reg = self.temp_registers.allocate(
466 VmType::new_contained_in_register(u32_type()),
467 "vec entry addr to copy from",
468 );
469 let element_type = self_basic_type.element().unwrap();
470 self.builder.add_vec_subscript(
471 value_addr_reg.register(),
472 &self_ptr_reg.ptr_reg,
473 zero_reg.register(),
474 element_type.total_size,
475 node,
476 "lookup first entry in vec",
477 );
478
479 let source_memory_location = MemoryLocation {
480 base_ptr_reg: value_addr_reg.register,
481 offset: MemoryOffset(0),
482 ty: VmType::new_unknown_placement(element_type),
483 };
484
485 self.emit_copy_value_from_memory_location(
486 output_destination,
487 &source_memory_location,
488 node,
489 "load the vec entry to target register",
490 );
491
492 self.builder.add_vec_remove_index(
493 &self_ptr_reg.ptr_reg, zero_reg.register(),
495 node,
496 "vec remove first index",
497 );
498 }
499 IntrinsicFunction::VecClear => {
500 let temp_element_count_reg = self.temp_registers.allocate(
501 VmType::new_contained_in_register(u16_type()),
502 "vec_clear zero",
503 );
504 self.builder.add_mov_16_immediate_value(
505 temp_element_count_reg.register(),
506 0,
507 node,
508 "set to zero",
509 );
510 self.builder.add_st16_using_ptr_with_offset(
511 output_destination.grab_memory_location(),
512 temp_element_count_reg.register(),
513 node,
514 "set element_count to zero",
515 );
516 }
517 IntrinsicFunction::VecGet => {
518 let key_expr = &arguments[0];
519 let key_region = self.emit_scalar_rvalue(key_expr, ctx);
520 let element_type = self_ptr_reg.ptr_reg.ty.basic_type.element().unwrap();
521
522 let temp_element_ptr = self.temp_registers.allocate(
524 VmType::new_contained_in_register(pointer_type()),
525 "temp for vec element address",
526 );
527
528 self.builder.add_vec_subscript(
530 temp_element_ptr.register(),
531 &self_ptr_reg.ptr_reg,
532 &key_region,
533 element_type.total_size,
534 node,
535 "get vec element address",
536 );
537
538 let element_memory_location = MemoryLocation {
540 base_ptr_reg: temp_element_ptr.register,
541 offset: MemoryOffset(0),
542 ty: VmType::new_unknown_placement(element_type),
543 };
544
545 self.emit_copy_value_from_memory_location(
547 output_destination,
548 &element_memory_location,
549 node,
550 "copy vec element to destination",
551 );
552 }
553 _ => todo!("Vec {intrinsic_fn}"),
554 }
555
556 }
579
580 fn emit_intrinsic_call_int(
581 &mut self,
582 target_reg: &TypedRegister,
583 intrinsic_fn: &IntrinsicFunction,
584 arguments: &[TypedRegister],
585 node: &Node,
586 ) {
587 let first_argument = &arguments[0];
588
589 match intrinsic_fn {
591 IntrinsicFunction::IntAbs => {
592 self.builder
593 .add_int_abs(target_reg, first_argument, node, "int abs");
594 }
595
596 IntrinsicFunction::IntRnd => {
597 self.builder
598 .add_int_rnd(target_reg, first_argument, node, "int pseudo random");
599 }
600 IntrinsicFunction::IntMax => {
601 let int_register = &arguments[1];
602
603 self.builder
604 .add_int_max(target_reg, first_argument, int_register, node, "int max");
605 }
606 IntrinsicFunction::IntMin => {
607 let int_register = &arguments[1];
608
609 self.builder
610 .add_int_min(target_reg, first_argument, int_register, node, "int min");
611 }
612 IntrinsicFunction::IntClamp => {
613 let min_reg = &arguments[1];
614 let max_reg = &arguments[2];
615 self.builder.add_int_clamp(
616 target_reg,
617 first_argument,
618 min_reg,
619 max_reg,
620 node,
621 "int clamp",
622 );
623 }
624 IntrinsicFunction::IntToFloat => {
625 self.builder.add_int_to_float(
626 target_reg,
627 first_argument,
628 node,
629 &format!("int to float {}", first_argument.comment()),
630 );
631 }
632 IntrinsicFunction::IntToString => {
633 self.builder
634 .add_int_to_string(target_reg, first_argument, node, "int_to_string");
635 }
636 _ => {}
637 }
638 }
640
641 #[allow(clippy::too_many_lines)]
642 fn emit_intrinsic_call_fixed(
643 &mut self,
644 target_reg: &TypedRegister,
645 intrinsic_fn: &IntrinsicFunction,
646 arguments: &[TypedRegister],
647 node: &Node,
648 ) {
649 let first_argument_reg = &arguments[0];
651 match intrinsic_fn {
652 IntrinsicFunction::FloatRound => {
653 self.builder
654 .add_float_round(target_reg, first_argument_reg, node, "float round");
655 }
656 IntrinsicFunction::FloatFloor => {
657 self.builder
658 .add_float_floor(target_reg, first_argument_reg, node, "float floor");
659 }
660 IntrinsicFunction::FloatSqrt => {
661 self.builder
662 .add_float_sqrt(target_reg, first_argument_reg, node, "float sqr");
663 }
664 IntrinsicFunction::FloatSign => {
665 self.builder
666 .add_float_sign(target_reg, first_argument_reg, node, "float sign");
667 }
668 IntrinsicFunction::FloatAbs => {
669 self.builder
670 .add_float_abs(target_reg, first_argument_reg, node, "float abs");
671 }
672 IntrinsicFunction::FloatRnd => {
673 self.builder.add_float_prnd(
674 target_reg,
675 first_argument_reg,
676 node,
677 "float pseudo random",
678 );
679 }
680 IntrinsicFunction::FloatCos => {
681 self.builder
682 .add_float_cos(target_reg, first_argument_reg, node, "float cos");
683 }
684 IntrinsicFunction::FloatSin => {
685 self.builder
686 .add_float_sin(target_reg, first_argument_reg, node, "float sin");
687 }
688 IntrinsicFunction::FloatAcos => {
689 self.builder
690 .add_float_acos(target_reg, first_argument_reg, node, "float acos");
691 }
692 IntrinsicFunction::FloatAsin => {
693 self.builder
694 .add_float_asin(target_reg, first_argument_reg, node, "float asin");
695 }
696 IntrinsicFunction::FloatAtan2 => {
697 self.builder
698 .add_float_atan2(target_reg, first_argument_reg, node, "float atan2");
699 }
700 IntrinsicFunction::FloatMin => {
701 let float_region = &arguments[1];
702 self.builder.add_float_min(
703 target_reg,
704 first_argument_reg,
705 float_region,
706 node,
707 "float min",
708 );
709 }
710 IntrinsicFunction::FloatMax => {
711 let float_region = &arguments[1];
712 self.builder.add_float_max(
713 target_reg,
714 first_argument_reg,
715 float_region,
716 node,
717 "float max",
718 );
719 }
720 IntrinsicFunction::FloatClamp => {
721 let float_region = &arguments[1];
722 let float_b_region = &arguments[2];
723
724 self.builder.add_float_clamp(
725 target_reg,
726 float_region,
727 first_argument_reg,
728 float_b_region,
729 node,
730 "float round",
731 );
732 }
733 IntrinsicFunction::FloatToString => self.builder.float_to_string(
734 target_reg,
735 first_argument_reg,
736 node,
737 "float_to_string",
738 ),
739 _ => panic!("wasn't a fixed operation"),
740 }
741 }
743
744 pub fn emit_intrinsic_transformer(
745 &mut self,
746 target_destination: &Destination,
747 intrinsic_fn: &IntrinsicFunction,
748 self_addr: &PointerLocation,
749 lambda: (Vec<VariableRef>, &Expression),
750 node: &Node,
751 ctx: &Context,
752 ) {
753 match intrinsic_fn {
754 IntrinsicFunction::TransformerFold => { }
756 IntrinsicFunction::TransformerFilter => {
757 self.emit_iterate_over_collection_with_lambda(
758 target_destination,
759 node,
760 Collection::Vec,
761 Transformer::Filter,
762 &self_addr.ptr_reg,
763 lambda,
764 ctx,
765 );
766 }
767
768 IntrinsicFunction::TransformerFor => {
769 self.emit_iterate_over_collection_with_lambda(
770 target_destination,
771 node,
772 Collection::Vec,
773 Transformer::For,
774 &self_addr.ptr_reg,
775 lambda,
776 ctx,
777 );
778 }
779 IntrinsicFunction::TransformerWhile => {
780 self.emit_iterate_over_collection_with_lambda(
781 target_destination,
782 node,
783 Collection::Vec,
784 Transformer::While,
785 &self_addr.ptr_reg,
786 lambda,
787 ctx,
788 );
789 }
790
791 IntrinsicFunction::TransformerFind => {
792 self.emit_iterate_over_collection_with_lambda(
793 target_destination,
794 node,
795 Collection::Vec,
796 Transformer::Find,
797 &self_addr.ptr_reg,
798 lambda,
799 ctx,
800 );
801 }
802 _ => todo!("{intrinsic_fn}"),
803 }
804 }
805
806 #[allow(clippy::too_many_lines)]
807 #[allow(clippy::too_many_arguments)]
808 pub fn emit_single_intrinsic_call_with_self_destination(
809 &mut self,
810 target_destination: &Destination,
811 node: &Node,
812 intrinsic_fn: &IntrinsicFunction,
813 self_destination: Option<&Destination>,
814 arguments: &[ArgumentExpression],
815 ctx: &Context,
816 comment: &str,
817 ) {
818 let self_reg = if let Some(self_dest) = self_destination {
820 self.emit_load_scalar_or_absolute_aggregate_pointer(self_dest, node, comment)
821 } else {
822 None
823 };
824
825 self.emit_single_intrinsic_call_with_self(
827 target_destination,
828 node,
829 intrinsic_fn,
830 self_reg.as_ref(),
831 arguments,
832 ctx,
833 comment,
834 );
835 }
836
837 #[allow(clippy::too_many_lines)]
838 #[allow(clippy::too_many_arguments)]
839 pub fn emit_single_intrinsic_call_with_self(
840 &mut self,
841 target_destination: &Destination,
842 node: &Node,
843 intrinsic_fn: &IntrinsicFunction,
844 self_reg: Option<&TypedRegister>,
845 arguments: &[ArgumentExpression],
846 ctx: &Context,
847 comment: &str,
848 ) {
849 let maybe_target = target_destination.register();
850
851 match intrinsic_fn {
852 IntrinsicFunction::Float2Magnitude
853 | IntrinsicFunction::FloatAbs
854 | IntrinsicFunction::FloatRound
855 | IntrinsicFunction::FloatFloor
856 | IntrinsicFunction::FloatSqrt
857 | IntrinsicFunction::FloatSign
858 | IntrinsicFunction::FloatRnd
859 | IntrinsicFunction::FloatCos
860 | IntrinsicFunction::FloatSin
861 | IntrinsicFunction::FloatAcos
862 | IntrinsicFunction::FloatAsin
863 | IntrinsicFunction::FloatAtan2
864 | IntrinsicFunction::FloatMin
865 | IntrinsicFunction::FloatMax
866 | IntrinsicFunction::FloatClamp
867 | IntrinsicFunction::FloatToString => {
868 let (temp_reg, dest_reg) = if target_destination.is_register() {
870 (None, target_destination.register().unwrap().clone())
871 } else {
872 let temp_reg = self.temp_registers.allocate(
873 VmType::new_contained_in_register(float_type()),
874 "temporary destination for low level intrinsic",
875 );
876
877 (Some(temp_reg.register.clone()), temp_reg.register)
878 };
879
880 let mut converted_regs = vec![self_reg.unwrap().clone()];
882 for arg in arguments {
883 let ArgumentExpression::Expression(found_expression) = arg else {
884 panic!("must be expression");
885 };
886 let materialized_arg = self.emit_scalar_rvalue(found_expression, ctx);
887 converted_regs.push(materialized_arg);
888 }
889
890 self.emit_intrinsic_call_fixed(&dest_reg, intrinsic_fn, &converted_regs, node);
891
892 if let Some(temp_reg) = temp_reg {
893 self.emit_store_scalar_to_memory_offset_instruction(
894 target_destination.grab_memory_location(),
895 &temp_reg,
896 node,
897 "store the fixed point value into memory",
898 );
899 }
900 }
901
902 IntrinsicFunction::IntToFloat => {
903 let (temp_reg, dest_reg) = if target_destination.is_register() {
905 (None, target_destination.register().unwrap().clone())
906 } else {
907 let temp_reg = self.temp_registers.allocate(
908 VmType::new_contained_in_register(float_type()),
909 "temporary destination for int to float intrinsic",
910 );
911
912 (Some(temp_reg.register.clone()), temp_reg.register)
913 };
914
915 let int_value_reg = self_reg.unwrap();
917
918 self.builder.add_int_to_float(
920 &dest_reg,
921 int_value_reg,
922 node,
923 &format!("int to float {}", int_value_reg.comment()),
924 );
925
926 if let Some(temp_reg) = temp_reg {
927 self.emit_store_scalar_to_memory_offset_instruction(
928 target_destination.grab_memory_location(),
929 &temp_reg,
930 node,
931 "store the float result from int to float conversion",
932 );
933 }
934 }
935
936 IntrinsicFunction::IntAbs
937 | IntrinsicFunction::IntRnd
938 | IntrinsicFunction::IntMax
939 | IntrinsicFunction::IntMin
940 | IntrinsicFunction::IntClamp
941 | IntrinsicFunction::IntToString => {
942 let (temp_reg, dest_reg) = if target_destination.is_register() {
944 let target_reg = target_destination.register().unwrap();
945 (None, target_reg.clone())
947 } else {
948 let temp_reg = self.temp_registers.allocate(
949 VmType::new_contained_in_register(u32_type()),
950 "temporary destination for low level intrinsic",
951 );
952
953 (Some(temp_reg.register.clone()), temp_reg.register)
954 };
955
956 let mut converted_regs = vec![self_reg.unwrap().clone()];
958 for arg in arguments {
959 let ArgumentExpression::Expression(found_expression) = arg else {
960 panic!("must be expression");
961 };
962 let materialized_arg = self.emit_scalar_rvalue(found_expression, ctx);
963 converted_regs.push(materialized_arg);
964 }
965
966 self.emit_intrinsic_call_int(&dest_reg, intrinsic_fn, &converted_regs, node);
967
968 if let Some(temp_reg) = temp_reg {
969 if target_destination.is_register() {
970 self.builder.add_mov_reg(
972 target_destination.register().unwrap(),
973 &temp_reg,
974 node,
975 "copy intrinsic result from temp to target register",
976 );
977 } else {
978 self.emit_store_scalar_to_memory_offset_instruction(
980 target_destination.grab_memory_location(),
981 &temp_reg,
982 node,
983 "put the low level intrinsic fixed (int) back to memory",
984 );
985 }
986 }
987 }
988
989 IntrinsicFunction::VecPush
990 | IntrinsicFunction::VecPop
991 | IntrinsicFunction::VecRemoveIndex
992 | IntrinsicFunction::VecRemoveIndexGetValue
993 | IntrinsicFunction::VecRemoveFirstIndexGetValue
994 | IntrinsicFunction::VecClear
995 | IntrinsicFunction::VecSwap
996 | IntrinsicFunction::VecInsert
997 | IntrinsicFunction::VecFirst
998 | IntrinsicFunction::VecGet
999 | IntrinsicFunction::VecLast => {
1000 let vec_self_ptr_reg = PointerLocation {
1003 ptr_reg: self_reg.unwrap().clone(),
1004 };
1005 let converted_to_expressions: Vec<_> = arguments
1006 .iter()
1007 .map(|arg| {
1008 let ArgumentExpression::Expression(found_expression) = arg else {
1009 panic!("must be expression");
1010 };
1011 found_expression.clone()
1012 })
1013 .collect();
1014
1015 self.emit_intrinsic_call_vec(
1016 target_destination,
1017 intrinsic_fn,
1018 &vec_self_ptr_reg,
1019 &converted_to_expressions,
1020 node,
1021 ctx,
1022 );
1023 }
1024
1025 IntrinsicFunction::GridGet
1026 | IntrinsicFunction::GridSet
1027 | IntrinsicFunction::GridWidth
1028 | IntrinsicFunction::GridHeight => {
1029 let grid_self_ptr_reg = PointerLocation {
1032 ptr_reg: self_reg.unwrap().clone(),
1033 };
1034 let converted_to_expressions: Vec<_> = arguments
1035 .iter()
1036 .map(|arg| {
1037 let ArgumentExpression::Expression(found_expression) = arg else {
1038 panic!("must be expression");
1039 };
1040 found_expression.clone()
1041 })
1042 .collect();
1043 self.emit_intrinsic_grid(
1044 target_destination,
1045 intrinsic_fn,
1046 &grid_self_ptr_reg,
1047 &converted_to_expressions,
1048 node,
1049 comment,
1050 ctx,
1051 );
1052 }
1053
1054 IntrinsicFunction::SparseIsAlive
1055 | IntrinsicFunction::SparseRemove
1056 | IntrinsicFunction::SparseAdd => {
1057 let grid_self_ptr_reg = PointerLocation {
1060 ptr_reg: self_reg.unwrap().clone(),
1061 };
1062 let converted_to_expressions: Vec<_> = arguments
1063 .iter()
1064 .map(|arg| {
1065 let ArgumentExpression::Expression(found_expression) = arg else {
1066 panic!("must be expression");
1067 };
1068 found_expression.clone()
1069 })
1070 .collect();
1071 self.emit_intrinsic_sparse(
1072 target_destination,
1073 intrinsic_fn,
1074 &grid_self_ptr_reg,
1075 &converted_to_expressions,
1076 node,
1077 comment,
1078 ctx,
1079 );
1080 }
1081
1082 IntrinsicFunction::TransformerFor
1083 | IntrinsicFunction::TransformerWhile
1084 | IntrinsicFunction::TransformerFindMap
1085 | IntrinsicFunction::TransformerAny
1086 | IntrinsicFunction::TransformerAll
1087 | IntrinsicFunction::TransformerMap
1088 | IntrinsicFunction::TransformerFilter
1089 | IntrinsicFunction::TransformerFilterMap
1090 | IntrinsicFunction::TransformerFind
1091 | IntrinsicFunction::TransformerFold => {
1092 let collection_self_ptr_reg = PointerLocation {
1094 ptr_reg: self_reg.unwrap().clone(),
1095 };
1096
1097 let lambda_expression = &arguments[0];
1098
1099 let ArgumentExpression::Expression(expr) = lambda_expression else {
1101 panic!("err");
1102 };
1103
1104 let ExpressionKind::Lambda(lambda_variables, lambda_expr) = &expr.kind else {
1105 panic!("must have lambda for transformers");
1106 };
1107
1108 self.emit_intrinsic_transformer(
1109 target_destination,
1110 intrinsic_fn,
1111 &collection_self_ptr_reg,
1112 (lambda_variables.clone(), lambda_expr),
1113 node,
1114 ctx,
1115 );
1116 }
1117
1118 IntrinsicFunction::RuntimePanic => {
1119 self.builder
1120 .add_panic(self_reg.unwrap(), node, "intrinsic panic");
1121 }
1122
1123 IntrinsicFunction::RuntimeHalt => {
1124 self.builder.add_halt(node, "intrinsic halt");
1125 }
1126
1127 IntrinsicFunction::RuntimeStep => {
1128 self.builder.add_step(node, "intrinsic step");
1129 }
1130
1131 IntrinsicFunction::RangeInit => {
1132 let start_reg = self_reg.unwrap();
1133 let end_arg = &arguments[0];
1139 let ArgumentExpression::Expression(end_arg_expr) = end_arg else {
1140 panic!();
1141 };
1142 let end_reg = self.emit_scalar_rvalue(end_arg_expr, ctx);
1143
1144 let is_inclusive = &arguments[1];
1145 let ArgumentExpression::Expression(is_inclusive_expr) = is_inclusive else {
1146 panic!();
1147 };
1148 let is_inclusive_reg = self.emit_scalar_rvalue(is_inclusive_expr, ctx);
1149 let absolute_range_pointer = self.emit_compute_effective_address_to_register(
1150 target_destination,
1151 node,
1152 "create range target pointer",
1153 );
1154 self.builder.add_range_init(
1155 &absolute_range_pointer,
1156 start_reg,
1157 &end_reg,
1158 &is_inclusive_reg,
1159 node,
1160 "create a range",
1161 );
1162 }
1163
1164 IntrinsicFunction::CodepointToString => {
1166 if maybe_target.is_none() {
1167 eprintln!("problem");
1168 }
1169 self.builder.codepoint_to_string(
1170 maybe_target.unwrap(),
1171 self_reg.unwrap(),
1172 node,
1173 "char_to_string",
1174 );
1175 }
1176
1177 IntrinsicFunction::CodepointToInt => {
1178 if maybe_target.is_none() {
1179 eprintln!("problem");
1180 }
1181 self.builder.add_mov_reg(
1182 maybe_target.unwrap(),
1183 self_reg.unwrap(),
1184 node,
1185 "char_to_int",
1186 );
1187 }
1188
1189 IntrinsicFunction::ByteToString => {
1191 if maybe_target.is_none() {
1192 eprintln!("problem");
1193 }
1194 self.builder.byte_to_string(
1195 maybe_target.unwrap(),
1196 self_reg.unwrap(),
1197 node,
1198 "byte_to_string",
1199 );
1200 }
1201
1202 IntrinsicFunction::ByteToInt => {
1203 if maybe_target.is_none() {
1204 eprintln!("problem");
1205 }
1206 self.builder.add_mov_reg(
1209 maybe_target.unwrap(),
1210 self_reg.unwrap(),
1211 node,
1212 "byte_to_int",
1213 );
1214 }
1215
1216 IntrinsicFunction::BoolToString => {
1218 if maybe_target.is_none() {
1219 eprintln!("problem");
1220 }
1221 self.builder.bool_to_string(
1222 maybe_target.unwrap(),
1223 self_reg.unwrap(),
1224 node,
1225 "bool_to_string",
1226 );
1227 }
1228
1229 IntrinsicFunction::StringToString => {
1230 self.builder.string_to_string(
1231 maybe_target.unwrap(),
1232 self_reg.unwrap(),
1233 node,
1234 "string_to_string",
1235 );
1236 }
1237
1238 IntrinsicFunction::MapIsEmpty | IntrinsicFunction::VecIsEmpty => {
1240 let collection_pointer = PointerLocation {
1241 ptr_reg: self_reg.unwrap().clone(),
1242 };
1243 self.emit_collection_is_empty(
1244 maybe_target.unwrap().clone(),
1245 &collection_pointer,
1246 node,
1247 "vec empty",
1248 );
1249 }
1250
1251 IntrinsicFunction::StringLen
1252 | IntrinsicFunction::MapLen
1253 | IntrinsicFunction::VecLen => {
1254 let collection_pointer = PointerLocation {
1255 ptr_reg: self_reg.unwrap().clone(),
1256 };
1257 self.emit_collection_len(
1258 maybe_target.unwrap(),
1259 &collection_pointer,
1260 node,
1261 "get the collection element_count",
1262 );
1263 }
1264 IntrinsicFunction::MapCapacity | IntrinsicFunction::VecCapacity => {
1265 let collection_pointer = PointerLocation {
1266 ptr_reg: self_reg.unwrap().clone(),
1267 };
1268 self.emit_collection_capacity(
1269 maybe_target.unwrap(),
1270 &collection_pointer,
1271 node,
1272 "get the collection element_count",
1273 );
1274 }
1275
1276 IntrinsicFunction::MapRemove | IntrinsicFunction::MapHas => {
1277 let grid_self_ptr_reg = PointerLocation {
1280 ptr_reg: self_reg.unwrap().clone(),
1281 };
1282 let converted_to_expressions: Vec<_> = arguments
1283 .iter()
1284 .map(|arg| {
1285 let ArgumentExpression::Expression(found_expression) = arg else {
1286 panic!("must be expression");
1287 };
1288 found_expression.clone()
1289 })
1290 .collect();
1291 self.emit_intrinsic_map(
1292 target_destination,
1293 intrinsic_fn,
1294 &grid_self_ptr_reg,
1295 &converted_to_expressions,
1296 node,
1297 comment,
1298 ctx,
1299 );
1300 } }
1302 }
1303
1304 fn emit_intrinsic_map_remove(
1305 &mut self,
1306 map_header_reg: &PointerLocation,
1307 key_expression: &Expression,
1308 ctx: &Context,
1309 ) {
1310 let key_register =
1311 self.emit_aggregate_pointer_or_pointer_to_scalar_memory(key_expression, ctx);
1312
1313 self.builder
1314 .add_map_remove(map_header_reg, &key_register, &key_expression.node, "");
1315 }
1316
1317 fn emit_collection_capacity(
1318 &mut self,
1319 output_reg: &TypedRegister,
1320 collection_addr: &PointerLocation,
1321 node: &Node,
1322 comment: &str,
1323 ) {
1324 self.builder.add_ld16_from_pointer_with_offset_u16(
1325 output_reg,
1326 &collection_addr.ptr_reg,
1327 COLLECTION_CAPACITY_OFFSET,
1328 node,
1329 comment,
1330 );
1331 }
1332
1333 fn emit_collection_len(
1334 &mut self,
1335 output_reg: &TypedRegister,
1336 collection_addr: &PointerLocation,
1337 node: &Node,
1338 comment: &str,
1339 ) {
1340 self.builder.add_ld16_from_pointer_with_offset_u16(
1341 output_reg,
1342 &collection_addr.ptr_reg,
1343 COLLECTION_ELEMENT_COUNT_OFFSET,
1344 node,
1345 &format!("{comment} - collection element_count"),
1346 );
1347 }
1348
1349 fn emit_collection_is_empty(
1350 &mut self,
1351 output_reg: TypedRegister,
1352 collection_addr: &PointerLocation,
1353 node: &Node,
1354 _comment: &str,
1355 ) {
1356 self.builder.add_ld16_from_pointer_with_offset_u16(
1357 &output_reg,
1358 &collection_addr.ptr_reg,
1359 COLLECTION_ELEMENT_COUNT_OFFSET,
1360 node,
1361 "get the map length for testing if it is empty",
1362 );
1363 self.builder.add_seqz(
1364 &output_reg,
1365 &output_reg,
1366 node,
1367 "convert the map length to inverted bool",
1368 );
1369 }
1370}