swamp_vm_instr_build/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use source_map_node::Node;
6use swamp_vm_types::opcode::OpCode;
7use swamp_vm_types::types::{BasicTypeKind, TypedRegister};
8pub use swamp_vm_types::{
9    BinaryInstruction, FrameMemoryAddress, FrameMemoryRegion, FrameMemorySize,
10    HeapMemoryOffset, HeapMemoryRegion, InstructionPosition, InstructionPositionOffset,
11    MemoryOffset, MemorySize, Meta, PatchPosition, ZFlagPolarity, HEAP_PTR_ON_FRAME_SIZE,
12    RANGE_HEADER_SIZE, RANGE_ITERATOR_SIZE,
13};
14use swamp_vm_types::{
15    CountU16, HeapMemoryAddress, MemoryAlignment, MemoryLocation, PointerLocation,
16    ProgramCounterDelta,
17};
18
19/// Keeps track of all the instructions, and the corresponding meta information (comments and node).
20pub struct InstructionBuilderState {
21    pub instructions: Vec<BinaryInstruction>,
22    pub meta: Vec<Meta>,
23}
24
25#[must_use]
26pub const fn u16_to_u8_pair(v: u16) -> (u8, u8) {
27    let bytes = v.to_le_bytes();
28    (bytes[0], bytes[1])
29}
30
31#[must_use]
32pub const fn u32_to_bytes(a: u32) -> (u8, u8, u8, u8) {
33    let bytes = a.to_le_bytes();
34    (bytes[0], bytes[1], bytes[2], bytes[3])
35}
36
37impl Default for InstructionBuilderState {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42impl InstructionBuilderState {
43    #[must_use]
44    pub const fn new() -> Self {
45        Self {
46            instructions: Vec::new(),
47            meta: Vec::new(),
48        }
49    }
50
51    #[must_use]
52    pub const fn position(&self) -> InstructionPosition {
53        InstructionPosition(self.instructions.len() as u32)
54    }
55
56    pub fn patch_enter(
57        &mut self,
58        patch_position: PatchPosition,
59        frame_memory_size: FrameMemorySize,
60    ) {
61        const ENTER: u8 = OpCode::Enter as u8;
62
63        let instruction = &mut self.instructions[patch_position.0.0 as usize];
64
65        match instruction.opcode {
66            ENTER => {
67                let bytes = frame_memory_size.0.to_le_bytes();
68
69                instruction.operands[0] = bytes[0];
70                instruction.operands[1] = bytes[1];
71                instruction.operands[2] = bytes[2];
72                instruction.operands[3] = bytes[3];
73            }
74            _ => {
75                panic!("Attempted to patch a non-enter instruction at position {patch_position:?}")
76            }
77        }
78    }
79
80    /// # Panics
81    ///
82    pub fn patch_call(&mut self, patch_position: PatchPosition, ip: &InstructionPosition) {
83        const CALL: u8 = OpCode::Call as u8;
84
85        let instruction = &mut self.instructions[patch_position.0.0 as usize];
86
87        match instruction.opcode {
88            CALL => {
89                let bytes = u32_to_bytes(ip.0);
90
91                instruction.operands[0] = bytes.0;
92                instruction.operands[1] = bytes.1;
93                instruction.operands[2] = bytes.2;
94                instruction.operands[3] = bytes.3;
95            }
96            _ => panic!("Attempted to patch a non-call instruction at position {patch_position:?}"),
97        }
98    }
99
100    pub fn add_ret(&mut self, node: &Node, comment: &str) {
101        self.add_instruction(OpCode::Ret, &[], node, comment);
102    }
103
104    pub fn add_hlt(&mut self, node: &Node, comment: &str) {
105        self.add_instruction(OpCode::Hlt, &[], node, comment);
106    }
107
108    fn add_instruction(&mut self, op_code: OpCode, operands: &[u8], node: &Node, comment: &str) {
109        let mut array: [u8; 8] = [0; 8];
110        assert!(operands.len() <= 8);
111        let len = operands.len();
112        array[..len].copy_from_slice(&operands[..len]);
113        self.instructions.push(BinaryInstruction {
114            opcode: op_code as u8,
115            operands: array,
116        });
117        let meta = Meta {
118            comment: comment.to_string(),
119            node: node.clone(),
120        };
121
122        self.meta.push(meta);
123    }
124}
125
126pub struct InstructionBuilder<'a> {
127    pub state: &'a mut InstructionBuilderState,
128}
129
130impl<'a> InstructionBuilder<'a> {
131    #[must_use]
132    pub const fn new(state: &'a mut InstructionBuilderState) -> Self {
133        Self { state }
134    }
135}
136
137impl InstructionBuilder<'_> {
138    pub fn add_trap_if_lt(
139        &mut self,
140        a: &TypedRegister,
141        b: &TypedRegister,
142        node: &Node,
143        comment: &str,
144    ) {
145        self.state.add_instruction(
146            OpCode::TrapOnLessThan,
147            &[a.addressing(), b.addressing()],
148            node,
149            comment,
150        );
151    }
152
153    #[must_use]
154    pub const fn position(&self) -> InstructionPosition {
155        InstructionPosition(self.state.instructions.len() as u32)
156    }
157
158    pub fn add_enter_placeholder(&mut self, node: &Node, comment: &str) -> PatchPosition {
159        let patch_position = PatchPosition(self.position());
160        self.state
161            .add_instruction(OpCode::Enter, &[0, 0, 0, 0], node, comment);
162
163        patch_position
164    }
165
166    pub fn patch_enter(&mut self, size: FrameMemorySize, patch_position: PatchPosition) {
167        self.state.patch_enter(patch_position, size);
168    }
169
170    pub fn add_jmp_if_equal_placeholder(
171        &mut self,
172        test_reg: &TypedRegister,
173        node: &Node,
174        comment: &str,
175    ) -> PatchPosition {
176        let position = self.position();
177
178        self.state
179            .add_instruction(OpCode::BTrue, &[test_reg.addressing(), 0, 0], node, comment);
180
181        PatchPosition(position)
182    }
183
184    pub fn add_jmp_if_true_placeholder(
185        &mut self,
186        test_reg: &TypedRegister,
187        node: &Node,
188        comment: &str,
189    ) -> PatchPosition {
190        self.add_jmp_if_equal_placeholder(test_reg, node, comment)
191    }
192
193    pub fn add_jmp_if_not_equal_placeholder(
194        &mut self,
195        test_reg: &TypedRegister,
196        node: &Node,
197        comment: &str,
198    ) -> PatchPosition {
199        let position = self.position();
200
201        self.state.add_instruction(
202            OpCode::BFalse,
203            &[test_reg.addressing(), 0, 0],
204            node,
205            comment,
206        );
207
208        PatchPosition(position)
209    }
210
211    pub fn add_jmp_if_not_true_placeholder(
212        &mut self,
213        test_reg: &TypedRegister,
214        node: &Node,
215        comment: &str,
216    ) -> PatchPosition {
217        self.add_jmp_if_not_equal_placeholder(test_reg, node, comment)
218    }
219
220    pub fn add_jmp_if_not_equal_polarity_placeholder(
221        &mut self,
222        test_reg: &TypedRegister,
223        polarity: &ZFlagPolarity,
224        node: &Node,
225        comment: &str,
226    ) -> PatchPosition {
227        match polarity {
228            ZFlagPolarity::TrueWhenSet => {
229                self.add_jmp_if_not_equal_placeholder(test_reg, node, comment)
230            }
231            ZFlagPolarity::TrueWhenClear => {
232                self.add_jmp_if_equal_placeholder(test_reg, node, comment)
233            }
234        }
235    }
236
237    pub fn add_grid_init(
238        &mut self,
239        target: &TypedRegister,
240        element_size_reg: &TypedRegister,
241        width: u16,
242        height: u16,
243        node: &Node,
244        comment: &str,
245    ) {
246        let width_octets = Self::u16_to_octets(width);
247        let height_octets = Self::u16_to_octets(height);
248        self.state.add_instruction(
249            OpCode::GridInit,
250            &[
251                target.addressing(),
252                element_size_reg.addressing(),
253                width_octets.0,
254                width_octets.1,
255                height_octets.0,
256                height_octets.1,
257            ],
258            node,
259            comment,
260        );
261    }
262
263    pub fn add_grid_get_entry_addr(
264        &mut self,
265        target: &TypedRegister,
266        grid_self_addr_reg: &PointerLocation,
267        x_reg: &TypedRegister,
268        y_reg: &TypedRegister,
269        element_size: MemorySize,
270        node: &Node,
271        comment: &str,
272    ) {
273        let element_size_bytes = u32_to_bytes(element_size.0);
274        self.state.add_instruction(
275            OpCode::GridGetEntryAddr,
276            &[
277                target.addressing(),
278                grid_self_addr_reg.addressing(),
279                x_reg.addressing(),
280                y_reg.addressing(),
281                element_size_bytes.0,
282                element_size_bytes.1,
283                element_size_bytes.2,
284                element_size_bytes.3,
285            ],
286            node,
287            comment,
288        );
289    }
290
291    pub fn add_sparse_init(
292        &mut self,
293        target: &PointerLocation,
294        element_size: MemorySize,
295        capacity: u16,
296        node: &Node,
297        comment: &str,
298    ) {
299        let element_size_octets = u32_to_bytes(element_size.0);
300        let capacity_octets = Self::u16_to_octets(capacity);
301        self.state.add_instruction(
302            OpCode::SparseInit,
303            &[
304                target.addressing(),
305                element_size_octets.0,
306                element_size_octets.1,
307                element_size_octets.2,
308                element_size_octets.3,
309                capacity_octets.0,
310                capacity_octets.1,
311            ],
312            node,
313            comment,
314        );
315    }
316
317    pub fn add_sparse_add_give_entry_address(
318        &mut self,
319        target_entry_addr_reg: &TypedRegister,
320        dest_handle_reg: &TypedRegister,
321        sparse_addr_reg: &PointerLocation,
322        element_size: MemorySize,
323        node: &Node,
324        comment: &str,
325    ) {
326        let element_size_octets = u32_to_bytes(element_size.0);
327        self.state.add_instruction(
328            OpCode::SparseAddGiveEntryAddress,
329            &[
330                target_entry_addr_reg.addressing(),
331                dest_handle_reg.addressing(),
332                sparse_addr_reg.addressing(),
333                element_size_octets.0,
334                element_size_octets.1,
335                element_size_octets.2,
336                element_size_octets.3,
337            ],
338            node,
339            comment,
340        );
341    }
342
343    pub fn add_sparse_remove(
344        &mut self,
345        sparse_ptr_reg: &PointerLocation,
346        int_reg: &TypedRegister,
347        node: &Node,
348        comment: &str,
349    ) {
350        self.state.add_instruction(
351            OpCode::SparseRemove,
352            &[sparse_ptr_reg.addressing(), int_reg.addressing()],
353            node,
354            comment,
355        );
356    }
357
358    pub fn add_sparse_is_alive(
359        &mut self,
360        dest_bool_reg: &TypedRegister,
361        sparse_ptr_reg: &PointerLocation,
362        int_reg: &TypedRegister,
363        node: &Node,
364        comment: &str,
365    ) {
366        self.state.add_instruction(
367            OpCode::SparseIsAlive,
368            &[
369                dest_bool_reg.addressing(),
370                sparse_ptr_reg.addressing(),
371                int_reg.addressing(),
372            ],
373            node,
374            comment,
375        );
376    }
377
378    pub fn add_sparse_get_entry_addr(
379        &mut self,
380        dest_entry_address_reg: &TypedRegister,
381        sparse_ptr_reg: &PointerLocation,
382        int_handle_reg: &TypedRegister,
383        element_size: MemorySize,
384        node: &Node,
385        comment: &str,
386    ) {
387        let element_size_bytes = u32_to_bytes(element_size.0);
388        self.state.add_instruction(
389            OpCode::SparseGetEntryAddr,
390            &[
391                dest_entry_address_reg.addressing(),
392                sparse_ptr_reg.addressing(),
393                int_handle_reg.addressing(),
394                element_size_bytes.0,
395                element_size_bytes.1,
396                element_size_bytes.2,
397                element_size_bytes.3,
398            ],
399            node,
400            comment,
401        );
402    }
403
404    pub fn add_vec_cmp(
405        &mut self,
406        dest_bool_reg: &TypedRegister,
407        first_ptr: &TypedRegister,
408        second_ptr: &TypedRegister,
409        node: &Node,
410        comment: &str,
411    ) {
412        self.state.add_instruction(
413            OpCode::VecCmp,
414            &[
415                dest_bool_reg.addressing(),
416                first_ptr.addressing(),
417                second_ptr.addressing(),
418            ],
419            node,
420            comment,
421        );
422    }
423
424    pub fn add_vec_swap(
425        &mut self,
426        vec_self_addr: &TypedRegister,
427        int_index_a: &TypedRegister,
428        int_index_b: &TypedRegister,
429        node: &Node,
430        comment: &str,
431    ) {
432        assert!(matches!(
433            vec_self_addr.ty().kind,
434            BasicTypeKind::DynamicLengthVecView(_)
435        ));
436        assert_eq!(int_index_a.size(), int_index_b.size());
437        self.state.add_instruction(
438            OpCode::VecSwap,
439            &[
440                vec_self_addr.addressing(),
441                int_index_a.addressing(),
442                int_index_b.addressing(),
443            ],
444            node,
445            comment,
446        );
447    }
448
449    pub fn add_vec_subscript(
450        &mut self,
451        target: &TypedRegister,
452        self_addr: &TypedRegister,
453        index: &TypedRegister,
454        element_size: MemorySize,
455        node: &Node,
456        comment: &str,
457    ) {
458        /* TODO: Bring this back // assert!(matches!(
459            self_addr.ty().kind,
460            BasicTypeKind::InternalVecPointer(_)
461        ));
462
463         */
464
465        let element_size_bytes = u32_to_bytes(element_size.0);
466        self.state.add_instruction(
467            OpCode::VecGet,
468            &[
469                target.addressing(),
470                self_addr.addressing(),
471                index.addressing(),
472                element_size_bytes.0,
473                element_size_bytes.1,
474                element_size_bytes.2,
475                element_size_bytes.3,
476            ],
477            node,
478            comment,
479        );
480    }
481
482
483    pub fn add_vec_push_addr(
484        &mut self,
485        target_reg: &TypedRegister,
486        vec_self_reg: &TypedRegister,
487        node: &Node,
488        comment: &str,
489    ) {
490        self.state.add_instruction(
491            OpCode::VecPushAddr,
492            &[target_reg.addressing(), vec_self_reg.addressing()],
493            node,
494            comment,
495        );
496    }
497
498    pub fn add_vec_pop(
499        &mut self,
500        target_addr: &TypedRegister,
501        self_addr: &TypedRegister,
502        element_size: MemorySize,
503        node: &Node,
504        comment: &str,
505    ) {
506        /* TODO: Bring back
507        assert!(matches!(
508            self_addr.ty().kind,
509            BasicTypeKind::DynamicLengthVecView(_)
510        ));
511
512         */
513
514        let element_size_bytes = u32_to_bytes(element_size.0);
515        self.state.add_instruction(
516            OpCode::VecPop,
517            &[
518                target_addr.addressing(),
519                self_addr.addressing(),
520                element_size_bytes.0,
521                element_size_bytes.1,
522                element_size_bytes.2,
523                element_size_bytes.3,
524            ],
525            node,
526            comment,
527        );
528    }
529
530    pub fn add_vec_remove_index(
531        &mut self,
532        self_addr: &TypedRegister,
533        element_item: &TypedRegister,
534        node: &Node,
535        comment: &str,
536    ) {
537        /* TODO: Bring back //
538        assert!(matches!(
539            self_addr.ty().kind,
540            BasicTypeKind::InternalVecPointer(_)
541        ));
542
543         */
544        self.state.add_instruction(
545            OpCode::VecRemoveIndex,
546            &[self_addr.addressing(), element_item.addressing()],
547            node,
548            comment,
549        );
550    }
551
552    pub fn add_vec_remove_index_get_value(
553        &mut self,
554        target_addr: &TypedRegister,
555        self_addr: &TypedRegister,
556        element_item: &TypedRegister,
557        node: &Node,
558        comment: &str,
559    ) {
560        assert!(matches!(
561            self_addr.ty().kind,
562            BasicTypeKind::DynamicLengthVecView(_)
563        ));
564        self.state.add_instruction(
565            OpCode::VecRemoveIndexGetValue,
566            &[
567                target_addr.addressing(),
568                self_addr.addressing(),
569                element_item.addressing(),
570            ],
571            node,
572            comment,
573        );
574    }
575
576    pub fn add_vec_iter_next_placeholder(
577        &mut self,
578        iterator_target: &TypedRegister,
579        closure_variable: &TypedRegister,
580        node: &Node,
581        comment: &str,
582    ) -> PatchPosition {
583        assert!(matches!(
584            iterator_target.ty().kind,
585            BasicTypeKind::InternalVecIterator
586        ));
587        let position = self.position();
588        self.state.add_instruction(
589            OpCode::VecIterNext,
590            &[
591                iterator_target.addressing(),
592                closure_variable.addressing(),
593                0,
594                0,
595            ],
596            node,
597            comment,
598        );
599        PatchPosition(position)
600    }
601
602    pub fn add_vec_iter_next_pair_placeholder(
603        &mut self,
604        iterator_target: &TypedRegister,
605        closure_variable_key: &TypedRegister,
606        closure_variable_value: &TypedRegister,
607        node: &Node,
608        comment: &str,
609    ) -> PatchPosition {
610        assert!(matches!(
611            iterator_target.ty().kind,
612            BasicTypeKind::InternalVecIterator
613        ));
614        let position = self.position();
615        self.state.add_instruction(
616            OpCode::VecIterNextPair,
617            &[
618                iterator_target.addressing(),
619                closure_variable_key.addressing(),
620                closure_variable_value.addressing(),
621                0,
622            ],
623            node,
624            comment,
625        );
626        PatchPosition(position)
627    }
628
629    pub fn add_string_iter_next_placeholder(
630        &mut self,
631        iterator_target: &TypedRegister,
632        closure_variable: &TypedRegister,
633        node: &Node,
634        comment: &str,
635    ) -> PatchPosition {
636        assert!(matches!(
637            iterator_target.ty().kind,
638            BasicTypeKind::InternalStringIterator
639        ));
640        let position = self.position();
641        self.state.add_instruction(
642            OpCode::StringIterNext,
643            &[
644                iterator_target.addressing(),
645                closure_variable.addressing(),
646                0,
647                0,
648            ],
649            node,
650            comment,
651        );
652        PatchPosition(position)
653    }
654
655    pub fn add_string_iter_next_pair_placeholder(
656        &mut self,
657        iterator_target: &TypedRegister,
658        closure_variable_key: &TypedRegister,
659        closure_variable_value: &TypedRegister,
660        node: &Node,
661        comment: &str,
662    ) -> PatchPosition {
663        /*
664        assert!(matches!(
665            iterator_target.ty().kind,
666            BasicTypeKind::InternalStringIterator
667        ));
668
669         */
670        let position = self.position();
671        self.state.add_instruction(
672            OpCode::StringIterNextPair,
673            &[
674                iterator_target.addressing(),
675                closure_variable_key.addressing(),
676                closure_variable_value.addressing(),
677                0,
678            ],
679            node,
680            comment,
681        );
682        PatchPosition(position)
683    }
684
685    pub fn add_eq_u8_immediate(
686        &mut self,
687        dest_bool_reg: &TypedRegister,
688        source_addr: &TypedRegister,
689        immediate: u8,
690        node: &Node,
691        comment: &str,
692    ) {
693        // TODO: BRING THIS BACK // assert!(source_addr.size().0 >= 1);
694        self.state.add_instruction(
695            OpCode::Eq8Imm,
696            &[
697                dest_bool_reg.addressing(),
698                source_addr.addressing(),
699                immediate,
700            ],
701            node,
702            comment,
703        );
704    }
705
706    pub fn add_call_placeholder(&mut self, node: &Node, comment: &str) -> PatchPosition {
707        let position = self.position();
708        self.state
709            .add_instruction(OpCode::Call, &[0], node, comment);
710        PatchPosition(position)
711    }
712
713    pub fn add_jump_placeholder(&mut self, node: &Node, comment: &str) -> PatchPosition {
714        let position = self.position();
715
716        self.state
717            .add_instruction(OpCode::B, &[0, 0], node, comment);
718
719        PatchPosition(position)
720    }
721
722    pub fn add_lea_from_frame_region(
723        &mut self,
724        target_heap: &TypedRegister,
725        frame_address_to_convert: FrameMemoryRegion,
726        node: &Node,
727        comment: &str,
728    ) {
729        let frame_addr_bytes = u32_to_bytes(frame_address_to_convert.addr.0);
730        self.state.add_instruction(
731            OpCode::LdPtrFromEffectiveFrameAddress,
732            &[
733                target_heap.addressing(),
734                frame_addr_bytes.0,
735                frame_addr_bytes.1,
736                frame_addr_bytes.2,
737                frame_addr_bytes.3,
738            ],
739            node,
740            &format!("{comment} region: {frame_address_to_convert}"),
741        );
742    }
743
744    pub fn add_ld_contiguous_regs_from_frame(
745        &mut self,
746        target_reg: u8,
747        stored_in_frame: FrameMemoryRegion,
748        count: u8,
749        node: &Node,
750        comment: &str,
751    ) {
752        let address_bytes = stored_in_frame.addr.0.to_le_bytes();
753        self.state.add_instruction(
754            OpCode::LdRegFromFrameRange,
755            &[
756                target_reg,
757                address_bytes[0],
758                address_bytes[1],
759                address_bytes[2],
760                address_bytes[3],
761                count,
762            ],
763            node,
764            comment,
765        );
766    }
767
768    pub fn add_ld_masked_regs_from_frame(
769        &mut self,
770        register_mask: u8,
771        stored_in_frame: FrameMemoryRegion,
772        node: &Node,
773        comment: &str,
774    ) {
775        let address_bytes = stored_in_frame.addr.0.to_le_bytes();
776        self.state.add_instruction(
777            OpCode::LdRegFromFrameUsingMask,
778            &[
779                register_mask,
780                address_bytes[0],
781                address_bytes[1],
782                address_bytes[2],
783                address_bytes[3],
784            ],
785            node,
786            comment,
787        );
788    }
789
790    pub fn add_st_contiguous_regs_to_frame(
791        &mut self,
792        frame_mem: FrameMemoryRegion,
793        source_reg: u8,
794        count: u8,
795        node: &Node,
796        comment: &str,
797    ) {
798        let address_bytes = frame_mem.addr.0.to_le_bytes();
799        self.state.add_instruction(
800            OpCode::StRegToFrame,
801            &[
802                address_bytes[0],
803                address_bytes[1],
804                address_bytes[2],
805                address_bytes[3],
806                source_reg,
807                count,
808            ],
809            node,
810            comment,
811        );
812    }
813
814    pub fn add_st_masked_regs_to_frame(
815        &mut self,
816        start_frame_mem: FrameMemoryAddress,
817        source_reg_mask: u8,
818        node: &Node,
819        comment: &str,
820    ) {
821        let address_bytes = start_frame_mem.0.to_le_bytes();
822        self.state.add_instruction(
823            OpCode::StRegToFrameUsingMask,
824            &[
825                address_bytes[0],
826                address_bytes[1],
827                address_bytes[2],
828                address_bytes[3],
829                source_reg_mask,
830            ],
831            node,
832            comment,
833        );
834    }
835
836    pub fn add_block_copy_with_immediate_size(
837        &mut self,
838        target_base_ptr_reg: &PointerLocation,
839        source_base_ptr_reg: &PointerLocation,
840        memory_size: MemorySize,
841        node: &Node,
842        comment: &str,
843    ) {
844        let size_bytes = u32_to_bytes(memory_size.0);
845
846        self.state.add_instruction(
847            OpCode::BlockCopy,
848            &[
849                target_base_ptr_reg.addressing(),
850                source_base_ptr_reg.addressing(),
851                size_bytes.0,
852                size_bytes.1,
853                size_bytes.2,
854                size_bytes.3,
855            ],
856            node,
857            comment,
858        );
859    }
860
861    pub fn add_panic(&mut self, str: &TypedRegister, node: &Node, comment: &str) {
862        self.state
863            .add_instruction(OpCode::Panic, &[str.addressing()], node, comment);
864    }
865
866    pub fn add_halt(&mut self, node: &Node, comment: &str) {
867        self.state.add_instruction(OpCode::Hlt, &[], node, comment);
868    }
869
870    pub fn add_step(&mut self, node: &Node, comment: &str) {
871        self.state.add_instruction(OpCode::Step, &[], node, comment);
872    }
873    pub fn add_call(&mut self, function_ip: &InstructionPosition, node: &Node, comment: &str) {
874        let ip_bytes = function_ip.0.to_le_bytes();
875        self.state.add_instruction(
876            OpCode::Call,
877            &[ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3]],
878            node,
879            comment,
880        );
881    }
882
883    pub fn add_host_call(
884        &mut self,
885        host_function_id: u16,
886        arguments_count: u8,
887        node: &Node,
888        comment: &str,
889    ) {
890        let ip_bytes = Self::u16_to_octets(host_function_id);
891        self.state.add_instruction(
892            OpCode::HostCall,
893            &[ip_bytes.0, ip_bytes.1, arguments_count],
894            node,
895            comment,
896        );
897    }
898
899    /// # Panics
900    ///
901    pub fn patch_jump(
902        &mut self,
903        patch_position: PatchPosition,
904        target_position: &InstructionPosition,
905    ) {
906        const JMP_IF_NOT: u8 = OpCode::BTrue as u8;
907        const JMP_IF: u8 = OpCode::BFalse as u8;
908        const JMP: u8 = OpCode::B as u8;
909
910        const VEC_ITER_NEXT: u8 = OpCode::VecIterNext as u8;
911        const VEC_ITER_NEXT_PAIR: u8 = OpCode::VecIterNextPair as u8;
912        const MAP_ITER_NEXT: u8 = OpCode::MapIterNext as u8;
913        const MAP_ITER_NEXT_PAIR: u8 = OpCode::MapIterNextPair as u8;
914
915        const SPARSE_ITER_NEXT: u8 = OpCode::SparseIterNext as u8;
916        const SPARSE_ITER_NEXT_PAIR: u8 = OpCode::SparseIterNextPair as u8;
917
918        const STRING_ITER_NEXT: u8 = OpCode::StringIterNext as u8;
919        const STRING_ITER_NEXT_PAIR: u8 = OpCode::StringIterNextPair as u8;
920
921        const RANGE_ITER_NEXT: u8 = OpCode::RangeIterNext as u8;
922
923        //const UNWRAP_JMP_NONE: u8 = OpCode::UnwrapJmpNone as u8;
924        //const UNWRAP_JMP_SOME: u8 = OpCode::UnwrapJmpSome as u8;
925
926        let instruction = &mut self.state.instructions[patch_position.0.0 as usize];
927        let effective_pc_address = patch_position.0 + ProgramCounterDelta(1); // when running, the PC has already advanced one step
928        let delta = *target_position - effective_pc_address;
929        let raw = delta.0;
930        let delta_bytes = raw.to_le_bytes();
931
932        match instruction.opcode {
933            JMP_IF_NOT | JMP_IF => {
934                instruction.operands[1] = delta_bytes[0];
935                instruction.operands[2] = delta_bytes[1];
936            }
937
938            JMP => {
939                instruction.operands[0] = delta_bytes[0];
940                instruction.operands[1] = delta_bytes[1];
941            }
942
943            SPARSE_ITER_NEXT | VEC_ITER_NEXT | STRING_ITER_NEXT | MAP_ITER_NEXT
944            | RANGE_ITER_NEXT => {
945                instruction.operands[2] = delta_bytes[0];
946                instruction.operands[3] = delta_bytes[1];
947            }
948
949            SPARSE_ITER_NEXT_PAIR
950            | VEC_ITER_NEXT_PAIR
951            | STRING_ITER_NEXT_PAIR
952            | MAP_ITER_NEXT_PAIR => {
953                instruction.operands[3] = delta_bytes[0];
954                instruction.operands[4] = delta_bytes[1];
955            }
956
957            _ => panic!("Attempted to patch a non-jump instruction at position {patch_position:?}"),
958        }
959    }
960
961    // It takes ownership of the patch position
962    pub fn patch_jump_here(&mut self, jump_position: PatchPosition) {
963        self.patch_jump(jump_position, &self.position());
964    }
965
966    pub fn add_jmp(&mut self, pc: InstructionPosition, node: &Node, comment: &str) {
967        let delta_bytes = self.calculate_pc_delta_bytes(pc);
968        self.state
969            .add_instruction(OpCode::B, &[delta_bytes[0], delta_bytes[1]], node, comment);
970    }
971
972    const fn calculate_pc_delta(
973        &self,
974        target_instruction: InstructionPosition,
975    ) -> ProgramCounterDelta {
976        ProgramCounterDelta(
977            ((target_instruction.0 as i32) - ((self.position().0 + 1) as i32)) as i16,
978        )
979    }
980    const fn calculate_pc_delta_bytes(&self, pc: InstructionPosition) -> [u8; 2] {
981        let delta = self.calculate_pc_delta(pc);
982
983        delta.0.to_le_bytes()
984    }
985
986    pub fn add_frame_memory_clear(
987        &mut self,
988        frame_region: FrameMemoryRegion,
989        node: &Node,
990        comment: &str,
991    ) {
992        let addr_bytes = u32_to_bytes(frame_region.addr.0);
993        let size_bytes = u32_to_bytes(frame_region.size.0);
994        self.state.add_instruction(
995            OpCode::FrameMemClr,
996            &[
997                addr_bytes.0,
998                addr_bytes.1,
999                addr_bytes.2,
1000                addr_bytes.3,
1001                size_bytes.0,
1002                size_bytes.1,
1003                size_bytes.2,
1004                size_bytes.3,
1005            ],
1006            node,
1007            comment,
1008        );
1009    }
1010
1011    // Slices
1012
1013    pub fn add_map_iter_init(
1014        &mut self,
1015        iterator_target: &TypedRegister,
1016        pointer_to_map_header: &TypedRegister,
1017        node: &Node,
1018        comment: &str,
1019    ) {
1020        self.state.add_instruction(
1021            OpCode::MapIterInit,
1022            &[
1023                iterator_target.addressing(),
1024                pointer_to_map_header.addressing(),
1025            ],
1026            node,
1027            comment,
1028        );
1029    }
1030
1031    pub fn add_map_iter_next_placeholder(
1032        &mut self,
1033        iterator_target: &TypedRegister,
1034        closure_variable: &TypedRegister,
1035        node: &Node,
1036        comment: &str,
1037    ) -> PatchPosition {
1038        let position = self.position();
1039        self.state.add_instruction(
1040            OpCode::MapIterNext,
1041            &[
1042                iterator_target.addressing(),
1043                closure_variable.addressing(),
1044                0,
1045            ],
1046            node,
1047            comment,
1048        );
1049        PatchPosition(position)
1050    }
1051
1052    pub fn add_map_iter_next_pair_placeholder(
1053        &mut self,
1054        iterator_target: &TypedRegister,
1055        closure_variable: &TypedRegister,
1056        closure_variable_b: &TypedRegister,
1057        node: &Node,
1058        comment: &str,
1059    ) -> PatchPosition {
1060        let position = self.position();
1061        self.state.add_instruction(
1062            OpCode::MapIterNextPair,
1063            &[
1064                iterator_target.addressing(),
1065                closure_variable.addressing(),
1066                closure_variable_b.addressing(),
1067                0,
1068            ],
1069            node,
1070            comment,
1071        );
1072        PatchPosition(position)
1073    }
1074
1075    pub fn add_range_init(
1076        &mut self,
1077        target_range_iterator: &TypedRegister,
1078        min_reg: &TypedRegister,
1079        max_reg: &TypedRegister,
1080        is_inclusive_reg: &TypedRegister,
1081        node: &Node,
1082        comment: &str,
1083    ) {
1084        self.state.add_instruction(
1085            OpCode::RangeInit,
1086            &[
1087                target_range_iterator.addressing(),
1088                min_reg.addressing(),
1089                max_reg.addressing(),
1090                is_inclusive_reg.addressing(),
1091            ],
1092            node,
1093            comment,
1094        );
1095    }
1096
1097    pub fn add_range_iter_next_placeholder(
1098        &mut self,
1099        iterator_target: &TypedRegister,
1100        closure_variable: &TypedRegister,
1101        node: &Node,
1102
1103        comment: &str,
1104    ) -> PatchPosition {
1105        let position = self.position();
1106        self.state.add_instruction(
1107            OpCode::RangeIterNext,
1108            &[
1109                iterator_target.addressing(),
1110                closure_variable.addressing(),
1111                0,
1112                0,
1113            ],
1114            node,
1115            comment,
1116        );
1117        PatchPosition(position)
1118    }
1119
1120    pub fn add_string_append(
1121        &mut self,
1122        dst_offset: &TypedRegister,
1123        lhs_offset: &TypedRegister,
1124        rhs_offset: &TypedRegister,
1125        node: &Node,
1126        comment: &str,
1127    ) {
1128        self.state.add_instruction(
1129            OpCode::StringAppend,
1130            &[
1131                dst_offset.addressing(),
1132                lhs_offset.addressing(),
1133                rhs_offset.addressing(),
1134            ],
1135            node,
1136            comment,
1137        );
1138    }
1139
1140    pub fn add_string_cmp(
1141        &mut self,
1142        dest_bool_reg: &TypedRegister,
1143        a: &TypedRegister,
1144        b: &TypedRegister,
1145        node: &Node,
1146        comment: &str,
1147    ) {
1148        self.state.add_instruction(
1149            OpCode::StringCmp,
1150            &[dest_bool_reg.addressing(), a.addressing(), b.addressing()],
1151            node,
1152            comment,
1153        );
1154    }
1155
1156    pub fn add_fixed_capacity_array_init_fill_capacity_and_len(
1157        &mut self,
1158        target_vec_to_init: &PointerLocation,
1159        capacity: u16,
1160        element_size: &MemorySize,
1161        node: &Node,
1162        comment: &str,
1163    ) {
1164        //debug_assert!(len > 0);
1165        debug_assert!(capacity > 0);
1166
1167        let capacity_bytes = u16_to_u8_pair(capacity);
1168        let element_bytes = u32_to_bytes(element_size.0);
1169
1170        self.state.add_instruction(
1171            OpCode::ArrayInitWithLenAndCapacity,
1172            &[
1173                target_vec_to_init.ptr_reg.addressing(),
1174                capacity_bytes.0,
1175                capacity_bytes.1,
1176                element_bytes.0,
1177                element_bytes.1,
1178                element_bytes.2,
1179                element_bytes.3,
1180            ],
1181            node,
1182            comment,
1183        );
1184    }
1185
1186    pub fn add_map_init_set_capacity(
1187        &mut self,
1188        target_map_to_init: &PointerLocation,
1189        logical_limit: CountU16,
1190        key_size_reg: &TypedRegister,
1191        key_alignment: MemoryAlignment,
1192        value_size_reg: &TypedRegister,
1193        value_alignment: MemoryAlignment,
1194        node: &Node,
1195        comment: &str,
1196    ) {
1197        debug_assert!(logical_limit.0 > 0);
1198
1199        let logical_limit_bytes = u16_to_u8_pair(logical_limit.0);
1200
1201        let key_alignment_usize: usize = key_alignment.into();
1202        let value_alignment_usize: usize = value_alignment.into();
1203
1204        //let value_size_bytes = u16_to_u8_pair(value_size.0);
1205        self.state.add_instruction(
1206            OpCode::MapInitWithCapacityAndKeyAndTupleSizeAddr,
1207            &[
1208                target_map_to_init.ptr_reg.addressing(),
1209                logical_limit_bytes.0,
1210                logical_limit_bytes.1,
1211                key_size_reg.addressing(),
1212                key_alignment_usize as u8,
1213                value_size_reg.addressing(),
1214                value_alignment_usize as u8,
1215            ],
1216            node,
1217            comment,
1218        );
1219    }
1220
1221    pub fn add_map_overwrite(
1222        &mut self,
1223        destination_map: &PointerLocation,
1224        source_map: &PointerLocation,
1225        node: &Node,
1226        comment: &str,
1227    ) {
1228        self.state.add_instruction(
1229            OpCode::MapOverwrite,
1230            &[destination_map.addressing(), source_map.addressing()],
1231            node,
1232            comment,
1233        );
1234    }
1235
1236    pub fn add_range_iter_init(
1237        &mut self,
1238        iterator_target: &TypedRegister,
1239        range_source_header: &TypedRegister,
1240        node: &Node,
1241        comment: &str,
1242    ) {
1243        // TODO: Bring this back // assert_eq!(iterator_target.size(), RANGE_ITERATOR_SIZE);
1244        // TODO: Bring this back // assert_eq!(range_source_header.size(), RANGE_HEADER_SIZE);
1245
1246        self.state.add_instruction(
1247            OpCode::RangeIterInit,
1248            &[
1249                iterator_target.addressing(),
1250                range_source_header.addressing(),
1251            ],
1252            node,
1253            comment,
1254        );
1255    }
1256
1257    pub fn add_vec_copy(
1258        &mut self,
1259        target_vec: &PointerLocation,
1260        source_vec: &PointerLocation,
1261        node: &Node,
1262        comment: &str,
1263    ) {
1264        self.state.add_instruction(
1265            OpCode::VecCopy,
1266            &[
1267                target_vec.ptr_reg.addressing(),
1268                source_vec.ptr_reg.addressing(),
1269            ],
1270            node,
1271            comment,
1272        );
1273    }
1274
1275    pub fn add_vec_copy_range(
1276        &mut self,
1277        target_vec: &PointerLocation,
1278        source_vec: &PointerLocation,
1279        range_header: &TypedRegister,
1280        node: &Node,
1281        comment: &str,
1282    ) {
1283        self.state.add_instruction(
1284            OpCode::VecCopyRange,
1285            &[
1286                target_vec.addressing(),
1287                source_vec.addressing(),
1288                range_header.addressing(),
1289            ],
1290            node,
1291            comment,
1292        );
1293    }
1294
1295    pub fn add_vec_init_set_capacity(
1296        &mut self,
1297        target_vec_to_init: &PointerLocation,
1298        capacity: CountU16,
1299        element_size: &MemorySize,
1300        node: &Node,
1301        comment: &str,
1302    ) {
1303        //debug_assert!(len > 0);
1304        debug_assert!(capacity.0 > 0);
1305
1306        let capacity_bytes = u16_to_u8_pair(capacity.0);
1307        let element_bytes = u32_to_bytes(element_size.0);
1308        self.state.add_instruction(
1309            OpCode::VecInit,
1310            &[
1311                target_vec_to_init.ptr_reg.addressing(),
1312                capacity_bytes.0,
1313                capacity_bytes.1,
1314                element_bytes.0,
1315                element_bytes.1,
1316                element_bytes.2,
1317                element_bytes.3,
1318            ],
1319            node,
1320            comment,
1321        );
1322    }
1323
1324    pub fn add_vec_iter_init(
1325        &mut self,
1326        iterator_target: &TypedRegister,
1327        pointer_to_vec_header: &TypedRegister,
1328        node: &Node,
1329        comment: &str,
1330    ) {
1331        self.state.add_instruction(
1332            OpCode::VecIterInit,
1333            &[
1334                iterator_target.addressing(),
1335                pointer_to_vec_header.addressing(),
1336            ],
1337            node,
1338            comment,
1339        );
1340    }
1341
1342    pub fn add_vec_iter_next(
1343        &mut self,
1344        iterator_target: &TypedRegister,
1345        closure_variable: &TypedRegister,
1346        instruction_position: InstructionPosition,
1347        node: &Node,
1348        comment: &str,
1349    ) {
1350        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1351        self.state.add_instruction(
1352            OpCode::VecIterNext,
1353            &[
1354                iterator_target.addressing(),
1355                closure_variable.addressing(),
1356                bytes[0],
1357                bytes[1],
1358            ],
1359            node,
1360            comment,
1361        );
1362    }
1363
1364    pub fn add_vec_iter_next_pair(
1365        &mut self,
1366        iterator_target: &TypedRegister,
1367        closure_variable_key: &TypedRegister,
1368        closure_variable_value: &TypedRegister,
1369        instruction_position: InstructionPosition,
1370        node: &Node,
1371        comment: &str,
1372    ) {
1373        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1374        self.state.add_instruction(
1375            OpCode::VecIterNextPair,
1376            &[
1377                iterator_target.addressing(),
1378                closure_variable_key.addressing(),
1379                closure_variable_value.addressing(),
1380                bytes[0],
1381                bytes[1],
1382            ],
1383            node,
1384            comment,
1385        );
1386    }
1387
1388    pub fn add_string_iter_init(
1389        &mut self,
1390        iterator_target: &TypedRegister,
1391        pointer_to_vec_header: &TypedRegister,
1392        element_size: MemorySize,
1393        node: &Node,
1394        comment: &str,
1395    ) {
1396        let element_size_bytes = u32_to_bytes(element_size.0);
1397        self.state.add_instruction(
1398            OpCode::StringIterInit,
1399            &[
1400                iterator_target.addressing(),
1401                pointer_to_vec_header.addressing(),
1402                element_size_bytes.0,
1403                element_size_bytes.1,
1404                element_size_bytes.2,
1405                element_size_bytes.3,
1406            ],
1407            node,
1408            comment,
1409        );
1410    }
1411
1412    pub fn add_string_iter_next(
1413        &mut self,
1414        iterator_target: &TypedRegister,
1415        closure_variable: &TypedRegister,
1416        instruction_position: InstructionPosition,
1417        node: &Node,
1418        comment: &str,
1419    ) {
1420        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1421        self.state.add_instruction(
1422            OpCode::StringIterNext,
1423            &[
1424                iterator_target.addressing(),
1425                closure_variable.addressing(),
1426                bytes[0],
1427                bytes[1],
1428            ],
1429            node,
1430            comment,
1431        );
1432    }
1433
1434    pub fn add_string_iter_next_pair(
1435        &mut self,
1436        iterator_target: &TypedRegister,
1437        closure_variable_key: &TypedRegister,
1438        closure_variable_value: &TypedRegister,
1439        instruction_position: InstructionPosition,
1440        node: &Node,
1441        comment: &str,
1442    ) {
1443        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1444        self.state.add_instruction(
1445            OpCode::StringIterNextPair,
1446            &[
1447                iterator_target.addressing(),
1448                closure_variable_key.addressing(),
1449                closure_variable_value.addressing(),
1450                bytes[0],
1451                bytes[1],
1452            ],
1453            node,
1454            comment,
1455        );
1456    }
1457    fn convert_to_lower_and_upper(data: u32) -> (u8, u8, u8, u8) {
1458        data.to_le_bytes().into()
1459    }
1460
1461    fn u16_to_octets(data: u16) -> (u8, u8) {
1462        data.to_le_bytes().into()
1463    }
1464
1465    pub fn add_st32_using_ptr_with_offset(
1466        &mut self,
1467        scalar_lvalue_location: &MemoryLocation,
1468        u32_reg: &TypedRegister,
1469        node: &Node,
1470        comment: &str,
1471    ) {
1472        //assert_eq!(u32_reg.ty().underlying().total_size.0, 4);
1473        let offset_bytes = u32_to_bytes(scalar_lvalue_location.offset.0);
1474        self.state.add_instruction(
1475            OpCode::St32UsingPtrWithOffset,
1476            &[
1477                scalar_lvalue_location.base_ptr_reg.addressing(),
1478                offset_bytes.0,
1479                offset_bytes.1,
1480                offset_bytes.2,
1481                offset_bytes.3,
1482                u32_reg.index,
1483            ],
1484            node,
1485            comment,
1486        );
1487    }
1488
1489    pub fn add_st16_using_ptr_with_offset(
1490        &mut self,
1491        scalar_lvalue_location: &MemoryLocation,
1492        u16_reg: &TypedRegister,
1493        node: &Node,
1494        comment: &str,
1495    ) {
1496        //assert_eq!(u16_reg.ty().underlying().total_size.0, 2);
1497        let offset_bytes = u32_to_bytes(scalar_lvalue_location.offset.0);
1498        self.state.add_instruction(
1499            OpCode::St16UsingPtrWithOffset,
1500            &[
1501                scalar_lvalue_location.base_ptr_reg.addressing(),
1502                offset_bytes.0,
1503                offset_bytes.1,
1504                offset_bytes.2,
1505                offset_bytes.3,
1506                u16_reg.index,
1507            ],
1508            node,
1509            comment,
1510        );
1511    }
1512
1513    pub fn add_st8_using_ptr_with_offset(
1514        &mut self,
1515        scalar_lvalue_location: &MemoryLocation,
1516        u8_reg: &TypedRegister,
1517        node: &Node,
1518        comment: &str,
1519    ) {
1520        // TODO: Bring this back. // assert_eq!(u8_reg.ty().underlying().total_size.0, 1);
1521        let offset_bytes = u32_to_bytes(scalar_lvalue_location.offset.0);
1522        self.state.add_instruction(
1523            OpCode::St8UsingPtrWithOffset,
1524            &[
1525                scalar_lvalue_location.base_ptr_reg.addressing(),
1526                offset_bytes.0,
1527                offset_bytes.1,
1528                offset_bytes.2,
1529                offset_bytes.3,
1530                u8_reg.addressing(),
1531            ],
1532            node,
1533            comment,
1534        );
1535    }
1536
1537    pub fn add_mov_16_immediate_value(
1538        &mut self,
1539        dst_offset: &TypedRegister,
1540        value: u16,
1541        node: &Node,
1542        comment: &str,
1543    ) {
1544        let bytes = Self::u16_to_octets(value);
1545
1546        self.state.add_instruction(
1547            OpCode::Mov16FromImmediateValue,
1548            &[dst_offset.addressing(), bytes.0, bytes.1],
1549            node,
1550            comment,
1551        );
1552    }
1553
1554    pub fn add_mov_32_immediate_value(
1555        &mut self,
1556        dst_offset: &TypedRegister,
1557        value: u32,
1558        node: &Node,
1559        comment: &str,
1560    ) {
1561        let bytes = Self::convert_to_lower_and_upper(value);
1562
1563        self.state.add_instruction(
1564            OpCode::Mov32FromImmediateValue,
1565            &[dst_offset.addressing(), bytes.0, bytes.1, bytes.2, bytes.3],
1566            node,
1567            comment,
1568        );
1569    }
1570
1571    pub fn add_ld32_from_absolute_memory_address(
1572        &mut self,
1573        dst_reg: &TypedRegister,
1574        absolute_mem_addr: &HeapMemoryAddress,
1575        node: &Node,
1576        comment: &str,
1577    ) {
1578        let bytes = u32_to_bytes(absolute_mem_addr.0);
1579
1580        self.state.add_instruction(
1581            OpCode::Ld32FromAbsoluteAddress,
1582            &[dst_reg.addressing(), bytes.0, bytes.1, bytes.2, bytes.3],
1583            node,
1584            comment,
1585        );
1586    }
1587
1588    pub fn add_ld16_from_pointer_from_memory_location(
1589        &mut self,
1590        dst_reg: &TypedRegister,
1591        source_memory_location: &MemoryLocation,
1592        node: &Node,
1593        comment: &str,
1594    ) {
1595        self.add_ld16_from_pointer_with_offset_u16(
1596            dst_reg,
1597            &source_memory_location.base_ptr_reg,
1598            source_memory_location.offset,
1599            node,
1600            comment,
1601        );
1602    }
1603
1604    pub fn add_ld16_from_pointer_with_offset_u16(
1605        &mut self,
1606        dst_reg: &TypedRegister,
1607        base_ptr_reg: &TypedRegister,
1608        offset: MemoryOffset,
1609        node: &Node,
1610        comment: &str,
1611    ) {
1612        let offset_bytes = u32_to_bytes(offset.0);
1613
1614        self.state.add_instruction(
1615            OpCode::Ld16FromPointerWithOffset,
1616            &[
1617                dst_reg.addressing(),
1618                base_ptr_reg.addressing(),
1619                offset_bytes.0,
1620                offset_bytes.1,
1621                offset_bytes.2,
1622                offset_bytes.3,
1623            ],
1624            node,
1625            comment,
1626        );
1627    }
1628
1629    pub fn add_ld32_from_pointer_with_offset_u16(
1630        &mut self,
1631        dst_reg: &TypedRegister,
1632        base_ptr_reg: &TypedRegister,
1633        offset: MemoryOffset,
1634        node: &Node,
1635        comment: &str,
1636    ) {
1637        let offset_bytes = u32_to_bytes(offset.0);
1638
1639        self.state.add_instruction(
1640            OpCode::Ld32FromPointerWithOffset,
1641            &[
1642                dst_reg.addressing(),
1643                base_ptr_reg.addressing(),
1644                offset_bytes.0,
1645                offset_bytes.1,
1646                offset_bytes.2,
1647                offset_bytes.3,
1648            ],
1649            node,
1650            comment,
1651        );
1652    }
1653
1654    pub fn add_ld8_from_absolute_memory_address(
1655        &mut self,
1656        dst_reg: &TypedRegister,
1657        absolute_mem_addr: &HeapMemoryAddress,
1658        node: &Node,
1659        comment: &str,
1660    ) {
1661        let absolute_memory_addr = u32_to_bytes(absolute_mem_addr.0);
1662
1663        self.state.add_instruction(
1664            OpCode::Ld8FromAbsoluteAddress,
1665            &[
1666                dst_reg.addressing(),
1667                absolute_memory_addr.0,
1668                absolute_memory_addr.1,
1669                absolute_memory_addr.2,
1670                absolute_memory_addr.3,
1671            ],
1672            node,
1673            comment,
1674        );
1675    }
1676
1677    pub fn add_ld8_from_pointer_with_offset_u16(
1678        &mut self,
1679        dst_reg: &TypedRegister,
1680        base_ptr_reg: &TypedRegister,
1681        offset: MemoryOffset,
1682        node: &Node,
1683        comment: &str,
1684    ) {
1685        let offset_bytes = u32_to_bytes(offset.0);
1686
1687        self.state.add_instruction(
1688            OpCode::Ld8FromPointerWithOffset,
1689            &[
1690                dst_reg.addressing(),
1691                base_ptr_reg.addressing(),
1692                offset_bytes.0,
1693                offset_bytes.1,
1694                offset_bytes.2,
1695                offset_bytes.3,
1696            ],
1697            node,
1698            comment,
1699        );
1700    }
1701
1702    pub fn add_mov_reg(
1703        &mut self,
1704        dst_offset: &TypedRegister,
1705        src_offset: &TypedRegister,
1706        node: &Node,
1707        comment: &str,
1708    ) {
1709        if dst_offset.index == src_offset.index {
1710            return;
1711        }
1712        self.state.add_instruction(
1713            OpCode::MovReg,
1714            &[dst_offset.addressing(), src_offset.addressing()],
1715            node,
1716            comment,
1717        );
1718    }
1719
1720    pub fn add_mov8_immediate(
1721        &mut self,
1722        dst_offset: &TypedRegister,
1723        value: u8,
1724        node: &Node,
1725        comment: &str,
1726    ) {
1727        self.state.add_instruction(
1728            OpCode::Mov8FromImmediateValue,
1729            &[dst_offset.addressing(), value],
1730            node,
1731            comment,
1732        );
1733    }
1734
1735    pub fn add_add_u32(
1736        &mut self,
1737        dst_offset: &TypedRegister,
1738        lhs_offset: &TypedRegister,
1739        rhs_offset: &TypedRegister,
1740        node: &Node,
1741        comment: &str,
1742    ) {
1743        // TODO: Bring this back //assert!(dst_offset.ty().is_int());
1744        // TODO: Bring this back //assert!(lhs_offset.ty().is_int());
1745        // TODO: Bring this back //assert!(rhs_offset.ty().is_int());
1746        self.state.add_instruction(
1747            OpCode::AddU32,
1748            &[
1749                dst_offset.addressing(),
1750                lhs_offset.addressing(),
1751                rhs_offset.addressing(),
1752            ],
1753            node,
1754            comment,
1755        );
1756    }
1757
1758    pub fn add_add_u32_imm(
1759        &mut self,
1760        dst_offset: &TypedRegister,
1761        lhs_offset: &TypedRegister,
1762        rhs_immediate: u32,
1763        node: &Node,
1764        comment: &str,
1765    ) {
1766        // TODO: Bring this back //assert!(dst_offset.ty().is_int());
1767        // TODO: Bring this back //assert!(lhs_offset.ty().is_int());
1768        // TODO: Bring this back //assert!(rhs_offset.ty().is_int());
1769        let immediate_bytes = u32_to_bytes(rhs_immediate);
1770        self.state.add_instruction(
1771            OpCode::AddU32Imm,
1772            &[
1773                dst_offset.addressing(),
1774                lhs_offset.addressing(),
1775                immediate_bytes.0,
1776                immediate_bytes.1,
1777                immediate_bytes.2,
1778                immediate_bytes.3,
1779            ],
1780            node,
1781            comment,
1782        );
1783    }
1784
1785    pub fn add_mod_i32(
1786        &mut self,
1787        dst_offset: &TypedRegister,
1788        lhs_offset: &TypedRegister,
1789        rhs_offset: &TypedRegister,
1790        node: &Node,
1791        comment: &str,
1792    ) {
1793        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1794        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1795        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1796
1797        self.state.add_instruction(
1798            OpCode::ModI32,
1799            &[
1800                dst_offset.addressing(),
1801                lhs_offset.addressing(),
1802                rhs_offset.addressing(),
1803            ],
1804            node,
1805            comment,
1806        );
1807    }
1808
1809    pub fn add_div_i32(
1810        &mut self,
1811        dst_offset: &TypedRegister,
1812        lhs_offset: &TypedRegister,
1813        rhs_offset: &TypedRegister,
1814        node: &Node,
1815        comment: &str,
1816    ) {
1817        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1818        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1819        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1820        self.state.add_instruction(
1821            OpCode::DivI32,
1822            &[
1823                dst_offset.addressing(),
1824                lhs_offset.addressing(),
1825                rhs_offset.addressing(),
1826            ],
1827            node,
1828            comment,
1829        );
1830    }
1831
1832    pub fn add_sub_u32(
1833        &mut self,
1834        dst_offset: &TypedRegister,
1835        lhs_offset: &TypedRegister,
1836        rhs_offset: &TypedRegister,
1837        node: &Node,
1838        comment: &str,
1839    ) {
1840        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1841        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1842        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1843        self.state.add_instruction(
1844            OpCode::SubU32,
1845            &[
1846                dst_offset.addressing(),
1847                lhs_offset.addressing(),
1848                rhs_offset.addressing(),
1849            ],
1850            node,
1851            comment,
1852        );
1853    }
1854
1855    pub fn add_mul_i32(
1856        &mut self,
1857        dst_offset: &TypedRegister,
1858        lhs_offset: &TypedRegister,
1859        rhs_offset: &TypedRegister,
1860        node: &Node,
1861        comment: &str,
1862    ) {
1863        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1864        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1865        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1866        self.state.add_instruction(
1867            OpCode::MulU32,
1868            &[
1869                dst_offset.addressing(),
1870                lhs_offset.addressing(),
1871                rhs_offset.addressing(),
1872            ],
1873            node,
1874            comment,
1875        );
1876    }
1877
1878    pub fn add_neg_i32(
1879        &mut self,
1880        target: &TypedRegister,
1881        source: &TypedRegister,
1882        node: &Node,
1883        comment: &str,
1884    ) {
1885        // TODO: Bring this back //assert!(target.ty().is_int());
1886        // TODO: Bring this back //assert!(source.ty().is_int());
1887        self.state.add_instruction(
1888            OpCode::NegI32,
1889            &[target.addressing(), source.addressing()],
1890            node,
1891            comment,
1892        );
1893    }
1894
1895    pub fn add_sub_f32(
1896        &mut self,
1897        dst_offset: &TypedRegister,
1898        lhs_offset: &TypedRegister,
1899        rhs_offset: &TypedRegister,
1900        node: &Node,
1901        comment: &str,
1902    ) {
1903        // TODO: bring this back // assert!(dst_offset.ty().is_float());
1904        // TODO: bring this back //assert!(lhs_offset.ty().is_float());
1905        // TODO: bring this back //assert!(rhs_offset.ty().is_float());
1906        self.state.add_instruction(
1907            OpCode::SubU32,
1908            &[
1909                dst_offset.addressing(),
1910                lhs_offset.addressing(),
1911                rhs_offset.addressing(),
1912            ],
1913            node,
1914            comment,
1915        );
1916    }
1917    pub fn add_mul_f32(
1918        &mut self,
1919        dst_offset: &TypedRegister,
1920        lhs_offset: &TypedRegister,
1921        rhs_offset: &TypedRegister,
1922        node: &Node,
1923        comment: &str,
1924    ) {
1925        // TODO: bring this back //assert!(dst_offset.ty().is_float());
1926        // TODO: bring this back //assert!(lhs_offset.ty().is_float());
1927        // TODO: bring this back //assert!(rhs_offset.ty().is_float());
1928        self.state.add_instruction(
1929            OpCode::MulF32,
1930            &[
1931                dst_offset.addressing(),
1932                lhs_offset.addressing(),
1933                rhs_offset.addressing(),
1934            ],
1935            node,
1936            comment,
1937        );
1938    }
1939    pub fn add_div_f32(
1940        &mut self,
1941        dst_offset: &TypedRegister,
1942        lhs_offset: &TypedRegister,
1943        rhs_offset: &TypedRegister,
1944        node: &Node,
1945        comment: &str,
1946    ) {
1947        // TODO: Bring this back //assert!(dst_offset.ty().is_float());
1948        // TODO: Bring this back //assert!(lhs_offset.ty().is_float());
1949        // TODO: Bring this back //assert!(rhs_offset.ty().is_float());
1950        self.state.add_instruction(
1951            OpCode::DivF32,
1952            &[
1953                dst_offset.addressing(),
1954                lhs_offset.addressing(),
1955                rhs_offset.addressing(),
1956            ],
1957            node,
1958            comment,
1959        );
1960    }
1961
1962    pub fn add_add_f32(
1963        &mut self,
1964        dst_offset: &TypedRegister,
1965        lhs_offset: &TypedRegister,
1966        rhs_offset: &TypedRegister,
1967        node: &Node,
1968        comment: &str,
1969    ) {
1970        // TODO: bring this back //assert!(dst_offset.ty().is_float());
1971        // TODO: bring this back //assert!(lhs_offset.ty().is_float());
1972        // TODO: bring this back //assert!(rhs_offset.ty().is_float());
1973        self.state.add_instruction(
1974            OpCode::AddU32,
1975            &[
1976                dst_offset.addressing(),
1977                lhs_offset.addressing(),
1978                rhs_offset.addressing(),
1979            ],
1980            node,
1981            comment,
1982        );
1983    }
1984
1985    pub fn add_neg_f32(
1986        &mut self,
1987        target: &TypedRegister,
1988        source: &TypedRegister,
1989        node: &Node,
1990        comment: &str,
1991    ) {
1992        // TODO: Bring this back // assert!(target.ty().is_float());
1993        // TODO: Bring this back // assert!(source.ty().is_float());
1994        self.state.add_instruction(
1995            OpCode::NegI32,
1996            &[target.addressing(), source.addressing()],
1997            node,
1998            comment,
1999        );
2000    }
2001
2002    pub fn add_lt_i32(
2003        &mut self,
2004        dest_bool_reg: &TypedRegister,
2005        lhs_offset: &TypedRegister,
2006        rhs_offset: &TypedRegister,
2007        node: &Node,
2008        comment: &str,
2009    ) {
2010        // TODO: Bring Back //assert!(lhs_offset.ty().is_int());
2011        // TODO: Bring Back //assert!(rhs_offset.ty().is_int());
2012        self.state.add_instruction(
2013            OpCode::LtI32,
2014            &[
2015                dest_bool_reg.addressing(),
2016                lhs_offset.addressing(),
2017                rhs_offset.addressing(),
2018            ],
2019            node,
2020            comment,
2021        );
2022    }
2023
2024    pub fn add_lt_u32(
2025        &mut self,
2026        lhs_offset: &TypedRegister,
2027        rhs_offset: &TypedRegister,
2028        node: &Node,
2029        comment: &str,
2030    ) {
2031        // TODO: Bring Back //assert!(lhs_offset.ty().is_int());
2032        // TODO: Bring Back //assert!(rhs_offset.ty().is_int());
2033        self.state.add_instruction(
2034            OpCode::LtU32,
2035            &[lhs_offset.addressing(), rhs_offset.addressing()],
2036            node,
2037            comment,
2038        );
2039    }
2040
2041    pub fn add_le_i32(
2042        &mut self,
2043        dest_bool_reg: &TypedRegister,
2044        lhs_offset: &TypedRegister,
2045        rhs_offset: &TypedRegister,
2046        node: &Node,
2047        comment: &str,
2048    ) {
2049        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
2050        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
2051        self.state.add_instruction(
2052            OpCode::LeI32,
2053            &[
2054                dest_bool_reg.addressing(),
2055                lhs_offset.addressing(),
2056                rhs_offset.addressing(),
2057            ],
2058            node,
2059            comment,
2060        );
2061    }
2062
2063    pub fn add_gt_i32(
2064        &mut self,
2065        dest_bool_reg: &TypedRegister,
2066        lhs_offset: &TypedRegister,
2067        rhs_offset: &TypedRegister,
2068        node: &Node,
2069        comment: &str,
2070    ) {
2071        // TODO: Bring this back. //assert!(lhs_offset.ty().is_int());
2072        // TODO: Bring this back. //assert!(rhs_offset.ty().is_int());
2073        self.state.add_instruction(
2074            OpCode::GtI32,
2075            &[
2076                dest_bool_reg.addressing(),
2077                lhs_offset.addressing(),
2078                rhs_offset.addressing(),
2079            ],
2080            node,
2081            comment,
2082        );
2083    }
2084
2085    pub fn add_ge_i32(
2086        &mut self,
2087        dest_bool_reg: &TypedRegister,
2088        lhs_offset: &TypedRegister,
2089        rhs_offset: &TypedRegister,
2090        node: &Node,
2091        comment: &str,
2092    ) {
2093        // TODO: bring this back //assert!(lhs_offset.ty().is_int());
2094        // TODO: bring this back //assert!(rhs_offset.ty().is_int());
2095        self.state.add_instruction(
2096            OpCode::GeI32,
2097            &[
2098                dest_bool_reg.addressing(),
2099                lhs_offset.addressing(),
2100                rhs_offset.addressing(),
2101            ],
2102            node,
2103            comment,
2104        );
2105    }
2106
2107    pub fn add_ge_u32(
2108        &mut self,
2109        dest_bool_reg: &TypedRegister,
2110        lhs_offset: &TypedRegister,
2111        rhs_offset: &TypedRegister,
2112        node: &Node,
2113        comment: &str,
2114    ) {
2115        // TODO: bring this back //assert!(lhs_offset.ty().is_int());
2116        // TODO: bring this back //assert!(rhs_offset.ty().is_int());
2117        self.state.add_instruction(
2118            OpCode::GeU32,
2119            &[
2120                dest_bool_reg.addressing(),
2121                lhs_offset.addressing(),
2122                rhs_offset.addressing(),
2123            ],
2124            node,
2125            comment,
2126        );
2127    }
2128
2129    pub fn add_meqz(
2130        &mut self,
2131        dest_bool_reg: &TypedRegister,
2132        addr: &TypedRegister,
2133        node: &Node,
2134        comment: &str,
2135    ) {
2136        self.state.add_instruction(
2137            OpCode::MovEqualToZero,
2138            &[dest_bool_reg.addressing(), addr.addressing()],
2139            node,
2140            comment,
2141        );
2142    }
2143
2144    pub fn add_trap(&mut self, trap_code: u8, node: &Node, comment: &str) {
2145        self.state
2146            .add_instruction(OpCode::Trap, &[trap_code], node, comment);
2147    }
2148
2149    pub fn add_cmp_reg(
2150        &mut self,
2151        dest_bool_reg: &TypedRegister,
2152        source_a: &TypedRegister,
2153        source_b: &TypedRegister,
2154        node: &Node,
2155        comment: &str,
2156    ) {
2157        self.state.add_instruction(
2158            OpCode::CmpReg,
2159            &[
2160                dest_bool_reg.addressing(),
2161                source_a.addressing(),
2162                source_b.addressing(),
2163            ],
2164            node,
2165            comment,
2166        );
2167    }
2168
2169    pub fn add_block_cmp(
2170        &mut self,
2171        dest_bool_reg: &TypedRegister,
2172        first_ptr: &TypedRegister,
2173        second_ptr: &TypedRegister,
2174        size: MemorySize,
2175        node: &Node,
2176        comment: &str,
2177    ) {
2178        let block_size_bytes = u32_to_bytes(size.0);
2179        self.state.add_instruction(
2180            OpCode::CmpBlock,
2181            &[
2182                dest_bool_reg.addressing(),
2183                first_ptr.addressing(),
2184                second_ptr.addressing(),
2185                block_size_bytes.0,
2186                block_size_bytes.1,
2187                block_size_bytes.2,
2188                block_size_bytes.3,
2189            ],
2190            node,
2191            comment,
2192        );
2193    }
2194
2195    // Collection specific
2196
2197    pub fn add_map_has(
2198        &mut self,
2199        dest_reg: &TypedRegister,
2200        self_addr: &PointerLocation,
2201        key_addr: &TypedRegister,
2202        node: &Node,
2203        comment: &str,
2204    ) {
2205        matches!(
2206            self_addr.ptr_reg.ty().kind,
2207            BasicTypeKind::DynamicLengthMapView(_, _)
2208        );
2209        self.state.add_instruction(
2210            OpCode::MapHas,
2211            &[
2212                dest_reg.addressing(),
2213                self_addr.addressing(),
2214                key_addr.addressing(),
2215            ],
2216            node,
2217            comment,
2218        );
2219    }
2220
2221    pub fn add_map_remove(
2222        &mut self,
2223        self_addr: &PointerLocation,
2224        key_addr: &TypedRegister,
2225        node: &Node,
2226        comment: &str,
2227    ) {
2228        matches!(
2229            self_addr.ptr_reg.ty().kind,
2230            BasicTypeKind::DynamicLengthMapView(_, _)
2231        );
2232        self.state.add_instruction(
2233            OpCode::MapRemove,
2234            &[self_addr.addressing(), key_addr.addressing()],
2235            node,
2236            comment,
2237        );
2238    }
2239
2240    pub fn add_map_get_entry_location(
2241        &mut self,
2242        target_entry_addr: &TypedRegister,
2243        map_self_addr: &PointerLocation,
2244        key: &TypedRegister,
2245        node: &Node,
2246        comment: &str,
2247    ) {
2248        //TODO: Bring this back: //matches!(map_self_addr.ty().kind, BasicTypeKind::InternalMapPointer(_, _));
2249        self.state.add_instruction(
2250            OpCode::MapGetEntryLocation,
2251            &[
2252                target_entry_addr.addressing(),
2253                map_self_addr.addressing(),
2254                key.addressing(),
2255            ],
2256            node,
2257            comment,
2258        );
2259    }
2260
2261    pub fn add_map_get_or_reserve_entry_location(
2262        &mut self,
2263        target_entry_reg: &TypedRegister,
2264        map_self_addr: &PointerLocation,
2265        key: &TypedRegister,
2266        node: &Node,
2267        comment: &str,
2268    ) {
2269        self.state.add_instruction(
2270            OpCode::MapGetOrReserveEntryLocation,
2271            &[
2272                target_entry_reg.addressing(),
2273                map_self_addr.addressing(),
2274                key.addressing(),
2275            ],
2276            node,
2277            comment,
2278        );
2279    }
2280
2281    pub fn add_int_rnd(
2282        &mut self,
2283        dest: &TypedRegister,
2284        self_int: &TypedRegister,
2285        node: &Node,
2286        comment: &str,
2287    ) {
2288        assert!(dest.ty().is_int());
2289        assert!(self_int.ty().is_int());
2290        self.state.add_instruction(
2291            OpCode::IntToRnd,
2292            &[dest.addressing(), self_int.addressing()],
2293            node,
2294            comment,
2295        );
2296    }
2297
2298    pub fn add_int_min(
2299        &mut self,
2300        dest: &TypedRegister,
2301        self_int: &TypedRegister,
2302        other_int: &TypedRegister,
2303        node: &Node,
2304        comment: &str,
2305    ) {
2306        // TODO: Bring this back //assert!(dest.ty().is_int());
2307        // TODO: Bring this back //assert!(self_int.ty().is_int());
2308
2309        self.state.add_instruction(
2310            OpCode::IntMin,
2311            &[
2312                dest.addressing(),
2313                self_int.addressing(),
2314                other_int.addressing(),
2315            ],
2316            node,
2317            comment,
2318        );
2319    }
2320
2321    pub fn add_int_max(
2322        &mut self,
2323        dest: &TypedRegister,
2324        self_int: &TypedRegister,
2325        other_int: &TypedRegister,
2326        node: &Node,
2327        comment: &str,
2328    ) {
2329        // TODO: Bring this back //assert!(dest.ty().is_int());
2330        // TODO: Bring this back //assert!(self_int.ty().is_int());
2331
2332        self.state.add_instruction(
2333            OpCode::IntMax,
2334            &[
2335                dest.addressing(),
2336                self_int.addressing(),
2337                other_int.addressing(),
2338            ],
2339            node,
2340            comment,
2341        );
2342    }
2343
2344    pub fn add_int_clamp(
2345        &mut self,
2346        dest: &TypedRegister,
2347        self_int: &TypedRegister,
2348        min_int: &TypedRegister,
2349        max_int: &TypedRegister,
2350        node: &Node,
2351        comment: &str,
2352    ) {
2353        assert!(dest.ty().is_int());
2354        assert!(self_int.ty().is_int());
2355        assert!(min_int.ty().is_int());
2356        assert!(max_int.ty().is_int());
2357        self.state.add_instruction(
2358            OpCode::IntClamp,
2359            &[
2360                dest.addressing(),
2361                self_int.addressing(),
2362                min_int.addressing(),
2363                max_int.addressing(),
2364            ],
2365            node,
2366            comment,
2367        );
2368    }
2369
2370    pub fn add_int_abs(
2371        &mut self,
2372        dest: &TypedRegister,
2373        self_int: &TypedRegister,
2374        node: &Node,
2375        comment: &str,
2376    ) {
2377        // TODO: Bring this back //  assert!(dest.ty().is_int());
2378        // TODO: Bring this back //  assert!(self_int.ty().is_int());
2379        self.state.add_instruction(
2380            OpCode::IntAbs,
2381            &[dest.addressing(), self_int.addressing()],
2382            node,
2383            comment,
2384        );
2385    }
2386
2387    pub fn add_int_to_float(
2388        &mut self,
2389        dest: &TypedRegister,
2390        self_int: &TypedRegister,
2391        node: &Node,
2392        comment: &str,
2393    ) {
2394        // TODO: bring this back //assert!(dest.ty().is_float());
2395        // TODO: bring this back //assert!(self_int.ty().is_int());
2396        self.state.add_instruction(
2397            OpCode::IntToFloat,
2398            &[dest.addressing(), self_int.addressing()],
2399            node,
2400            comment,
2401        );
2402    }
2403
2404    pub fn add_int_to_string(
2405        &mut self,
2406        dest: &TypedRegister,
2407        self_int: &TypedRegister,
2408        node: &Node,
2409        comment: &str,
2410    ) {
2411        assert!(dest.ty().is_str());
2412        assert!(self_int.ty().is_int());
2413        self.state.add_instruction(
2414            OpCode::IntToString,
2415            &[dest.addressing(), self_int.addressing()],
2416            node,
2417            comment,
2418        );
2419    }
2420
2421    pub fn bool_to_string(
2422        &mut self,
2423        dest_str: &TypedRegister,
2424        self_bool: &TypedRegister,
2425        node: &Node,
2426        comment: &str,
2427    ) {
2428        assert!(dest_str.ty().is_str());
2429        assert!(self_bool.ty().is_bool());
2430        self.state.add_instruction(
2431            OpCode::BoolToString,
2432            &[dest_str.addressing(), self_bool.addressing()],
2433            node,
2434            comment,
2435        );
2436    }
2437
2438    pub fn byte_to_string(
2439        &mut self,
2440        dest_str: &TypedRegister,
2441        self_bool: &TypedRegister,
2442        node: &Node,
2443        comment: &str,
2444    ) {
2445        assert!(dest_str.ty().is_str());
2446        assert!(self_bool.ty().is_byte());
2447        self.state.add_instruction(
2448            OpCode::ByteToString,
2449            &[dest_str.addressing(), self_bool.addressing()],
2450            node,
2451            comment,
2452        );
2453    }
2454
2455    pub fn codepoint_to_string(
2456        &mut self,
2457        dest_str: &TypedRegister,
2458        self_char: &TypedRegister,
2459        node: &Node,
2460        comment: &str,
2461    ) {
2462        assert!(dest_str.ty().is_str());
2463        assert!(self_char.ty().is_codepoint());
2464        self.state.add_instruction(
2465            OpCode::CodepointToString,
2466            &[dest_str.addressing(), self_char.addressing()],
2467            node,
2468            comment,
2469        );
2470    }
2471
2472    pub fn string_to_string(
2473        &mut self,
2474        dest_str: &TypedRegister,
2475        self_str: &TypedRegister,
2476        node: &Node,
2477        comment: &str,
2478    ) {
2479        assert!(dest_str.ty().is_str());
2480        assert!(self_str.ty().is_str());
2481        self.state.add_instruction(
2482            OpCode::StringToString,
2483            &[dest_str.addressing(), self_str.addressing()],
2484            node,
2485            comment,
2486        );
2487    }
2488
2489    pub fn float_to_string(
2490        &mut self,
2491        dest_str: &TypedRegister,
2492        self_float: &TypedRegister,
2493        node: &Node,
2494        comment: &str,
2495    ) {
2496        assert!(dest_str.ty().is_str());
2497        assert!(self_float.ty().is_float());
2498        self.state.add_instruction(
2499            OpCode::FloatToString,
2500            &[dest_str.addressing(), self_float.addressing()],
2501            node,
2502            comment,
2503        );
2504    }
2505
2506    pub fn add_float_round(
2507        &mut self,
2508        dest_int: &TypedRegister,
2509        self_float: &TypedRegister,
2510        node: &Node,
2511        comment: &str,
2512    ) {
2513        // assert!(dest_int.ty().is_int());
2514        assert!(self_float.ty().is_float());
2515        self.state.add_instruction(
2516            OpCode::FloatRound,
2517            &[dest_int.addressing(), self_float.addressing()],
2518            node,
2519            comment,
2520        );
2521    }
2522
2523    pub fn add_float_floor(
2524        &mut self,
2525        dest_int: &TypedRegister,
2526        self_float: &TypedRegister,
2527        node: &Node,
2528        comment: &str,
2529    ) {
2530        // TODO: bring this back //assert!(dest_int.ty().is_int());
2531        // TODO: bring this back //assert!(self_float.ty().is_float());
2532        self.state.add_instruction(
2533            OpCode::FloatFloor,
2534            &[dest_int.addressing(), self_float.addressing()],
2535            node,
2536            comment,
2537        );
2538    }
2539
2540    pub fn add_float_sqrt(
2541        &mut self,
2542        dest_float: &TypedRegister,
2543        self_float: &TypedRegister,
2544        node: &Node,
2545        comment: &str,
2546    ) {
2547        // TODO: bring this back //assert!(dest_float.ty().is_float());
2548        // TODO: bring this back //assert!(self_float.ty().is_float());
2549        self.state.add_instruction(
2550            OpCode::FloatSqrt,
2551            &[dest_float.addressing(), self_float.addressing()],
2552            node,
2553            comment,
2554        );
2555    }
2556
2557    pub fn add_float_sign(
2558        &mut self,
2559        dest_float: &TypedRegister,
2560        self_float: &TypedRegister,
2561        node: &Node,
2562        comment: &str,
2563    ) {
2564        assert!(dest_float.ty().is_float());
2565        assert!(self_float.ty().is_float());
2566        self.state.add_instruction(
2567            OpCode::FloatSign,
2568            &[dest_float.addressing(), self_float.addressing()],
2569            node,
2570            comment,
2571        );
2572    }
2573
2574    pub fn add_float_abs(
2575        &mut self,
2576        dest_float: &TypedRegister,
2577        self_float: &TypedRegister,
2578        node: &Node,
2579        comment: &str,
2580    ) {
2581        assert!(dest_float.ty().is_float());
2582        assert!(self_float.ty().is_float());
2583        self.state.add_instruction(
2584            OpCode::FloatAbs,
2585            &[dest_float.addressing(), self_float.addressing()],
2586            node,
2587            comment,
2588        );
2589    }
2590
2591    pub fn add_float_prnd(
2592        &mut self,
2593        dest_float: &TypedRegister,
2594        self_float: &TypedRegister,
2595        node: &Node,
2596        comment: &str,
2597    ) {
2598        assert!(dest_float.ty().is_float());
2599        assert!(self_float.ty().is_float());
2600        self.state.add_instruction(
2601            OpCode::FloatPseudoRandom,
2602            &[dest_float.addressing(), self_float.addressing()],
2603            node,
2604            comment,
2605        );
2606    }
2607
2608    pub fn add_float_sin(
2609        &mut self,
2610        dest_float: &TypedRegister,
2611        self_float: &TypedRegister,
2612        node: &Node,
2613        comment: &str,
2614    ) {
2615        assert!(dest_float.ty().is_float());
2616        assert!(self_float.ty().is_float());
2617        self.state.add_instruction(
2618            OpCode::FloatSin,
2619            &[dest_float.addressing(), self_float.addressing()],
2620            node,
2621            comment,
2622        );
2623    }
2624
2625    pub fn add_float_cos(
2626        &mut self,
2627        dest_float: &TypedRegister,
2628        self_float: &TypedRegister,
2629        node: &Node,
2630        comment: &str,
2631    ) {
2632        assert!(dest_float.ty().is_float());
2633        assert!(self_float.ty().is_float());
2634        self.state.add_instruction(
2635            OpCode::FloatCos,
2636            &[dest_float.addressing(), self_float.addressing()],
2637            node,
2638            comment,
2639        );
2640    }
2641
2642    pub fn add_float_acos(
2643        &mut self,
2644        dest_float: &TypedRegister,
2645        self_float: &TypedRegister,
2646        node: &Node,
2647        comment: &str,
2648    ) {
2649        assert!(dest_float.ty().is_float());
2650        assert!(self_float.ty().is_float());
2651        self.state.add_instruction(
2652            OpCode::FloatAcos,
2653            &[dest_float.addressing(), self_float.addressing()],
2654            node,
2655            comment,
2656        );
2657    }
2658
2659    pub fn add_float_asin(
2660        &mut self,
2661        dest_float: &TypedRegister,
2662        self_float: &TypedRegister,
2663        node: &Node,
2664        comment: &str,
2665    ) {
2666        assert!(dest_float.ty().is_float());
2667        assert!(self_float.ty().is_float());
2668        self.state.add_instruction(
2669            OpCode::FloatAsin,
2670            &[dest_float.addressing(), self_float.addressing()],
2671            node,
2672            comment,
2673        );
2674    }
2675
2676    pub fn add_float_atan2(
2677        &mut self,
2678        dest_float: &TypedRegister,
2679        self_float: &TypedRegister,
2680        node: &Node,
2681        comment: &str,
2682    ) {
2683        assert!(dest_float.ty().is_float());
2684        assert!(self_float.ty().is_float());
2685        self.state.add_instruction(
2686            OpCode::FloatAtan2,
2687            &[dest_float.addressing(), self_float.addressing()],
2688            node,
2689            comment,
2690        );
2691    }
2692
2693    pub fn add_float_min(
2694        &mut self,
2695        dest_float: &TypedRegister,
2696        self_float: &TypedRegister,
2697        other: &TypedRegister,
2698        node: &Node,
2699        comment: &str,
2700    ) {
2701        assert!(dest_float.ty().is_float());
2702        assert!(self_float.ty().is_float());
2703        self.state.add_instruction(
2704            OpCode::FloatMin,
2705            &[
2706                dest_float.addressing(),
2707                self_float.addressing(),
2708                other.addressing(),
2709            ],
2710            node,
2711            comment,
2712        );
2713    }
2714
2715    pub fn add_float_max(
2716        &mut self,
2717        dest_float: &TypedRegister,
2718        self_float: &TypedRegister,
2719        max_float: &TypedRegister,
2720        node: &Node,
2721        comment: &str,
2722    ) {
2723        assert!(dest_float.ty().is_float());
2724        assert!(self_float.ty().is_float());
2725        assert!(max_float.ty().is_float());
2726        self.state.add_instruction(
2727            OpCode::FloatMax,
2728            &[
2729                dest_float.addressing(),
2730                self_float.addressing(),
2731                max_float.addressing(),
2732            ],
2733            node,
2734            comment,
2735        );
2736    }
2737
2738    pub fn add_float_clamp(
2739        &mut self,
2740        dest_float: &TypedRegister,
2741        self_float: &TypedRegister,
2742        min_float: &TypedRegister,
2743        max_float: &TypedRegister,
2744        node: &Node,
2745        comment: &str,
2746    ) {
2747        assert!(dest_float.ty().is_float());
2748        assert!(self_float.ty().is_float());
2749        assert!(min_float.ty().is_float());
2750        assert!(max_float.ty().is_float());
2751
2752        self.state.add_instruction(
2753            OpCode::FloatClamp,
2754            &[
2755                dest_float.addressing(),
2756                min_float.addressing(),
2757                self_float.addressing(),
2758                max_float.addressing(),
2759            ],
2760            node,
2761            comment,
2762        );
2763    }
2764
2765    pub fn add_sparse_iter_init(
2766        &mut self,
2767        iterator_target: &TypedRegister,
2768        pointer_to_sparse_header: &TypedRegister,
2769        node: &Node,
2770        comment: &str,
2771    ) {
2772        self.state.add_instruction(
2773            OpCode::SparseIterInit,
2774            &[
2775                iterator_target.addressing(),
2776                pointer_to_sparse_header.addressing(),
2777            ],
2778            node,
2779            comment,
2780        );
2781    }
2782
2783    pub fn add_sparse_iter_next_placeholder(
2784        &mut self,
2785        iterator_target: &TypedRegister,
2786        closure_variable: &TypedRegister,
2787        node: &Node,
2788        comment: &str,
2789    ) -> PatchPosition {
2790        let position = self.position();
2791        self.state.add_instruction(
2792            OpCode::SparseIterNext,
2793            &[
2794                iterator_target.addressing(),
2795                closure_variable.addressing(),
2796                0,
2797                0,
2798            ],
2799            node,
2800            comment,
2801        );
2802        PatchPosition(position)
2803    }
2804
2805    pub fn add_sparse_iter_next_pair_placeholder(
2806        &mut self,
2807        iterator_target: &TypedRegister,
2808        closure_variable: &TypedRegister,
2809        closure_variable_b: &TypedRegister,
2810        node: &Node,
2811        comment: &str,
2812    ) -> PatchPosition {
2813        let position = self.position();
2814        self.state.add_instruction(
2815            OpCode::SparseIterNextPair,
2816            &[
2817                iterator_target.addressing(),
2818                closure_variable.addressing(),
2819                closure_variable_b.addressing(),
2820                0,
2821                0,
2822            ],
2823            node,
2824            comment,
2825        );
2826        PatchPosition(position)
2827    }
2828}