swamp_vm_instr_build/
lib.rs

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