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