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