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