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