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    pub fn add_string_multiply(
1140        &mut self,
1141        dst_offset: &TypedRegister,
1142        lhs_offset: &TypedRegister,
1143        rhs_offset: &TypedRegister,
1144        node: &Node,
1145        comment: &str,
1146    ) {
1147        self.state.add_instruction(
1148            OpCode::StringRepeat,
1149            &[
1150                dst_offset.addressing(),
1151                lhs_offset.addressing(),
1152                rhs_offset.addressing(),
1153            ],
1154            node,
1155            comment,
1156        );
1157    }
1158
1159    pub fn add_string_cmp(
1160        &mut self,
1161        dest_bool_reg: &TypedRegister,
1162        a: &TypedRegister,
1163        b: &TypedRegister,
1164        node: &Node,
1165        comment: &str,
1166    ) {
1167        self.state.add_instruction(
1168            OpCode::StringCmp,
1169            &[dest_bool_reg.addressing(), a.addressing(), b.addressing()],
1170            node,
1171            comment,
1172        );
1173    }
1174
1175    pub fn add_fixed_capacity_array_init_fill_capacity_and_len(
1176        &mut self,
1177        target_vec_to_init: &PointerLocation,
1178        capacity: u16,
1179        element_size: &MemorySize,
1180        node: &Node,
1181        comment: &str,
1182    ) {
1183        //debug_assert!(len > 0);
1184        debug_assert!(capacity > 0);
1185
1186        let capacity_bytes = u16_to_u8_pair(capacity);
1187        let element_bytes = u32_to_bytes(element_size.0);
1188
1189        self.state.add_instruction(
1190            OpCode::ArrayInitWithLenAndCapacity,
1191            &[
1192                target_vec_to_init.ptr_reg.addressing(),
1193                capacity_bytes.0,
1194                capacity_bytes.1,
1195                element_bytes.0,
1196                element_bytes.1,
1197                element_bytes.2,
1198                element_bytes.3,
1199            ],
1200            node,
1201            comment,
1202        );
1203    }
1204
1205    pub fn add_map_init_set_capacity(
1206        &mut self,
1207        target_map_to_init: &PointerLocation,
1208        logical_limit: CountU16,
1209        key_size_reg: &TypedRegister,
1210        key_alignment: MemoryAlignment,
1211        value_size_reg: &TypedRegister,
1212        value_alignment: MemoryAlignment,
1213        node: &Node,
1214        comment: &str,
1215    ) {
1216        debug_assert!(logical_limit.0 > 0);
1217
1218        let logical_limit_bytes = u16_to_u8_pair(logical_limit.0);
1219
1220        let key_alignment_usize: usize = key_alignment.into();
1221        let value_alignment_usize: usize = value_alignment.into();
1222
1223        //let value_size_bytes = u16_to_u8_pair(value_size.0);
1224        self.state.add_instruction(
1225            OpCode::MapInitWithCapacityAndKeyAndTupleSizeAddr,
1226            &[
1227                target_map_to_init.ptr_reg.addressing(),
1228                logical_limit_bytes.0,
1229                logical_limit_bytes.1,
1230                key_size_reg.addressing(),
1231                key_alignment_usize as u8,
1232                value_size_reg.addressing(),
1233                value_alignment_usize as u8,
1234            ],
1235            node,
1236            comment,
1237        );
1238    }
1239
1240    pub fn add_map_overwrite(
1241        &mut self,
1242        destination_map: &PointerLocation,
1243        source_map: &PointerLocation,
1244        node: &Node,
1245        comment: &str,
1246    ) {
1247        self.state.add_instruction(
1248            OpCode::MapOverwrite,
1249            &[destination_map.addressing(), source_map.addressing()],
1250            node,
1251            comment,
1252        );
1253    }
1254
1255    pub fn add_range_iter_init(
1256        &mut self,
1257        iterator_target: &TypedRegister,
1258        range_source_header: &TypedRegister,
1259        node: &Node,
1260        comment: &str,
1261    ) {
1262        // TODO: Bring this back // assert_eq!(iterator_target.size(), RANGE_ITERATOR_SIZE);
1263        // TODO: Bring this back // assert_eq!(range_source_header.size(), RANGE_HEADER_SIZE);
1264
1265        self.state.add_instruction(
1266            OpCode::RangeIterInit,
1267            &[
1268                iterator_target.addressing(),
1269                range_source_header.addressing(),
1270            ],
1271            node,
1272            comment,
1273        );
1274    }
1275
1276    pub fn add_vec_copy(
1277        &mut self,
1278        target_vec: &PointerLocation,
1279        source_vec: &PointerLocation,
1280        node: &Node,
1281        comment: &str,
1282    ) {
1283        self.state.add_instruction(
1284            OpCode::VecCopy,
1285            &[
1286                target_vec.ptr_reg.addressing(),
1287                source_vec.ptr_reg.addressing(),
1288            ],
1289            node,
1290            comment,
1291        );
1292    }
1293
1294    pub fn add_vec_copy_range(
1295        &mut self,
1296        target_vec: &PointerLocation,
1297        source_vec: &PointerLocation,
1298        range_header: &TypedRegister,
1299        node: &Node,
1300        comment: &str,
1301    ) {
1302        self.state.add_instruction(
1303            OpCode::VecCopyRange,
1304            &[
1305                target_vec.addressing(),
1306                source_vec.addressing(),
1307                range_header.addressing(),
1308            ],
1309            node,
1310            comment,
1311        );
1312    }
1313
1314    pub fn add_vec_init_set_capacity(
1315        &mut self,
1316        target_vec_to_init: &PointerLocation,
1317        capacity: CountU16,
1318        element_size: &MemorySize,
1319        node: &Node,
1320        comment: &str,
1321    ) {
1322        //debug_assert!(len > 0);
1323        debug_assert!(capacity.0 > 0);
1324
1325        let capacity_bytes = u16_to_u8_pair(capacity.0);
1326        let element_bytes = u32_to_bytes(element_size.0);
1327        self.state.add_instruction(
1328            OpCode::VecInit,
1329            &[
1330                target_vec_to_init.ptr_reg.addressing(),
1331                capacity_bytes.0,
1332                capacity_bytes.1,
1333                element_bytes.0,
1334                element_bytes.1,
1335                element_bytes.2,
1336                element_bytes.3,
1337            ],
1338            node,
1339            comment,
1340        );
1341    }
1342
1343    pub fn add_vec_iter_init(
1344        &mut self,
1345        iterator_target: &TypedRegister,
1346        pointer_to_vec_header: &TypedRegister,
1347        node: &Node,
1348        comment: &str,
1349    ) {
1350        self.state.add_instruction(
1351            OpCode::VecIterInit,
1352            &[
1353                iterator_target.addressing(),
1354                pointer_to_vec_header.addressing(),
1355            ],
1356            node,
1357            comment,
1358        );
1359    }
1360
1361    pub fn add_vec_iter_next(
1362        &mut self,
1363        iterator_target: &TypedRegister,
1364        closure_variable: &TypedRegister,
1365        instruction_position: InstructionPosition,
1366        node: &Node,
1367        comment: &str,
1368    ) {
1369        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1370        self.state.add_instruction(
1371            OpCode::VecIterNext,
1372            &[
1373                iterator_target.addressing(),
1374                closure_variable.addressing(),
1375                bytes[0],
1376                bytes[1],
1377            ],
1378            node,
1379            comment,
1380        );
1381    }
1382
1383    pub fn add_vec_iter_next_pair(
1384        &mut self,
1385        iterator_target: &TypedRegister,
1386        closure_variable_key: &TypedRegister,
1387        closure_variable_value: &TypedRegister,
1388        instruction_position: InstructionPosition,
1389        node: &Node,
1390        comment: &str,
1391    ) {
1392        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1393        self.state.add_instruction(
1394            OpCode::VecIterNextPair,
1395            &[
1396                iterator_target.addressing(),
1397                closure_variable_key.addressing(),
1398                closure_variable_value.addressing(),
1399                bytes[0],
1400                bytes[1],
1401            ],
1402            node,
1403            comment,
1404        );
1405    }
1406
1407    pub fn add_string_iter_init(
1408        &mut self,
1409        iterator_target: &TypedRegister,
1410        pointer_to_vec_header: &TypedRegister,
1411        element_size: MemorySize,
1412        node: &Node,
1413        comment: &str,
1414    ) {
1415        let element_size_bytes = u32_to_bytes(element_size.0);
1416        self.state.add_instruction(
1417            OpCode::StringIterInit,
1418            &[
1419                iterator_target.addressing(),
1420                pointer_to_vec_header.addressing(),
1421                element_size_bytes.0,
1422                element_size_bytes.1,
1423                element_size_bytes.2,
1424                element_size_bytes.3,
1425            ],
1426            node,
1427            comment,
1428        );
1429    }
1430
1431    pub fn add_string_iter_next(
1432        &mut self,
1433        iterator_target: &TypedRegister,
1434        closure_variable: &TypedRegister,
1435        instruction_position: InstructionPosition,
1436        node: &Node,
1437        comment: &str,
1438    ) {
1439        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1440        self.state.add_instruction(
1441            OpCode::StringIterNext,
1442            &[
1443                iterator_target.addressing(),
1444                closure_variable.addressing(),
1445                bytes[0],
1446                bytes[1],
1447            ],
1448            node,
1449            comment,
1450        );
1451    }
1452
1453    pub fn add_string_iter_next_pair(
1454        &mut self,
1455        iterator_target: &TypedRegister,
1456        closure_variable_key: &TypedRegister,
1457        closure_variable_value: &TypedRegister,
1458        instruction_position: InstructionPosition,
1459        node: &Node,
1460        comment: &str,
1461    ) {
1462        let bytes = self.calculate_pc_delta_bytes(instruction_position);
1463        self.state.add_instruction(
1464            OpCode::StringIterNextPair,
1465            &[
1466                iterator_target.addressing(),
1467                closure_variable_key.addressing(),
1468                closure_variable_value.addressing(),
1469                bytes[0],
1470                bytes[1],
1471            ],
1472            node,
1473            comment,
1474        );
1475    }
1476    fn convert_to_lower_and_upper(data: u32) -> (u8, u8, u8, u8) {
1477        data.to_le_bytes().into()
1478    }
1479
1480    fn u16_to_octets(data: u16) -> (u8, u8) {
1481        data.to_le_bytes().into()
1482    }
1483
1484    pub fn add_st32_using_ptr_with_offset(
1485        &mut self,
1486        scalar_lvalue_location: &MemoryLocation,
1487        u32_reg: &TypedRegister,
1488        node: &Node,
1489        comment: &str,
1490    ) {
1491        //assert_eq!(u32_reg.ty().underlying().total_size.0, 4);
1492        let offset_bytes = u32_to_bytes(scalar_lvalue_location.offset.0);
1493        self.state.add_instruction(
1494            OpCode::St32UsingPtrWithOffset,
1495            &[
1496                scalar_lvalue_location.base_ptr_reg.addressing(),
1497                offset_bytes.0,
1498                offset_bytes.1,
1499                offset_bytes.2,
1500                offset_bytes.3,
1501                u32_reg.index,
1502            ],
1503            node,
1504            comment,
1505        );
1506    }
1507
1508    pub fn add_st16_using_ptr_with_offset(
1509        &mut self,
1510        scalar_lvalue_location: &MemoryLocation,
1511        u16_reg: &TypedRegister,
1512        node: &Node,
1513        comment: &str,
1514    ) {
1515        //assert_eq!(u16_reg.ty().underlying().total_size.0, 2);
1516        let offset_bytes = u32_to_bytes(scalar_lvalue_location.offset.0);
1517        self.state.add_instruction(
1518            OpCode::St16UsingPtrWithOffset,
1519            &[
1520                scalar_lvalue_location.base_ptr_reg.addressing(),
1521                offset_bytes.0,
1522                offset_bytes.1,
1523                offset_bytes.2,
1524                offset_bytes.3,
1525                u16_reg.index,
1526            ],
1527            node,
1528            comment,
1529        );
1530    }
1531
1532    pub fn add_st8_using_ptr_with_offset(
1533        &mut self,
1534        scalar_lvalue_location: &MemoryLocation,
1535        u8_reg: &TypedRegister,
1536        node: &Node,
1537        comment: &str,
1538    ) {
1539        // TODO: Bring this back. // assert_eq!(u8_reg.ty().underlying().total_size.0, 1);
1540        let offset_bytes = u32_to_bytes(scalar_lvalue_location.offset.0);
1541        self.state.add_instruction(
1542            OpCode::St8UsingPtrWithOffset,
1543            &[
1544                scalar_lvalue_location.base_ptr_reg.addressing(),
1545                offset_bytes.0,
1546                offset_bytes.1,
1547                offset_bytes.2,
1548                offset_bytes.3,
1549                u8_reg.addressing(),
1550            ],
1551            node,
1552            comment,
1553        );
1554    }
1555
1556    pub fn add_mov_16_immediate_value(
1557        &mut self,
1558        dst_offset: &TypedRegister,
1559        value: u16,
1560        node: &Node,
1561        comment: &str,
1562    ) {
1563        let bytes = Self::u16_to_octets(value);
1564
1565        self.state.add_instruction(
1566            OpCode::Mov16FromImmediateValue,
1567            &[dst_offset.addressing(), bytes.0, bytes.1],
1568            node,
1569            comment,
1570        );
1571    }
1572
1573    pub fn add_mov_32_immediate_value(
1574        &mut self,
1575        dst_offset: &TypedRegister,
1576        value: u32,
1577        node: &Node,
1578        comment: &str,
1579    ) {
1580        let bytes = Self::convert_to_lower_and_upper(value);
1581
1582        self.state.add_instruction(
1583            OpCode::Mov32FromImmediateValue,
1584            &[dst_offset.addressing(), bytes.0, bytes.1, bytes.2, bytes.3],
1585            node,
1586            comment,
1587        );
1588    }
1589
1590    pub fn add_ld32_from_absolute_memory_address(
1591        &mut self,
1592        dst_reg: &TypedRegister,
1593        absolute_mem_addr: &HeapMemoryAddress,
1594        node: &Node,
1595        comment: &str,
1596    ) {
1597        let bytes = u32_to_bytes(absolute_mem_addr.0);
1598
1599        self.state.add_instruction(
1600            OpCode::Ld32FromAbsoluteAddress,
1601            &[dst_reg.addressing(), bytes.0, bytes.1, bytes.2, bytes.3],
1602            node,
1603            comment,
1604        );
1605    }
1606
1607    pub fn add_ld16_from_pointer_from_memory_location(
1608        &mut self,
1609        dst_reg: &TypedRegister,
1610        source_memory_location: &MemoryLocation,
1611        node: &Node,
1612        comment: &str,
1613    ) {
1614        self.add_ld16_from_pointer_with_offset_u16(
1615            dst_reg,
1616            &source_memory_location.base_ptr_reg,
1617            source_memory_location.offset,
1618            node,
1619            comment,
1620        );
1621    }
1622
1623    pub fn add_ld16_from_pointer_with_offset_u16(
1624        &mut self,
1625        dst_reg: &TypedRegister,
1626        base_ptr_reg: &TypedRegister,
1627        offset: MemoryOffset,
1628        node: &Node,
1629        comment: &str,
1630    ) {
1631        let offset_bytes = u32_to_bytes(offset.0);
1632
1633        self.state.add_instruction(
1634            OpCode::Ld16FromPointerWithOffset,
1635            &[
1636                dst_reg.addressing(),
1637                base_ptr_reg.addressing(),
1638                offset_bytes.0,
1639                offset_bytes.1,
1640                offset_bytes.2,
1641                offset_bytes.3,
1642            ],
1643            node,
1644            comment,
1645        );
1646    }
1647
1648    pub fn add_ld32_from_pointer_with_offset_u16(
1649        &mut self,
1650        dst_reg: &TypedRegister,
1651        base_ptr_reg: &TypedRegister,
1652        offset: MemoryOffset,
1653        node: &Node,
1654        comment: &str,
1655    ) {
1656        let offset_bytes = u32_to_bytes(offset.0);
1657
1658        self.state.add_instruction(
1659            OpCode::Ld32FromPointerWithOffset,
1660            &[
1661                dst_reg.addressing(),
1662                base_ptr_reg.addressing(),
1663                offset_bytes.0,
1664                offset_bytes.1,
1665                offset_bytes.2,
1666                offset_bytes.3,
1667            ],
1668            node,
1669            comment,
1670        );
1671    }
1672
1673    pub fn add_ld8_from_absolute_memory_address(
1674        &mut self,
1675        dst_reg: &TypedRegister,
1676        absolute_mem_addr: &HeapMemoryAddress,
1677        node: &Node,
1678        comment: &str,
1679    ) {
1680        let absolute_memory_addr = u32_to_bytes(absolute_mem_addr.0);
1681
1682        self.state.add_instruction(
1683            OpCode::Ld8FromAbsoluteAddress,
1684            &[
1685                dst_reg.addressing(),
1686                absolute_memory_addr.0,
1687                absolute_memory_addr.1,
1688                absolute_memory_addr.2,
1689                absolute_memory_addr.3,
1690            ],
1691            node,
1692            comment,
1693        );
1694    }
1695
1696    pub fn add_ld8_from_pointer_with_offset_u16(
1697        &mut self,
1698        dst_reg: &TypedRegister,
1699        base_ptr_reg: &TypedRegister,
1700        offset: MemoryOffset,
1701        node: &Node,
1702        comment: &str,
1703    ) {
1704        let offset_bytes = u32_to_bytes(offset.0);
1705
1706        self.state.add_instruction(
1707            OpCode::Ld8FromPointerWithOffset,
1708            &[
1709                dst_reg.addressing(),
1710                base_ptr_reg.addressing(),
1711                offset_bytes.0,
1712                offset_bytes.1,
1713                offset_bytes.2,
1714                offset_bytes.3,
1715            ],
1716            node,
1717            comment,
1718        );
1719    }
1720
1721    pub fn add_mov_reg(
1722        &mut self,
1723        dst_offset: &TypedRegister,
1724        src_offset: &TypedRegister,
1725        node: &Node,
1726        comment: &str,
1727    ) {
1728        if dst_offset.index == src_offset.index {
1729            return;
1730        }
1731        self.state.add_instruction(
1732            OpCode::MovReg,
1733            &[dst_offset.addressing(), src_offset.addressing()],
1734            node,
1735            comment,
1736        );
1737    }
1738
1739    pub fn add_mov8_immediate(
1740        &mut self,
1741        dst_offset: &TypedRegister,
1742        value: u8,
1743        node: &Node,
1744        comment: &str,
1745    ) {
1746        self.state.add_instruction(
1747            OpCode::Mov8FromImmediateValue,
1748            &[dst_offset.addressing(), value],
1749            node,
1750            comment,
1751        );
1752    }
1753
1754    pub fn add_add_u32(
1755        &mut self,
1756        dst_offset: &TypedRegister,
1757        lhs_offset: &TypedRegister,
1758        rhs_offset: &TypedRegister,
1759        node: &Node,
1760        comment: &str,
1761    ) {
1762        // TODO: Bring this back //assert!(dst_offset.ty().is_int());
1763        // TODO: Bring this back //assert!(lhs_offset.ty().is_int());
1764        // TODO: Bring this back //assert!(rhs_offset.ty().is_int());
1765        self.state.add_instruction(
1766            OpCode::AddU32,
1767            &[
1768                dst_offset.addressing(),
1769                lhs_offset.addressing(),
1770                rhs_offset.addressing(),
1771            ],
1772            node,
1773            comment,
1774        );
1775    }
1776
1777    pub fn add_add_u32_imm(
1778        &mut self,
1779        dst_offset: &TypedRegister,
1780        lhs_offset: &TypedRegister,
1781        rhs_immediate: u32,
1782        node: &Node,
1783        comment: &str,
1784    ) {
1785        // TODO: Bring this back //assert!(dst_offset.ty().is_int());
1786        // TODO: Bring this back //assert!(lhs_offset.ty().is_int());
1787        // TODO: Bring this back //assert!(rhs_offset.ty().is_int());
1788        let immediate_bytes = u32_to_bytes(rhs_immediate);
1789        self.state.add_instruction(
1790            OpCode::AddU32Imm,
1791            &[
1792                dst_offset.addressing(),
1793                lhs_offset.addressing(),
1794                immediate_bytes.0,
1795                immediate_bytes.1,
1796                immediate_bytes.2,
1797                immediate_bytes.3,
1798            ],
1799            node,
1800            comment,
1801        );
1802    }
1803
1804    pub fn add_mod_i32(
1805        &mut self,
1806        dst_offset: &TypedRegister,
1807        lhs_offset: &TypedRegister,
1808        rhs_offset: &TypedRegister,
1809        node: &Node,
1810        comment: &str,
1811    ) {
1812        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1813        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1814        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1815
1816        self.state.add_instruction(
1817            OpCode::ModI32,
1818            &[
1819                dst_offset.addressing(),
1820                lhs_offset.addressing(),
1821                rhs_offset.addressing(),
1822            ],
1823            node,
1824            comment,
1825        );
1826    }
1827
1828    pub fn add_div_i32(
1829        &mut self,
1830        dst_offset: &TypedRegister,
1831        lhs_offset: &TypedRegister,
1832        rhs_offset: &TypedRegister,
1833        node: &Node,
1834        comment: &str,
1835    ) {
1836        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1837        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1838        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1839        self.state.add_instruction(
1840            OpCode::DivI32,
1841            &[
1842                dst_offset.addressing(),
1843                lhs_offset.addressing(),
1844                rhs_offset.addressing(),
1845            ],
1846            node,
1847            comment,
1848        );
1849    }
1850
1851    pub fn add_sub_u32(
1852        &mut self,
1853        dst_offset: &TypedRegister,
1854        lhs_offset: &TypedRegister,
1855        rhs_offset: &TypedRegister,
1856        node: &Node,
1857        comment: &str,
1858    ) {
1859        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1860        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1861        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1862        self.state.add_instruction(
1863            OpCode::SubU32,
1864            &[
1865                dst_offset.addressing(),
1866                lhs_offset.addressing(),
1867                rhs_offset.addressing(),
1868            ],
1869            node,
1870            comment,
1871        );
1872    }
1873
1874    pub fn add_mul_i32(
1875        &mut self,
1876        dst_offset: &TypedRegister,
1877        lhs_offset: &TypedRegister,
1878        rhs_offset: &TypedRegister,
1879        node: &Node,
1880        comment: &str,
1881    ) {
1882        // TODO: Bring this back // assert!(dst_offset.ty().is_int());
1883        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
1884        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
1885        self.state.add_instruction(
1886            OpCode::MulU32,
1887            &[
1888                dst_offset.addressing(),
1889                lhs_offset.addressing(),
1890                rhs_offset.addressing(),
1891            ],
1892            node,
1893            comment,
1894        );
1895    }
1896
1897    pub fn add_neg_i32(
1898        &mut self,
1899        target: &TypedRegister,
1900        source: &TypedRegister,
1901        node: &Node,
1902        comment: &str,
1903    ) {
1904        // TODO: Bring this back //assert!(target.ty().is_int());
1905        // TODO: Bring this back //assert!(source.ty().is_int());
1906        self.state.add_instruction(
1907            OpCode::NegI32,
1908            &[target.addressing(), source.addressing()],
1909            node,
1910            comment,
1911        );
1912    }
1913
1914    pub fn add_sub_f32(
1915        &mut self,
1916        dst_offset: &TypedRegister,
1917        lhs_offset: &TypedRegister,
1918        rhs_offset: &TypedRegister,
1919        node: &Node,
1920        comment: &str,
1921    ) {
1922        // TODO: bring this back // assert!(dst_offset.ty().is_float());
1923        // TODO: bring this back //assert!(lhs_offset.ty().is_float());
1924        // TODO: bring this back //assert!(rhs_offset.ty().is_float());
1925        self.state.add_instruction(
1926            OpCode::SubU32,
1927            &[
1928                dst_offset.addressing(),
1929                lhs_offset.addressing(),
1930                rhs_offset.addressing(),
1931            ],
1932            node,
1933            comment,
1934        );
1935    }
1936    pub fn add_mul_f32(
1937        &mut self,
1938        dst_offset: &TypedRegister,
1939        lhs_offset: &TypedRegister,
1940        rhs_offset: &TypedRegister,
1941        node: &Node,
1942        comment: &str,
1943    ) {
1944        // TODO: bring this back //assert!(dst_offset.ty().is_float());
1945        // TODO: bring this back //assert!(lhs_offset.ty().is_float());
1946        // TODO: bring this back //assert!(rhs_offset.ty().is_float());
1947        self.state.add_instruction(
1948            OpCode::MulF32,
1949            &[
1950                dst_offset.addressing(),
1951                lhs_offset.addressing(),
1952                rhs_offset.addressing(),
1953            ],
1954            node,
1955            comment,
1956        );
1957    }
1958    pub fn add_div_f32(
1959        &mut self,
1960        dst_offset: &TypedRegister,
1961        lhs_offset: &TypedRegister,
1962        rhs_offset: &TypedRegister,
1963        node: &Node,
1964        comment: &str,
1965    ) {
1966        // TODO: Bring this back //assert!(dst_offset.ty().is_float());
1967        // TODO: Bring this back //assert!(lhs_offset.ty().is_float());
1968        // TODO: Bring this back //assert!(rhs_offset.ty().is_float());
1969        self.state.add_instruction(
1970            OpCode::DivF32,
1971            &[
1972                dst_offset.addressing(),
1973                lhs_offset.addressing(),
1974                rhs_offset.addressing(),
1975            ],
1976            node,
1977            comment,
1978        );
1979    }
1980
1981    pub fn add_add_f32(
1982        &mut self,
1983        dst_offset: &TypedRegister,
1984        lhs_offset: &TypedRegister,
1985        rhs_offset: &TypedRegister,
1986        node: &Node,
1987        comment: &str,
1988    ) {
1989        // TODO: bring this back //assert!(dst_offset.ty().is_float());
1990        // TODO: bring this back //assert!(lhs_offset.ty().is_float());
1991        // TODO: bring this back //assert!(rhs_offset.ty().is_float());
1992        self.state.add_instruction(
1993            OpCode::AddU32,
1994            &[
1995                dst_offset.addressing(),
1996                lhs_offset.addressing(),
1997                rhs_offset.addressing(),
1998            ],
1999            node,
2000            comment,
2001        );
2002    }
2003
2004    pub fn add_neg_f32(
2005        &mut self,
2006        target: &TypedRegister,
2007        source: &TypedRegister,
2008        node: &Node,
2009        comment: &str,
2010    ) {
2011        // TODO: Bring this back // assert!(target.ty().is_float());
2012        // TODO: Bring this back // assert!(source.ty().is_float());
2013        self.state.add_instruction(
2014            OpCode::NegI32,
2015            &[target.addressing(), source.addressing()],
2016            node,
2017            comment,
2018        );
2019    }
2020
2021    pub fn add_lt_i32(
2022        &mut self,
2023        dest_bool_reg: &TypedRegister,
2024        lhs_offset: &TypedRegister,
2025        rhs_offset: &TypedRegister,
2026        node: &Node,
2027        comment: &str,
2028    ) {
2029        // TODO: Bring Back //assert!(lhs_offset.ty().is_int());
2030        // TODO: Bring Back //assert!(rhs_offset.ty().is_int());
2031        self.state.add_instruction(
2032            OpCode::LtI32,
2033            &[
2034                dest_bool_reg.addressing(),
2035                lhs_offset.addressing(),
2036                rhs_offset.addressing(),
2037            ],
2038            node,
2039            comment,
2040        );
2041    }
2042
2043    pub fn add_lt_u32(
2044        &mut self,
2045        lhs_offset: &TypedRegister,
2046        rhs_offset: &TypedRegister,
2047        node: &Node,
2048        comment: &str,
2049    ) {
2050        // TODO: Bring Back //assert!(lhs_offset.ty().is_int());
2051        // TODO: Bring Back //assert!(rhs_offset.ty().is_int());
2052        self.state.add_instruction(
2053            OpCode::LtU32,
2054            &[lhs_offset.addressing(), rhs_offset.addressing()],
2055            node,
2056            comment,
2057        );
2058    }
2059
2060    pub fn add_le_i32(
2061        &mut self,
2062        dest_bool_reg: &TypedRegister,
2063        lhs_offset: &TypedRegister,
2064        rhs_offset: &TypedRegister,
2065        node: &Node,
2066        comment: &str,
2067    ) {
2068        // TODO: Bring this back // assert!(lhs_offset.ty().is_int());
2069        // TODO: Bring this back // assert!(rhs_offset.ty().is_int());
2070        self.state.add_instruction(
2071            OpCode::LeI32,
2072            &[
2073                dest_bool_reg.addressing(),
2074                lhs_offset.addressing(),
2075                rhs_offset.addressing(),
2076            ],
2077            node,
2078            comment,
2079        );
2080    }
2081
2082    pub fn add_gt_i32(
2083        &mut self,
2084        dest_bool_reg: &TypedRegister,
2085        lhs_offset: &TypedRegister,
2086        rhs_offset: &TypedRegister,
2087        node: &Node,
2088        comment: &str,
2089    ) {
2090        // TODO: Bring this back. //assert!(lhs_offset.ty().is_int());
2091        // TODO: Bring this back. //assert!(rhs_offset.ty().is_int());
2092        self.state.add_instruction(
2093            OpCode::GtI32,
2094            &[
2095                dest_bool_reg.addressing(),
2096                lhs_offset.addressing(),
2097                rhs_offset.addressing(),
2098            ],
2099            node,
2100            comment,
2101        );
2102    }
2103
2104    pub fn add_ge_i32(
2105        &mut self,
2106        dest_bool_reg: &TypedRegister,
2107        lhs_offset: &TypedRegister,
2108        rhs_offset: &TypedRegister,
2109        node: &Node,
2110        comment: &str,
2111    ) {
2112        // TODO: bring this back //assert!(lhs_offset.ty().is_int());
2113        // TODO: bring this back //assert!(rhs_offset.ty().is_int());
2114        self.state.add_instruction(
2115            OpCode::GeI32,
2116            &[
2117                dest_bool_reg.addressing(),
2118                lhs_offset.addressing(),
2119                rhs_offset.addressing(),
2120            ],
2121            node,
2122            comment,
2123        );
2124    }
2125
2126    pub fn add_ge_u32(
2127        &mut self,
2128        dest_bool_reg: &TypedRegister,
2129        lhs_offset: &TypedRegister,
2130        rhs_offset: &TypedRegister,
2131        node: &Node,
2132        comment: &str,
2133    ) {
2134        // TODO: bring this back //assert!(lhs_offset.ty().is_int());
2135        // TODO: bring this back //assert!(rhs_offset.ty().is_int());
2136        self.state.add_instruction(
2137            OpCode::GeU32,
2138            &[
2139                dest_bool_reg.addressing(),
2140                lhs_offset.addressing(),
2141                rhs_offset.addressing(),
2142            ],
2143            node,
2144            comment,
2145        );
2146    }
2147
2148    pub fn add_meqz(
2149        &mut self,
2150        dest_bool_reg: &TypedRegister,
2151        addr: &TypedRegister,
2152        node: &Node,
2153        comment: &str,
2154    ) {
2155        self.state.add_instruction(
2156            OpCode::MovEqualToZero,
2157            &[dest_bool_reg.addressing(), addr.addressing()],
2158            node,
2159            comment,
2160        );
2161    }
2162
2163    pub fn add_trap(&mut self, trap_code: u8, node: &Node, comment: &str) {
2164        self.state
2165            .add_instruction(OpCode::Trap, &[trap_code], node, comment);
2166    }
2167
2168    pub fn add_cmp_reg(
2169        &mut self,
2170        dest_bool_reg: &TypedRegister,
2171        source_a: &TypedRegister,
2172        source_b: &TypedRegister,
2173        node: &Node,
2174        comment: &str,
2175    ) {
2176        self.state.add_instruction(
2177            OpCode::CmpReg,
2178            &[
2179                dest_bool_reg.addressing(),
2180                source_a.addressing(),
2181                source_b.addressing(),
2182            ],
2183            node,
2184            comment,
2185        );
2186    }
2187
2188    pub fn add_block_cmp(
2189        &mut self,
2190        dest_bool_reg: &TypedRegister,
2191        first_ptr: &TypedRegister,
2192        second_ptr: &TypedRegister,
2193        size: MemorySize,
2194        node: &Node,
2195        comment: &str,
2196    ) {
2197        let block_size_bytes = u32_to_bytes(size.0);
2198        self.state.add_instruction(
2199            OpCode::CmpBlock,
2200            &[
2201                dest_bool_reg.addressing(),
2202                first_ptr.addressing(),
2203                second_ptr.addressing(),
2204                block_size_bytes.0,
2205                block_size_bytes.1,
2206                block_size_bytes.2,
2207                block_size_bytes.3,
2208            ],
2209            node,
2210            comment,
2211        );
2212    }
2213
2214    // Collection specific
2215
2216    pub fn add_map_has(
2217        &mut self,
2218        dest_reg: &TypedRegister,
2219        self_addr: &PointerLocation,
2220        key_addr: &TypedRegister,
2221        node: &Node,
2222        comment: &str,
2223    ) {
2224        matches!(
2225            self_addr.ptr_reg.ty().kind,
2226            BasicTypeKind::DynamicLengthMapView(_, _)
2227        );
2228        self.state.add_instruction(
2229            OpCode::MapHas,
2230            &[
2231                dest_reg.addressing(),
2232                self_addr.addressing(),
2233                key_addr.addressing(),
2234            ],
2235            node,
2236            comment,
2237        );
2238    }
2239
2240    pub fn add_map_remove(
2241        &mut self,
2242        self_addr: &PointerLocation,
2243        key_addr: &TypedRegister,
2244        node: &Node,
2245        comment: &str,
2246    ) {
2247        matches!(
2248            self_addr.ptr_reg.ty().kind,
2249            BasicTypeKind::DynamicLengthMapView(_, _)
2250        );
2251        self.state.add_instruction(
2252            OpCode::MapRemove,
2253            &[self_addr.addressing(), key_addr.addressing()],
2254            node,
2255            comment,
2256        );
2257    }
2258
2259    pub fn add_map_get_entry_location(
2260        &mut self,
2261        target_entry_addr: &TypedRegister,
2262        map_self_addr: &PointerLocation,
2263        key: &TypedRegister,
2264        node: &Node,
2265        comment: &str,
2266    ) {
2267        //TODO: Bring this back: //matches!(map_self_addr.ty().kind, BasicTypeKind::InternalMapPointer(_, _));
2268        self.state.add_instruction(
2269            OpCode::MapGetEntryLocation,
2270            &[
2271                target_entry_addr.addressing(),
2272                map_self_addr.addressing(),
2273                key.addressing(),
2274            ],
2275            node,
2276            comment,
2277        );
2278    }
2279
2280    pub fn add_map_get_or_reserve_entry_location(
2281        &mut self,
2282        target_entry_reg: &TypedRegister,
2283        map_self_addr: &PointerLocation,
2284        key: &TypedRegister,
2285        node: &Node,
2286        comment: &str,
2287    ) {
2288        self.state.add_instruction(
2289            OpCode::MapGetOrReserveEntryLocation,
2290            &[
2291                target_entry_reg.addressing(),
2292                map_self_addr.addressing(),
2293                key.addressing(),
2294            ],
2295            node,
2296            comment,
2297        );
2298    }
2299
2300    pub fn add_int_rnd(
2301        &mut self,
2302        dest: &TypedRegister,
2303        self_int: &TypedRegister,
2304        node: &Node,
2305        comment: &str,
2306    ) {
2307        assert!(dest.ty().is_int());
2308        assert!(self_int.ty().is_int());
2309        self.state.add_instruction(
2310            OpCode::IntToRnd,
2311            &[dest.addressing(), self_int.addressing()],
2312            node,
2313            comment,
2314        );
2315    }
2316
2317    pub fn add_int_min(
2318        &mut self,
2319        dest: &TypedRegister,
2320        self_int: &TypedRegister,
2321        other_int: &TypedRegister,
2322        node: &Node,
2323        comment: &str,
2324    ) {
2325        // TODO: Bring this back //assert!(dest.ty().is_int());
2326        // TODO: Bring this back //assert!(self_int.ty().is_int());
2327
2328        self.state.add_instruction(
2329            OpCode::IntMin,
2330            &[
2331                dest.addressing(),
2332                self_int.addressing(),
2333                other_int.addressing(),
2334            ],
2335            node,
2336            comment,
2337        );
2338    }
2339
2340    pub fn add_int_max(
2341        &mut self,
2342        dest: &TypedRegister,
2343        self_int: &TypedRegister,
2344        other_int: &TypedRegister,
2345        node: &Node,
2346        comment: &str,
2347    ) {
2348        // TODO: Bring this back //assert!(dest.ty().is_int());
2349        // TODO: Bring this back //assert!(self_int.ty().is_int());
2350
2351        self.state.add_instruction(
2352            OpCode::IntMax,
2353            &[
2354                dest.addressing(),
2355                self_int.addressing(),
2356                other_int.addressing(),
2357            ],
2358            node,
2359            comment,
2360        );
2361    }
2362
2363    pub fn add_int_clamp(
2364        &mut self,
2365        dest: &TypedRegister,
2366        self_int: &TypedRegister,
2367        min_int: &TypedRegister,
2368        max_int: &TypedRegister,
2369        node: &Node,
2370        comment: &str,
2371    ) {
2372        assert!(dest.ty().is_int());
2373        assert!(self_int.ty().is_int());
2374        assert!(min_int.ty().is_int());
2375        assert!(max_int.ty().is_int());
2376        self.state.add_instruction(
2377            OpCode::IntClamp,
2378            &[
2379                dest.addressing(),
2380                self_int.addressing(),
2381                min_int.addressing(),
2382                max_int.addressing(),
2383            ],
2384            node,
2385            comment,
2386        );
2387    }
2388
2389    pub fn add_int_abs(
2390        &mut self,
2391        dest: &TypedRegister,
2392        self_int: &TypedRegister,
2393        node: &Node,
2394        comment: &str,
2395    ) {
2396        // TODO: Bring this back //  assert!(dest.ty().is_int());
2397        // TODO: Bring this back //  assert!(self_int.ty().is_int());
2398        self.state.add_instruction(
2399            OpCode::IntAbs,
2400            &[dest.addressing(), self_int.addressing()],
2401            node,
2402            comment,
2403        );
2404    }
2405
2406    pub fn add_int_to_float(
2407        &mut self,
2408        dest: &TypedRegister,
2409        self_int: &TypedRegister,
2410        node: &Node,
2411        comment: &str,
2412    ) {
2413        // TODO: bring this back //assert!(dest.ty().is_float());
2414        // TODO: bring this back //assert!(self_int.ty().is_int());
2415        self.state.add_instruction(
2416            OpCode::IntToFloat,
2417            &[dest.addressing(), self_int.addressing()],
2418            node,
2419            comment,
2420        );
2421    }
2422
2423    pub fn add_int_to_string(
2424        &mut self,
2425        dest: &TypedRegister,
2426        self_int: &TypedRegister,
2427        node: &Node,
2428        comment: &str,
2429    ) {
2430        assert!(dest.ty().is_str());
2431        assert!(self_int.ty().is_int());
2432        self.state.add_instruction(
2433            OpCode::IntToString,
2434            &[dest.addressing(), self_int.addressing()],
2435            node,
2436            comment,
2437        );
2438    }
2439
2440    pub fn bool_to_string(
2441        &mut self,
2442        dest_str: &TypedRegister,
2443        self_bool: &TypedRegister,
2444        node: &Node,
2445        comment: &str,
2446    ) {
2447        assert!(dest_str.ty().is_str());
2448        assert!(self_bool.ty().is_bool());
2449        self.state.add_instruction(
2450            OpCode::BoolToString,
2451            &[dest_str.addressing(), self_bool.addressing()],
2452            node,
2453            comment,
2454        );
2455    }
2456
2457    pub fn byte_to_string(
2458        &mut self,
2459        dest_str: &TypedRegister,
2460        self_bool: &TypedRegister,
2461        node: &Node,
2462        comment: &str,
2463    ) {
2464        assert!(dest_str.ty().is_str());
2465        assert!(self_bool.ty().is_byte());
2466        self.state.add_instruction(
2467            OpCode::ByteToString,
2468            &[dest_str.addressing(), self_bool.addressing()],
2469            node,
2470            comment,
2471        );
2472    }
2473
2474    pub fn codepoint_to_string(
2475        &mut self,
2476        dest_str: &TypedRegister,
2477        self_char: &TypedRegister,
2478        node: &Node,
2479        comment: &str,
2480    ) {
2481        assert!(dest_str.ty().is_str());
2482        assert!(self_char.ty().is_codepoint());
2483        self.state.add_instruction(
2484            OpCode::CodepointToString,
2485            &[dest_str.addressing(), self_char.addressing()],
2486            node,
2487            comment,
2488        );
2489    }
2490
2491    pub fn string_to_string(
2492        &mut self,
2493        dest_str: &TypedRegister,
2494        self_str: &TypedRegister,
2495        node: &Node,
2496        comment: &str,
2497    ) {
2498        assert!(dest_str.ty().is_str());
2499        assert!(self_str.ty().is_str());
2500        self.state.add_instruction(
2501            OpCode::StringToString,
2502            &[dest_str.addressing(), self_str.addressing()],
2503            node,
2504            comment,
2505        );
2506    }
2507
2508    pub fn float_to_string(
2509        &mut self,
2510        dest_str: &TypedRegister,
2511        self_float: &TypedRegister,
2512        node: &Node,
2513        comment: &str,
2514    ) {
2515        assert!(dest_str.ty().is_str());
2516        assert!(self_float.ty().is_float());
2517        self.state.add_instruction(
2518            OpCode::FloatToString,
2519            &[dest_str.addressing(), self_float.addressing()],
2520            node,
2521            comment,
2522        );
2523    }
2524
2525    pub fn add_float_round(
2526        &mut self,
2527        dest_int: &TypedRegister,
2528        self_float: &TypedRegister,
2529        node: &Node,
2530        comment: &str,
2531    ) {
2532        // assert!(dest_int.ty().is_int());
2533        assert!(self_float.ty().is_float());
2534        self.state.add_instruction(
2535            OpCode::FloatRound,
2536            &[dest_int.addressing(), self_float.addressing()],
2537            node,
2538            comment,
2539        );
2540    }
2541
2542    pub fn add_float_floor(
2543        &mut self,
2544        dest_int: &TypedRegister,
2545        self_float: &TypedRegister,
2546        node: &Node,
2547        comment: &str,
2548    ) {
2549        // TODO: bring this back //assert!(dest_int.ty().is_int());
2550        // TODO: bring this back //assert!(self_float.ty().is_float());
2551        self.state.add_instruction(
2552            OpCode::FloatFloor,
2553            &[dest_int.addressing(), self_float.addressing()],
2554            node,
2555            comment,
2556        );
2557    }
2558
2559    pub fn add_float_sqrt(
2560        &mut self,
2561        dest_float: &TypedRegister,
2562        self_float: &TypedRegister,
2563        node: &Node,
2564        comment: &str,
2565    ) {
2566        // TODO: bring this back //assert!(dest_float.ty().is_float());
2567        // TODO: bring this back //assert!(self_float.ty().is_float());
2568        self.state.add_instruction(
2569            OpCode::FloatSqrt,
2570            &[dest_float.addressing(), self_float.addressing()],
2571            node,
2572            comment,
2573        );
2574    }
2575
2576    pub fn add_float_sign(
2577        &mut self,
2578        dest_float: &TypedRegister,
2579        self_float: &TypedRegister,
2580        node: &Node,
2581        comment: &str,
2582    ) {
2583        assert!(dest_float.ty().is_float());
2584        assert!(self_float.ty().is_float());
2585        self.state.add_instruction(
2586            OpCode::FloatSign,
2587            &[dest_float.addressing(), self_float.addressing()],
2588            node,
2589            comment,
2590        );
2591    }
2592
2593    pub fn add_float_abs(
2594        &mut self,
2595        dest_float: &TypedRegister,
2596        self_float: &TypedRegister,
2597        node: &Node,
2598        comment: &str,
2599    ) {
2600        assert!(dest_float.ty().is_float());
2601        assert!(self_float.ty().is_float());
2602        self.state.add_instruction(
2603            OpCode::FloatAbs,
2604            &[dest_float.addressing(), self_float.addressing()],
2605            node,
2606            comment,
2607        );
2608    }
2609
2610    pub fn add_float_prnd(
2611        &mut self,
2612        dest_float: &TypedRegister,
2613        self_float: &TypedRegister,
2614        node: &Node,
2615        comment: &str,
2616    ) {
2617        assert!(dest_float.ty().is_float());
2618        assert!(self_float.ty().is_float());
2619        self.state.add_instruction(
2620            OpCode::FloatPseudoRandom,
2621            &[dest_float.addressing(), self_float.addressing()],
2622            node,
2623            comment,
2624        );
2625    }
2626
2627    pub fn add_float_sin(
2628        &mut self,
2629        dest_float: &TypedRegister,
2630        self_float: &TypedRegister,
2631        node: &Node,
2632        comment: &str,
2633    ) {
2634        assert!(dest_float.ty().is_float());
2635        assert!(self_float.ty().is_float());
2636        self.state.add_instruction(
2637            OpCode::FloatSin,
2638            &[dest_float.addressing(), self_float.addressing()],
2639            node,
2640            comment,
2641        );
2642    }
2643
2644    pub fn add_float_cos(
2645        &mut self,
2646        dest_float: &TypedRegister,
2647        self_float: &TypedRegister,
2648        node: &Node,
2649        comment: &str,
2650    ) {
2651        assert!(dest_float.ty().is_float());
2652        assert!(self_float.ty().is_float());
2653        self.state.add_instruction(
2654            OpCode::FloatCos,
2655            &[dest_float.addressing(), self_float.addressing()],
2656            node,
2657            comment,
2658        );
2659    }
2660
2661    pub fn add_float_acos(
2662        &mut self,
2663        dest_float: &TypedRegister,
2664        self_float: &TypedRegister,
2665        node: &Node,
2666        comment: &str,
2667    ) {
2668        assert!(dest_float.ty().is_float());
2669        assert!(self_float.ty().is_float());
2670        self.state.add_instruction(
2671            OpCode::FloatAcos,
2672            &[dest_float.addressing(), self_float.addressing()],
2673            node,
2674            comment,
2675        );
2676    }
2677
2678    pub fn add_float_asin(
2679        &mut self,
2680        dest_float: &TypedRegister,
2681        self_float: &TypedRegister,
2682        node: &Node,
2683        comment: &str,
2684    ) {
2685        assert!(dest_float.ty().is_float());
2686        assert!(self_float.ty().is_float());
2687        self.state.add_instruction(
2688            OpCode::FloatAsin,
2689            &[dest_float.addressing(), self_float.addressing()],
2690            node,
2691            comment,
2692        );
2693    }
2694
2695    pub fn add_float_atan2(
2696        &mut self,
2697        dest_float: &TypedRegister,
2698        self_float: &TypedRegister,
2699        node: &Node,
2700        comment: &str,
2701    ) {
2702        assert!(dest_float.ty().is_float());
2703        assert!(self_float.ty().is_float());
2704        self.state.add_instruction(
2705            OpCode::FloatAtan2,
2706            &[dest_float.addressing(), self_float.addressing()],
2707            node,
2708            comment,
2709        );
2710    }
2711
2712    pub fn add_float_min(
2713        &mut self,
2714        dest_float: &TypedRegister,
2715        self_float: &TypedRegister,
2716        other: &TypedRegister,
2717        node: &Node,
2718        comment: &str,
2719    ) {
2720        assert!(dest_float.ty().is_float());
2721        assert!(self_float.ty().is_float());
2722        self.state.add_instruction(
2723            OpCode::FloatMin,
2724            &[
2725                dest_float.addressing(),
2726                self_float.addressing(),
2727                other.addressing(),
2728            ],
2729            node,
2730            comment,
2731        );
2732    }
2733
2734    pub fn add_float_max(
2735        &mut self,
2736        dest_float: &TypedRegister,
2737        self_float: &TypedRegister,
2738        max_float: &TypedRegister,
2739        node: &Node,
2740        comment: &str,
2741    ) {
2742        assert!(dest_float.ty().is_float());
2743        assert!(self_float.ty().is_float());
2744        assert!(max_float.ty().is_float());
2745        self.state.add_instruction(
2746            OpCode::FloatMax,
2747            &[
2748                dest_float.addressing(),
2749                self_float.addressing(),
2750                max_float.addressing(),
2751            ],
2752            node,
2753            comment,
2754        );
2755    }
2756
2757    pub fn add_float_clamp(
2758        &mut self,
2759        dest_float: &TypedRegister,
2760        self_float: &TypedRegister,
2761        min_float: &TypedRegister,
2762        max_float: &TypedRegister,
2763        node: &Node,
2764        comment: &str,
2765    ) {
2766        assert!(dest_float.ty().is_float());
2767        assert!(self_float.ty().is_float());
2768        assert!(min_float.ty().is_float());
2769        assert!(max_float.ty().is_float());
2770
2771        self.state.add_instruction(
2772            OpCode::FloatClamp,
2773            &[
2774                dest_float.addressing(),
2775                min_float.addressing(),
2776                self_float.addressing(),
2777                max_float.addressing(),
2778            ],
2779            node,
2780            comment,
2781        );
2782    }
2783
2784    pub fn add_sparse_iter_init(
2785        &mut self,
2786        iterator_target: &TypedRegister,
2787        pointer_to_sparse_header: &TypedRegister,
2788        node: &Node,
2789        comment: &str,
2790    ) {
2791        self.state.add_instruction(
2792            OpCode::SparseIterInit,
2793            &[
2794                iterator_target.addressing(),
2795                pointer_to_sparse_header.addressing(),
2796            ],
2797            node,
2798            comment,
2799        );
2800    }
2801
2802    pub fn add_sparse_iter_next_placeholder(
2803        &mut self,
2804        iterator_target: &TypedRegister,
2805        closure_variable: &TypedRegister,
2806        node: &Node,
2807        comment: &str,
2808    ) -> PatchPosition {
2809        let position = self.position();
2810        self.state.add_instruction(
2811            OpCode::SparseIterNext,
2812            &[
2813                iterator_target.addressing(),
2814                closure_variable.addressing(),
2815                0,
2816                0,
2817            ],
2818            node,
2819            comment,
2820        );
2821        PatchPosition(position)
2822    }
2823
2824    pub fn add_sparse_iter_next_pair_placeholder(
2825        &mut self,
2826        iterator_target: &TypedRegister,
2827        closure_variable: &TypedRegister,
2828        closure_variable_b: &TypedRegister,
2829        node: &Node,
2830        comment: &str,
2831    ) -> PatchPosition {
2832        let position = self.position();
2833        self.state.add_instruction(
2834            OpCode::SparseIterNextPair,
2835            &[
2836                iterator_target.addressing(),
2837                closure_variable.addressing(),
2838                closure_variable_b.addressing(),
2839                0,
2840                0,
2841            ],
2842            node,
2843            comment,
2844        );
2845        PatchPosition(position)
2846    }
2847}