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
406 IntrinsicFunction::VecSlice => {
407 let range_expr = &arguments[0];
408 let range_region = self.emit_scalar_rvalue(range_expr, ctx);
409
410 self.builder.add_vec_copy_range(&output_destination.grab_memory_location().pointer_location().unwrap(), self_ptr_reg, &range_region, node, "vec slice");
411 }
412
413 IntrinsicFunction::VecRemoveIndex => {
414 let index_region_expr = &arguments[0];
415 let index_region = self.emit_scalar_rvalue(index_region_expr, ctx);
416
417 let element_type = self_basic_type.element().unwrap();
418
419 self.builder.add_vec_remove_index(
420 &self_ptr_reg.ptr_reg,
421 &index_region,
422 node,
423 "remove index",
424 );
425 }
426 IntrinsicFunction::VecRemoveIndexGetValue => {
427 let key_expr = &arguments[0];
428 let key_region = self.emit_scalar_rvalue(key_expr, ctx);
429 let element_type = self_basic_type.element().unwrap();
430
431 if let Some(target_reg) = output_destination.register() {
433 self.builder.add_vec_remove_index_get_value(
435 target_reg,
436 &self_ptr_reg.ptr_reg, &key_region,
438 node,
439 "vec remove index get value to register",
440 );
441 } else {
442 let temp_reg = self.temp_registers.allocate(
444 VmType::new_contained_in_register(element_type),
445 "temp for vec remove index get value",
446 );
447
448 self.builder.add_vec_remove_index_get_value(
449 &temp_reg.register,
450 &self_ptr_reg.ptr_reg,
451 &key_region,
452 node,
453 "vec remove index get value to temp",
454 );
455
456 let source = Destination::Register(temp_reg.register);
458 self.emit_copy_value_between_destinations(
459 output_destination,
460 &source,
461 node,
462 "copy vec element to destination",
463 );
464 }
465 }
466 IntrinsicFunction::VecRemoveFirstIndexGetValue => {
467 let zero_reg = self.temp_registers.allocate(
468 VmType::new_contained_in_register(u8_type()),
469 "vec remove first. set index 0",
470 );
471 self.builder
472 .add_mov8_immediate(zero_reg.register(), 0, node, "zero index");
473 let value_addr_reg = self.temp_registers.allocate(
474 VmType::new_contained_in_register(u32_type()),
475 "vec entry addr to copy from",
476 );
477 let element_type = self_basic_type.element().unwrap();
478 self.builder.add_vec_subscript(
479 value_addr_reg.register(),
480 &self_ptr_reg.ptr_reg,
481 zero_reg.register(),
482 element_type.total_size,
483 node,
484 "lookup first entry in vec",
485 );
486
487 let source_memory_location = MemoryLocation {
488 base_ptr_reg: value_addr_reg.register,
489 offset: MemoryOffset(0),
490 ty: VmType::new_unknown_placement(element_type),
491 };
492
493 self.emit_copy_value_from_memory_location(
494 output_destination,
495 &source_memory_location,
496 node,
497 "load the vec entry to target register",
498 );
499
500 self.builder.add_vec_remove_index(
501 &self_ptr_reg.ptr_reg, zero_reg.register(),
503 node,
504 "vec remove first index",
505 );
506 }
507 IntrinsicFunction::VecClear => {
508 let temp_element_count_reg = self.temp_registers.allocate(
509 VmType::new_contained_in_register(u16_type()),
510 "vec_clear zero",
511 );
512 self.builder.add_mov_16_immediate_value(
513 temp_element_count_reg.register(),
514 0,
515 node,
516 "set to zero",
517 );
518 self.builder.add_st16_using_ptr_with_offset(
519 output_destination.grab_memory_location(),
520 temp_element_count_reg.register(),
521 node,
522 "set element_count to zero",
523 );
524 }
525
526 IntrinsicFunction::VecGet => {
527 let key_expr = &arguments[0];
528 let key_region = self.emit_scalar_rvalue(key_expr, ctx);
529 let element_type = self_ptr_reg.ptr_reg.ty.basic_type.element().unwrap();
530
531 let temp_element_ptr = self.temp_registers.allocate(
533 VmType::new_contained_in_register(pointer_type()),
534 "temp for vec element address",
535 );
536
537 self.builder.add_vec_subscript(
539 temp_element_ptr.register(),
540 &self_ptr_reg.ptr_reg,
541 &key_region,
542 element_type.total_size,
543 node,
544 "get vec element address",
545 );
546
547 let element_memory_location = MemoryLocation {
549 base_ptr_reg: temp_element_ptr.register,
550 offset: MemoryOffset(0),
551 ty: VmType::new_unknown_placement(element_type),
552 };
553
554 self.emit_copy_value_from_memory_location(
556 output_destination,
557 &element_memory_location,
558 node,
559 "copy vec element to destination",
560 );
561 }
562 _ => todo!("Vec {intrinsic_fn}"),
563 }
564
565 }
588
589 fn emit_intrinsic_call_int(
590 &mut self,
591 target_reg: &TypedRegister,
592 intrinsic_fn: &IntrinsicFunction,
593 arguments: &[TypedRegister],
594 node: &Node,
595 ) {
596 let first_argument = &arguments[0];
597
598 match intrinsic_fn {
600 IntrinsicFunction::IntAbs => {
601 self.builder
602 .add_int_abs(target_reg, first_argument, node, "int abs");
603 }
604
605 IntrinsicFunction::IntRnd => {
606 self.builder
607 .add_int_rnd(target_reg, first_argument, node, "int pseudo random");
608 }
609 IntrinsicFunction::IntMax => {
610 let int_register = &arguments[1];
611
612 self.builder
613 .add_int_max(target_reg, first_argument, int_register, node, "int max");
614 }
615 IntrinsicFunction::IntMin => {
616 let int_register = &arguments[1];
617
618 self.builder
619 .add_int_min(target_reg, first_argument, int_register, node, "int min");
620 }
621 IntrinsicFunction::IntClamp => {
622 let min_reg = &arguments[1];
623 let max_reg = &arguments[2];
624 self.builder.add_int_clamp(
625 target_reg,
626 first_argument,
627 min_reg,
628 max_reg,
629 node,
630 "int clamp",
631 );
632 }
633 IntrinsicFunction::IntToFloat => {
634 self.builder.add_int_to_float(
635 target_reg,
636 first_argument,
637 node,
638 &format!("int to float {}", first_argument.comment()),
639 );
640 }
641 IntrinsicFunction::IntToString => {
642 self.builder
643 .add_int_to_string(target_reg, first_argument, node, "int_to_string");
644 }
645 _ => {}
646 }
647 }
649
650 #[allow(clippy::too_many_lines)]
651 fn emit_intrinsic_call_fixed(
652 &mut self,
653 target_reg: &TypedRegister,
654 intrinsic_fn: &IntrinsicFunction,
655 arguments: &[TypedRegister],
656 node: &Node,
657 ) {
658 let first_argument_reg = &arguments[0];
660 match intrinsic_fn {
661 IntrinsicFunction::FloatRound => {
662 self.builder
663 .add_float_round(target_reg, first_argument_reg, node, "float round");
664 }
665 IntrinsicFunction::FloatFloor => {
666 self.builder
667 .add_float_floor(target_reg, first_argument_reg, node, "float floor");
668 }
669 IntrinsicFunction::FloatSqrt => {
670 self.builder
671 .add_float_sqrt(target_reg, first_argument_reg, node, "float sqr");
672 }
673 IntrinsicFunction::FloatSign => {
674 self.builder
675 .add_float_sign(target_reg, first_argument_reg, node, "float sign");
676 }
677 IntrinsicFunction::FloatAbs => {
678 self.builder
679 .add_float_abs(target_reg, first_argument_reg, node, "float abs");
680 }
681 IntrinsicFunction::FloatRnd => {
682 self.builder.add_float_prnd(
683 target_reg,
684 first_argument_reg,
685 node,
686 "float pseudo random",
687 );
688 }
689 IntrinsicFunction::FloatCos => {
690 self.builder
691 .add_float_cos(target_reg, first_argument_reg, node, "float cos");
692 }
693 IntrinsicFunction::FloatSin => {
694 self.builder
695 .add_float_sin(target_reg, first_argument_reg, node, "float sin");
696 }
697 IntrinsicFunction::FloatAcos => {
698 self.builder
699 .add_float_acos(target_reg, first_argument_reg, node, "float acos");
700 }
701 IntrinsicFunction::FloatAsin => {
702 self.builder
703 .add_float_asin(target_reg, first_argument_reg, node, "float asin");
704 }
705 IntrinsicFunction::FloatAtan2 => {
706 self.builder
707 .add_float_atan2(target_reg, first_argument_reg, node, "float atan2");
708 }
709 IntrinsicFunction::FloatMin => {
710 let float_region = &arguments[1];
711 self.builder.add_float_min(
712 target_reg,
713 first_argument_reg,
714 float_region,
715 node,
716 "float min",
717 );
718 }
719 IntrinsicFunction::FloatMax => {
720 let float_region = &arguments[1];
721 self.builder.add_float_max(
722 target_reg,
723 first_argument_reg,
724 float_region,
725 node,
726 "float max",
727 );
728 }
729 IntrinsicFunction::FloatClamp => {
730 let float_region = &arguments[1];
731 let float_b_region = &arguments[2];
732
733 self.builder.add_float_clamp(
734 target_reg,
735 float_region,
736 first_argument_reg,
737 float_b_region,
738 node,
739 "float round",
740 );
741 }
742 IntrinsicFunction::FloatToString => self.builder.float_to_string(
743 target_reg,
744 first_argument_reg,
745 node,
746 "float_to_string",
747 ),
748 _ => panic!("wasn't a fixed operation"),
749 }
750 }
752
753 pub fn emit_intrinsic_transformer(
754 &mut self,
755 target_destination: &Destination,
756 intrinsic_fn: &IntrinsicFunction,
757 self_addr: &PointerLocation,
758 lambda: (Vec<VariableRef>, &Expression),
759 node: &Node,
760 ctx: &Context,
761 ) {
762 match intrinsic_fn {
763 IntrinsicFunction::TransformerFold => { }
765 IntrinsicFunction::TransformerFilter => {
766 self.emit_iterate_over_collection_with_lambda(
767 target_destination,
768 node,
769 Collection::Vec,
770 Transformer::Filter,
771 &self_addr.ptr_reg,
772 lambda,
773 ctx,
774 );
775 }
776
777 IntrinsicFunction::TransformerFor => {
778 self.emit_iterate_over_collection_with_lambda(
779 target_destination,
780 node,
781 Collection::Vec,
782 Transformer::For,
783 &self_addr.ptr_reg,
784 lambda,
785 ctx,
786 );
787 }
788 IntrinsicFunction::TransformerWhile => {
789 self.emit_iterate_over_collection_with_lambda(
790 target_destination,
791 node,
792 Collection::Vec,
793 Transformer::While,
794 &self_addr.ptr_reg,
795 lambda,
796 ctx,
797 );
798 }
799
800 IntrinsicFunction::TransformerFind => {
801 self.emit_iterate_over_collection_with_lambda(
802 target_destination,
803 node,
804 Collection::Vec,
805 Transformer::Find,
806 &self_addr.ptr_reg,
807 lambda,
808 ctx,
809 );
810 }
811 _ => todo!("{intrinsic_fn}"),
812 }
813 }
814
815 #[allow(clippy::too_many_lines)]
816 #[allow(clippy::too_many_arguments)]
817 pub fn emit_single_intrinsic_call_with_self_destination(
818 &mut self,
819 target_destination: &Destination,
820 node: &Node,
821 intrinsic_fn: &IntrinsicFunction,
822 self_destination: Option<&Destination>,
823 arguments: &[ArgumentExpression],
824 ctx: &Context,
825 comment: &str,
826 ) {
827 let self_reg = if let Some(self_dest) = self_destination {
829 self.emit_load_scalar_or_absolute_aggregate_pointer(self_dest, node, comment)
830 } else {
831 None
832 };
833
834 self.emit_single_intrinsic_call_with_self(
836 target_destination,
837 node,
838 intrinsic_fn,
839 self_reg.as_ref(),
840 arguments,
841 ctx,
842 comment,
843 );
844 }
845
846 #[allow(clippy::too_many_lines)]
847 #[allow(clippy::too_many_arguments)]
848 pub fn emit_single_intrinsic_call_with_self(
849 &mut self,
850 target_destination: &Destination,
851 node: &Node,
852 intrinsic_fn: &IntrinsicFunction,
853 self_reg: Option<&TypedRegister>,
854 arguments: &[ArgumentExpression],
855 ctx: &Context,
856 comment: &str,
857 ) {
858 let maybe_target = target_destination.register();
859
860 match intrinsic_fn {
861 IntrinsicFunction::Float2Magnitude
862 | IntrinsicFunction::FloatAbs
863 | IntrinsicFunction::FloatRound
864 | IntrinsicFunction::FloatFloor
865 | IntrinsicFunction::FloatSqrt
866 | IntrinsicFunction::FloatSign
867 | IntrinsicFunction::FloatRnd
868 | IntrinsicFunction::FloatCos
869 | IntrinsicFunction::FloatSin
870 | IntrinsicFunction::FloatAcos
871 | IntrinsicFunction::FloatAsin
872 | IntrinsicFunction::FloatAtan2
873 | IntrinsicFunction::FloatMin
874 | IntrinsicFunction::FloatMax
875 | IntrinsicFunction::FloatClamp
876 | IntrinsicFunction::FloatToString => {
877 let (temp_reg, dest_reg) = if target_destination.is_register() {
879 (None, target_destination.register().unwrap().clone())
880 } else {
881 let temp_reg = self.temp_registers.allocate(
882 VmType::new_contained_in_register(float_type()),
883 "temporary destination for low level intrinsic",
884 );
885
886 (Some(temp_reg.register.clone()), temp_reg.register)
887 };
888
889 let mut converted_regs = vec![self_reg.unwrap().clone()];
891 for arg in arguments {
892 let ArgumentExpression::Expression(found_expression) = arg else {
893 panic!("must be expression");
894 };
895 let materialized_arg = self.emit_scalar_rvalue(found_expression, ctx);
896 converted_regs.push(materialized_arg);
897 }
898
899 self.emit_intrinsic_call_fixed(&dest_reg, intrinsic_fn, &converted_regs, node);
900
901 if let Some(temp_reg) = temp_reg {
902 self.emit_store_scalar_to_memory_offset_instruction(
903 target_destination.grab_memory_location(),
904 &temp_reg,
905 node,
906 "store the fixed point value into memory",
907 );
908 }
909 }
910
911 IntrinsicFunction::IntToFloat => {
912 let (temp_reg, dest_reg) = if target_destination.is_register() {
914 (None, target_destination.register().unwrap().clone())
915 } else {
916 let temp_reg = self.temp_registers.allocate(
917 VmType::new_contained_in_register(float_type()),
918 "temporary destination for int to float intrinsic",
919 );
920
921 (Some(temp_reg.register.clone()), temp_reg.register)
922 };
923
924 let int_value_reg = self_reg.unwrap();
926
927 self.builder.add_int_to_float(
929 &dest_reg,
930 int_value_reg,
931 node,
932 &format!("int to float {}", int_value_reg.comment()),
933 );
934
935 if let Some(temp_reg) = temp_reg {
936 self.emit_store_scalar_to_memory_offset_instruction(
937 target_destination.grab_memory_location(),
938 &temp_reg,
939 node,
940 "store the float result from int to float conversion",
941 );
942 }
943 }
944
945 IntrinsicFunction::IntAbs
946 | IntrinsicFunction::IntRnd
947 | IntrinsicFunction::IntMax
948 | IntrinsicFunction::IntMin
949 | IntrinsicFunction::IntClamp
950 | IntrinsicFunction::IntToString => {
951 let (temp_reg, dest_reg) = if target_destination.is_register() {
953 let target_reg = target_destination.register().unwrap();
954 (None, target_reg.clone())
956 } else {
957 let temp_reg = self.temp_registers.allocate(
958 VmType::new_contained_in_register(u32_type()),
959 "temporary destination for low level intrinsic",
960 );
961
962 (Some(temp_reg.register.clone()), temp_reg.register)
963 };
964
965 let mut converted_regs = vec![self_reg.unwrap().clone()];
967 for arg in arguments {
968 let ArgumentExpression::Expression(found_expression) = arg else {
969 panic!("must be expression");
970 };
971 let materialized_arg = self.emit_scalar_rvalue(found_expression, ctx);
972 converted_regs.push(materialized_arg);
973 }
974
975 self.emit_intrinsic_call_int(&dest_reg, intrinsic_fn, &converted_regs, node);
976
977 if let Some(temp_reg) = temp_reg {
978 if target_destination.is_register() {
979 self.builder.add_mov_reg(
981 target_destination.register().unwrap(),
982 &temp_reg,
983 node,
984 "copy intrinsic result from temp to target register",
985 );
986 } else {
987 self.emit_store_scalar_to_memory_offset_instruction(
989 target_destination.grab_memory_location(),
990 &temp_reg,
991 node,
992 "put the low level intrinsic fixed (int) back to memory",
993 );
994 }
995 }
996 }
997
998 IntrinsicFunction::VecPush
999 | IntrinsicFunction::VecPop
1000 | IntrinsicFunction::VecRemoveIndex
1001 | IntrinsicFunction::VecRemoveIndexGetValue
1002 | IntrinsicFunction::VecRemoveFirstIndexGetValue
1003 | IntrinsicFunction::VecClear
1004 | IntrinsicFunction::VecSlice
1005 | IntrinsicFunction::VecSwap
1006 | IntrinsicFunction::VecInsert
1007 | IntrinsicFunction::VecFirst
1008 | IntrinsicFunction::VecGet
1009 | IntrinsicFunction::VecLast => {
1010 let vec_self_ptr_reg = PointerLocation {
1013 ptr_reg: self_reg.unwrap().clone(),
1014 };
1015 let converted_to_expressions: Vec<_> = arguments
1016 .iter()
1017 .map(|arg| {
1018 let ArgumentExpression::Expression(found_expression) = arg else {
1019 panic!("must be expression");
1020 };
1021 found_expression.clone()
1022 })
1023 .collect();
1024
1025 self.emit_intrinsic_call_vec(
1026 target_destination,
1027 intrinsic_fn,
1028 &vec_self_ptr_reg,
1029 &converted_to_expressions,
1030 node,
1031 ctx,
1032 );
1033 }
1034
1035 IntrinsicFunction::GridGet
1036 | IntrinsicFunction::GridSet
1037 | IntrinsicFunction::GridWidth
1038 | IntrinsicFunction::GridHeight => {
1039 let grid_self_ptr_reg = PointerLocation {
1042 ptr_reg: self_reg.unwrap().clone(),
1043 };
1044 let converted_to_expressions: Vec<_> = arguments
1045 .iter()
1046 .map(|arg| {
1047 let ArgumentExpression::Expression(found_expression) = arg else {
1048 panic!("must be expression");
1049 };
1050 found_expression.clone()
1051 })
1052 .collect();
1053 self.emit_intrinsic_grid(
1054 target_destination,
1055 intrinsic_fn,
1056 &grid_self_ptr_reg,
1057 &converted_to_expressions,
1058 node,
1059 comment,
1060 ctx,
1061 );
1062 }
1063
1064 IntrinsicFunction::SparseIsAlive
1065 | IntrinsicFunction::SparseRemove
1066 | IntrinsicFunction::SparseAdd => {
1067 let grid_self_ptr_reg = PointerLocation {
1070 ptr_reg: self_reg.unwrap().clone(),
1071 };
1072 let converted_to_expressions: Vec<_> = arguments
1073 .iter()
1074 .map(|arg| {
1075 let ArgumentExpression::Expression(found_expression) = arg else {
1076 panic!("must be expression");
1077 };
1078 found_expression.clone()
1079 })
1080 .collect();
1081 self.emit_intrinsic_sparse(
1082 target_destination,
1083 intrinsic_fn,
1084 &grid_self_ptr_reg,
1085 &converted_to_expressions,
1086 node,
1087 comment,
1088 ctx,
1089 );
1090 }
1091
1092 IntrinsicFunction::TransformerFor
1093 | IntrinsicFunction::TransformerWhile
1094 | IntrinsicFunction::TransformerFindMap
1095 | IntrinsicFunction::TransformerAny
1096 | IntrinsicFunction::TransformerAll
1097 | IntrinsicFunction::TransformerMap
1098 | IntrinsicFunction::TransformerFilter
1099 | IntrinsicFunction::TransformerFilterMap
1100 | IntrinsicFunction::TransformerFind
1101 | IntrinsicFunction::TransformerFold => {
1102 let collection_self_ptr_reg = PointerLocation {
1104 ptr_reg: self_reg.unwrap().clone(),
1105 };
1106
1107 let lambda_expression = &arguments[0];
1108
1109 let ArgumentExpression::Expression(expr) = lambda_expression else {
1111 panic!("err");
1112 };
1113
1114 let ExpressionKind::Lambda(lambda_variables, lambda_expr) = &expr.kind else {
1115 panic!("must have lambda for transformers");
1116 };
1117
1118 self.emit_intrinsic_transformer(
1119 target_destination,
1120 intrinsic_fn,
1121 &collection_self_ptr_reg,
1122 (lambda_variables.clone(), lambda_expr),
1123 node,
1124 ctx,
1125 );
1126 }
1127
1128 IntrinsicFunction::RuntimePanic => {
1129 self.builder
1130 .add_panic(self_reg.unwrap(), node, "intrinsic panic");
1131 }
1132
1133 IntrinsicFunction::RuntimeHalt => {
1134 self.builder.add_halt(node, "intrinsic halt");
1135 }
1136
1137 IntrinsicFunction::RuntimeStep => {
1138 self.builder.add_step(node, "intrinsic step");
1139 }
1140
1141 IntrinsicFunction::RangeInit => {
1142 let start_reg = self_reg.unwrap();
1143 let end_arg = &arguments[0];
1149 let ArgumentExpression::Expression(end_arg_expr) = end_arg else {
1150 panic!();
1151 };
1152 let end_reg = self.emit_scalar_rvalue(end_arg_expr, ctx);
1153
1154 let is_inclusive = &arguments[1];
1155 let ArgumentExpression::Expression(is_inclusive_expr) = is_inclusive else {
1156 panic!();
1157 };
1158 let is_inclusive_reg = self.emit_scalar_rvalue(is_inclusive_expr, ctx);
1159 let absolute_range_pointer = self.emit_compute_effective_address_to_register(
1160 target_destination,
1161 node,
1162 "create range target pointer",
1163 );
1164 self.builder.add_range_init(
1165 &absolute_range_pointer,
1166 start_reg,
1167 &end_reg,
1168 &is_inclusive_reg,
1169 node,
1170 "create a range",
1171 );
1172 }
1173
1174 IntrinsicFunction::CodepointToString => {
1176 if maybe_target.is_none() {
1177 eprintln!("problem");
1178 }
1179 self.builder.codepoint_to_string(
1180 maybe_target.unwrap(),
1181 self_reg.unwrap(),
1182 node,
1183 "char_to_string",
1184 );
1185 }
1186
1187 IntrinsicFunction::CodepointToInt => {
1188 if maybe_target.is_none() {
1189 eprintln!("problem");
1190 }
1191 self.builder.add_mov_reg(
1192 maybe_target.unwrap(),
1193 self_reg.unwrap(),
1194 node,
1195 "char_to_int",
1196 );
1197 }
1198
1199 IntrinsicFunction::ByteToString => {
1201 if maybe_target.is_none() {
1202 eprintln!("problem");
1203 }
1204 self.builder.byte_to_string(
1205 maybe_target.unwrap(),
1206 self_reg.unwrap(),
1207 node,
1208 "byte_to_string",
1209 );
1210 }
1211
1212 IntrinsicFunction::ByteToInt => {
1213 if maybe_target.is_none() {
1214 eprintln!("problem");
1215 }
1216 self.builder.add_mov_reg(
1219 maybe_target.unwrap(),
1220 self_reg.unwrap(),
1221 node,
1222 "byte_to_int",
1223 );
1224 }
1225
1226 IntrinsicFunction::BoolToString => {
1228 if maybe_target.is_none() {
1229 eprintln!("problem");
1230 }
1231 self.builder.bool_to_string(
1232 maybe_target.unwrap(),
1233 self_reg.unwrap(),
1234 node,
1235 "bool_to_string",
1236 );
1237 }
1238
1239 IntrinsicFunction::StringToString => {
1240 self.builder.string_to_string(
1241 maybe_target.unwrap(),
1242 self_reg.unwrap(),
1243 node,
1244 "string_to_string",
1245 );
1246 }
1247
1248 IntrinsicFunction::MapIsEmpty | IntrinsicFunction::VecIsEmpty => {
1250 let collection_pointer = PointerLocation {
1251 ptr_reg: self_reg.unwrap().clone(),
1252 };
1253 self.emit_collection_is_empty(
1254 maybe_target.unwrap().clone(),
1255 &collection_pointer,
1256 node,
1257 "vec empty",
1258 );
1259 }
1260
1261 IntrinsicFunction::StringLen
1262 | IntrinsicFunction::MapLen
1263 | IntrinsicFunction::VecLen => {
1264 let collection_pointer = PointerLocation {
1265 ptr_reg: self_reg.unwrap().clone(),
1266 };
1267 self.emit_collection_len(
1268 maybe_target.unwrap(),
1269 &collection_pointer,
1270 node,
1271 "get the collection element_count",
1272 );
1273 }
1274 IntrinsicFunction::MapCapacity | IntrinsicFunction::VecCapacity => {
1275 let collection_pointer = PointerLocation {
1276 ptr_reg: self_reg.unwrap().clone(),
1277 };
1278 self.emit_collection_capacity(
1279 maybe_target.unwrap(),
1280 &collection_pointer,
1281 node,
1282 "get the collection element_count",
1283 );
1284 }
1285
1286 IntrinsicFunction::MapRemove | IntrinsicFunction::MapHas => {
1287 let grid_self_ptr_reg = PointerLocation {
1290 ptr_reg: self_reg.unwrap().clone(),
1291 };
1292 let converted_to_expressions: Vec<_> = arguments
1293 .iter()
1294 .map(|arg| {
1295 let ArgumentExpression::Expression(found_expression) = arg else {
1296 panic!("must be expression");
1297 };
1298 found_expression.clone()
1299 })
1300 .collect();
1301 self.emit_intrinsic_map(
1302 target_destination,
1303 intrinsic_fn,
1304 &grid_self_ptr_reg,
1305 &converted_to_expressions,
1306 node,
1307 comment,
1308 ctx,
1309 );
1310 } }
1312 }
1313
1314 fn emit_intrinsic_map_remove(
1315 &mut self,
1316 map_header_reg: &PointerLocation,
1317 key_expression: &Expression,
1318 ctx: &Context,
1319 ) {
1320 let key_register =
1321 self.emit_aggregate_pointer_or_pointer_to_scalar_memory(key_expression, ctx);
1322
1323 self.builder
1324 .add_map_remove(map_header_reg, &key_register, &key_expression.node, "");
1325 }
1326
1327 fn emit_collection_capacity(
1328 &mut self,
1329 output_reg: &TypedRegister,
1330 collection_addr: &PointerLocation,
1331 node: &Node,
1332 comment: &str,
1333 ) {
1334 self.builder.add_ld16_from_pointer_with_offset_u16(
1335 output_reg,
1336 &collection_addr.ptr_reg,
1337 COLLECTION_CAPACITY_OFFSET,
1338 node,
1339 comment,
1340 );
1341 }
1342
1343 fn emit_collection_len(
1344 &mut self,
1345 output_reg: &TypedRegister,
1346 collection_addr: &PointerLocation,
1347 node: &Node,
1348 comment: &str,
1349 ) {
1350 self.builder.add_ld16_from_pointer_with_offset_u16(
1351 output_reg,
1352 &collection_addr.ptr_reg,
1353 COLLECTION_ELEMENT_COUNT_OFFSET,
1354 node,
1355 &format!("{comment} - collection element_count"),
1356 );
1357 }
1358
1359 fn emit_collection_is_empty(
1360 &mut self,
1361 output_reg: TypedRegister,
1362 collection_addr: &PointerLocation,
1363 node: &Node,
1364 _comment: &str,
1365 ) {
1366 self.builder.add_ld16_from_pointer_with_offset_u16(
1367 &output_reg,
1368 &collection_addr.ptr_reg,
1369 COLLECTION_ELEMENT_COUNT_OFFSET,
1370 node,
1371 "get the map length for testing if it is empty",
1372 );
1373 self.builder.add_meqz(
1374 &output_reg,
1375 &output_reg,
1376 node,
1377 "convert the map length to inverted bool",
1378 );
1379 }
1380}