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