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