1use 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
19pub 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 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 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 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 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 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 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 let instruction = &mut self.state.instructions[patch_position.0.0 as usize];
898 let effective_pc_address = patch_position.0 + ProgramCounterDelta(1); 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 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 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!(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 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 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!(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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!(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 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 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}