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