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