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