swamp_vm_instr_build/
lib.rs

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