swamp_vm_instr_build/
lib.rs

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