swamp_vm_instr_build/
lib.rs

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