1use crate::{
6 AggregateMemoryLocation, CountU16, FrameMemoryAddress, FrameMemoryRegion, FrameMemorySize,
7 HEAP_PTR_ON_FRAME_ALIGNMENT, HEAP_PTR_ON_FRAME_SIZE, HeapMemoryAddress, HeapMemoryRegion,
8 InstructionPosition, InstructionPositionOffset, InstructionRange, MAP_HEADER_ALIGNMENT,
9 MAP_HEADER_SIZE, MAP_ITERATOR_ALIGNMENT, MAP_ITERATOR_SIZE, MemoryAlignment, MemoryLocation,
10 MemoryOffset, MemorySize, ProgramCounterDelta, RANGE_HEADER_ALIGNMENT, RANGE_HEADER_SIZE,
11 RANGE_ITERATOR_ALIGNMENT, RANGE_ITERATOR_SIZE, RegIndex, STRING_PTR_ALIGNMENT, STRING_PTR_SIZE,
12 VEC_HEADER_SIZE, VEC_ITERATOR_ALIGNMENT, VEC_ITERATOR_SIZE, VEC_PTR_ALIGNMENT, VEC_PTR_SIZE,
13 align_to,
14};
15use seq_fmt::comma;
16use std::cmp::{Ordering, max};
17use std::fmt::{Debug, Display, Formatter, Write};
18use std::rc::Rc;
19use tracing::error;
20use yansi::Paint;
21
22pub type BasicTypeRef = Rc<BasicType>;
23
24#[derive(Clone, Debug)]
25pub struct OffsetMemoryItem {
26 pub offset: MemoryOffset,
27 pub size: MemorySize,
28 pub name: String,
29 pub ty: BasicTypeRef,
30}
31
32impl Display for OffsetMemoryItem {
33 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34 write!(f, "{}:{}", self.name, self.ty)
35 }
36}
37
38#[derive(Clone, Debug)]
39pub struct StructType {
40 pub name: String,
41 pub fields: Vec<OffsetMemoryItem>,
42 pub total_size: MemorySize,
43 pub max_alignment: MemoryAlignment,
44}
45
46impl Display for StructType {
47 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
48 write!(f, "{}", self.name)?;
49 for field in &self.fields {
50 write!(
51 f,
52 "{:04X}:{:X} {}:{}",
53 field.offset.0, field.size.0, field.name, field.ty
54 )?;
55 }
56 Ok(())
57 }
58}
59
60#[derive(Clone, Debug)]
61pub struct TupleType {
62 pub fields: Vec<OffsetMemoryItem>,
63 pub total_size: MemorySize,
64 pub max_alignment: MemoryAlignment,
65}
66
67impl TupleType {
68 #[must_use]
69 pub fn aligned_size_of_field(&self, field_index: usize) -> MemorySize {
70 let max_alignment: usize = self.max_alignment.into();
71 MemorySize(max(self.fields[field_index].size.0 as usize, max_alignment) as u32)
72 }
73}
74
75impl Display for TupleType {
76 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77 for field in &self.fields {
78 write!(f, "{:04X}:{:X} {}", field.offset.0, field.size.0, field.ty)?;
79 }
80 Ok(())
81 }
82}
83
84#[derive(Clone, Debug)]
85pub struct TaggedUnionVariant {
86 pub name: String, pub ty: BasicTypeRef, }
89
90impl Display for TaggedUnionVariant {
91 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
92 write!(f, "{}: {}", self.name, self.ty)
93 }
94}
95
96#[derive(Clone, Debug)]
97pub struct TaggedUnion {
98 pub name: String,
99 pub tag_offset: MemoryOffset, pub tag_alignment: MemoryAlignment,
101 pub tag_size: MemorySize,
102 pub payload_max_size: MemorySize,
103 pub max_payload_alignment: MemoryAlignment,
104 pub payload_offset: MemoryOffset,
105 pub variants: Vec<TaggedUnionVariant>,
106 pub total_size: MemorySize,
107 pub max_alignment: MemoryAlignment,
108}
109
110impl Display for TaggedUnion {
111 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
112 write!(f, "union {}:", self.name,)?;
113 for (offset, variant) in self.variants.iter().enumerate() {
114 writeln!(f, " {offset}: {variant}")?;
115 }
116 Ok(())
117 }
118}
119
120impl TaggedUnion {
121 #[must_use]
122 pub fn payload_offset(&self) -> MemoryOffset {
123 align_to(MemoryOffset(self.tag_size.0), self.max_alignment)
124 }
125}
126
127impl TaggedUnion {
128 #[must_use]
129 pub fn get_variant_by_index(&self, index: usize) -> &TaggedUnionVariant {
130 debug_assert!(
131 index < self.variants.len(),
132 "variant out of bounds {index} out of {}",
133 self.variants.len()
134 );
135 &self.variants[index]
136 }
137
138 #[must_use]
139 pub fn get_variant_as_offset_item(&self, index: usize) -> OffsetMemoryItem {
140 let variant = self.get_variant_by_index(index);
141 OffsetMemoryItem {
142 offset: self.payload_offset,
143 size: variant.ty.total_size,
144 name: variant.name.clone(),
145 ty: variant.ty.clone(),
146 }
147 }
148}
149
150#[derive(Debug, Clone)]
151pub struct FrameMemoryAttribute {
152 pub is_temporary: bool,
153}
154
155#[derive(Debug, Clone)]
156pub enum DecoratedOperandAccessKind {
157 WriteRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), ReadRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), ReadIndirectPointer(FrameMemoryAddress), DeltaPc(ProgramCounterDelta), AbsolutePc(InstructionPosition), MemorySize(MemorySize),
163 AbsoluteMemoryPosition(HeapMemoryAddress), WriteFrameMemoryAddress(FrameMemoryAddress), ReadFrameMemoryAddress(FrameMemoryAddress), WriteBaseRegWithOffset(RegIndex, MemoryOffset),
167 ReadBaseRegWithOffset(RegIndex, MemoryOffset),
168 ImmediateU8(u8),
169 ImmediateU16(u16),
170 ImmediateU32(u32),
171 CountU16(u16),
172 CountU8(u8),
173 WriteMask(u8),
174 ReadMask(u8),
175}
176
177impl DecoratedOperandAccessKind {
178 #[must_use]
179 pub const fn path_info(&self) -> Option<&PathInfo> {
180 match self {
181 Self::ReadRegister(addr, maybe_path_info, b) => maybe_path_info.as_ref(),
182 Self::WriteRegister(addr, maybe_path_info, _attr) => maybe_path_info.as_ref(),
183 _ => None,
184 }
185 }
186}
187
188pub struct DecoratedOperandOrigin {}
236
237pub struct DecoratedOperand {
238 pub kind: DecoratedOperandAccessKind,
239 pub origin: DecoratedOperandOrigin,
240}
241
242pub struct DecoratedOpcode {
243 pub name: String,
244 pub operands: Vec<DecoratedOperand>,
245}
246
247#[derive(Clone, Debug)]
248pub struct MemoryElement {
249 pub offset: MemoryOffset,
250 pub size: MemorySize,
251 pub alignment: MemoryAlignment,
252}
253
254#[derive(Clone, Debug)]
255pub enum BasicTypeKind {
256 Empty,
257 U8,
258 B8,
259 U16,
260 S32,
261 Fixed32,
262 U32,
263 InternalStringPointer,
264 InternalGridPointer,
265 Struct(StructType),
266 TaggedUnion(TaggedUnion),
267 Tuple(TupleType),
268 Optional(TaggedUnion),
269 InternalRangeHeader,
270
271 InternalVecIterator,
273 InternalMapIterator,
274 InternalSparseIterator,
275 InternalRangeIterator,
276 SliceView(BasicTypeRef),
278
279 FixedCapacityArray(BasicTypeRef, usize),
281 DynamicLengthVecView(BasicTypeRef),
282 VecStorage(BasicTypeRef, usize),
283 StackStorage(BasicTypeRef, usize),
284 QueueStorage(BasicTypeRef, usize),
285 MapStorage {
286 key_type: BasicTypeRef,
287 value_type: BasicTypeRef,
288 logical_limit: usize,
289 capacity: CountU16,
290 },
291 SparseView(BasicTypeRef),
292 SparseStorage(BasicTypeRef, usize),
293
294 DynamicLengthMapView(Box<OffsetMemoryItem>, Box<OffsetMemoryItem>),
295 GridView(BasicTypeRef),
297 GridStorage(BasicTypeRef, usize, usize),
298}
299
300impl BasicTypeKind {}
301
302impl BasicTypeKind {
303 pub(crate) const fn manifestation(&self) -> Manifestation {
304 if self.is_scalar() {
305 Manifestation::Scalar
306 } else {
307 Manifestation::Aggregate
308 }
309 }
310}
311
312pub enum Manifestation {
313 Scalar,
314 Aggregate,
315}
316
317impl Manifestation {
318 #[must_use]
319 pub const fn string(&self) -> &str {
320 match self {
321 Self::Scalar => "scalar",
322 Self::Aggregate => "aggregate",
323 }
324 }
325}
326
327impl Display for Manifestation {
328 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
329 write!(f, "{}", self.string())
330 }
331}
332
333impl BasicTypeKind {
334 pub(crate) const fn is_scalar(&self) -> bool {
335 matches!(
336 self,
337 Self::Empty
338 | Self::B8
339 | Self::U8
340 | Self::U16
341 | Self::S32
342 | Self::U32
343 | Self::Fixed32
344 | Self::InternalStringPointer
345 )
346 }
347
348 #[must_use]
349 pub const fn is_aggregate(&self) -> bool {
350 !self.is_scalar()
351 }
352
353 #[must_use]
354 pub const fn is_mutable_reference(&self) -> bool {
355 false }
357
358 pub(crate) const fn is_immutable(&self) -> bool {
359 !self.is_mutable_reference()
360 }
361
362 #[must_use]
363 pub const fn needs_copy_back_when_mutable(&self) -> bool {
364 self.is_scalar()
365 }
366
367 #[must_use]
368 pub fn union_info(&self) -> &TaggedUnion {
369 if let Self::TaggedUnion(union) = self {
370 union
371 } else {
372 panic!("wrong type")
373 }
374 }
375}
376
377impl Display for BasicTypeKind {
378 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
379 match self {
380 Self::Empty => write!(f, "()"),
381 Self::U8 => write!(f, "u8"),
382 Self::B8 => write!(f, "b8"),
383 Self::U16 => write!(f, "u16"),
384 Self::S32 => write!(f, "i32"),
385 Self::Fixed32 => write!(f, "Fixed(i32)"),
386 Self::U32 => write!(f, "u32"),
387 Self::InternalStringPointer => write!(f, "String"),
388 Self::InternalRangeHeader => write!(f, "Range"),
389 Self::FixedCapacityArray(item_type, size) => write!(f, "[{item_type}; {size}]"),
390 Self::DynamicLengthVecView(item_type) => write!(f, "Vec<{item_type}>"),
391 Self::VecStorage(item_type, size) => write!(f, "Vec<{item_type}, {size}>"),
392 Self::SparseView(item_type) => write!(f, "Sparse<{item_type}>"),
393 Self::GridView(item_type) => write!(f, "Grid<{item_type}>"),
394 Self::SparseStorage(item_type, size) => write!(f, "SparseStorage<{item_type}, {size}>"),
395 Self::StackStorage(item_type, size) => write!(f, "StackStorage<{item_type}, {size}>"),
396 Self::GridStorage(item_type, width, height) => {
397 write!(f, "GridStorage<{item_type}, ({width},{height})>")
398 }
399 Self::QueueStorage(item_type, size) => write!(f, "QueueStorage<{item_type}, {size}>"),
400 Self::MapStorage {
401 logical_limit: logical_size,
402 capacity,
403 key_type,
404 value_type,
405 ..
406 } => write!(
407 f,
408 "MapStorage<{key_type}, {value_type}, {logical_size} ({capacity})>",
409 ),
410 Self::DynamicLengthMapView(key, value) => write!(f, "Map<{key}, {value}>"),
411 Self::InternalGridPointer => write!(f, "Grid"),
412 Self::InternalVecIterator => write!(f, "Vec::Iterator"),
413 Self::InternalMapIterator => write!(f, "Map::Iterator"),
414 Self::InternalSparseIterator => write!(f, "Sparse::Iterator"),
415 Self::InternalRangeIterator => write!(f, "Range::Iterator"),
416 Self::Struct(struct_type) => write!(f, "{}", struct_type.name),
417 Self::TaggedUnion(union) => write!(f, "enum {}", union.name),
418 Self::Optional(optional) => write!(f, "{}?", optional.get_variant_by_index(1).ty),
419 Self::Tuple(tuple_type) => write!(f, "({})", comma(&tuple_type.fields)),
420 Self::SliceView(a) => write!(f, "slice<{}>", a.kind),
421 Self::DynamicLengthMapView(a, b) => write!(f, "slice_pair<{a}, {b}>"),
422 }
423 }
424}
425
426#[must_use]
502pub fn pointer_type_again() -> BasicTypeRef {
503 Rc::new(BasicType {
504 id: BasicTypeId::EMPTY,
505 kind: BasicTypeKind::InternalStringPointer, total_size: MemorySize(4),
507 max_alignment: MemoryAlignment::U32,
508 })
509}
510
511#[must_use]
513pub fn string_type() -> BasicTypeRef {
514 Rc::new(BasicType {
515 id: BasicTypeId::EMPTY,
516 kind: BasicTypeKind::InternalStringPointer,
517 total_size: STRING_PTR_SIZE,
518 max_alignment: STRING_PTR_ALIGNMENT,
519 })
520}
521#[must_use]
523pub fn int_type() -> BasicTypeRef {
524 Rc::new(BasicType {
525 id: BasicTypeId::EMPTY,
526 kind: BasicTypeKind::S32,
527 total_size: MemorySize(4),
528 max_alignment: MemoryAlignment::U32,
529 })
530}
531
532#[must_use]
534pub fn float_type() -> BasicTypeRef {
535 Rc::new(BasicType {
536 id: BasicTypeId::EMPTY,
537 kind: BasicTypeKind::Fixed32,
538 total_size: MemorySize(4),
539 max_alignment: MemoryAlignment::U32,
540 })
541}
542
543#[must_use]
545pub fn bytes_type() -> BasicTypeRef {
546 Rc::new(BasicType {
547 id: BasicTypeId::EMPTY,
548 kind: BasicTypeKind::Empty,
549 total_size: MemorySize(0),
550 max_alignment: MemoryAlignment::U32,
551 })
552}
553
554#[must_use]
555pub const fn range_type() -> BasicType {
556 BasicType {
557 id: BasicTypeId::EMPTY,
558 kind: BasicTypeKind::InternalRangeHeader,
559 total_size: RANGE_HEADER_SIZE,
560 max_alignment: RANGE_HEADER_ALIGNMENT,
561 }
562}
563
564#[must_use]
565pub const fn range_iter_type() -> BasicType {
566 BasicType {
567 id: BasicTypeId::EMPTY,
568 kind: BasicTypeKind::InternalRangeIterator,
569 total_size: RANGE_ITERATOR_SIZE,
570 max_alignment: RANGE_ITERATOR_ALIGNMENT,
571 }
572}
573
574#[must_use]
575pub fn slice_type() -> BasicType {
576 BasicType {
577 id: BasicTypeId::EMPTY,
578 kind: BasicTypeKind::SliceView(BasicTypeRef::from(u8_type())), total_size: MAP_HEADER_SIZE,
580 max_alignment: MAP_HEADER_ALIGNMENT,
581 }
582}
583
584#[must_use]
586pub fn unknown_type() -> BasicTypeRef {
587 Rc::new(BasicType {
588 id: BasicTypeId::EMPTY,
589 kind: BasicTypeKind::Empty,
590 total_size: MemorySize(0),
591 max_alignment: MemoryAlignment::U8,
592 })
593}
594
595#[must_use]
596pub fn vec_type() -> BasicType {
597 BasicType {
598 id: BasicTypeId::EMPTY,
599 kind: BasicTypeKind::DynamicLengthVecView(BasicTypeRef::from(unknown_type())),
600 total_size: VEC_PTR_SIZE,
601 max_alignment: VEC_PTR_ALIGNMENT,
602 }
603}
604
605#[must_use]
606pub const fn vec_iter_type() -> BasicType {
607 BasicType {
608 id: BasicTypeId::EMPTY,
609 kind: BasicTypeKind::InternalVecIterator,
610 total_size: VEC_ITERATOR_SIZE,
611 max_alignment: VEC_ITERATOR_ALIGNMENT,
612 }
613}
614
615#[must_use]
616pub fn map_type() -> BasicType {
617 BasicType {
618 id: BasicTypeId::EMPTY,
619 kind: BasicTypeKind::DynamicLengthMapView(
620 Box::from(OffsetMemoryItem {
621 offset: MemoryOffset(0),
622 size: MemorySize(0),
623 name: String::new(),
624 ty: Rc::new(BasicType {
625 id: BasicTypeId::EMPTY,
626 kind: BasicTypeKind::Empty,
627 total_size: MemorySize(0),
628 max_alignment: MemoryAlignment::U8,
629 }),
630 }),
631 Box::from(OffsetMemoryItem {
632 offset: MemoryOffset(0),
633 size: MemorySize(0),
634 name: String::new(),
635 ty: Rc::new(BasicType {
636 id: BasicTypeId::EMPTY,
637 kind: BasicTypeKind::Empty,
638 total_size: MemorySize(0),
639 max_alignment: MemoryAlignment::U8,
640 }),
641 }),
642 ),
643
644 total_size: MAP_HEADER_SIZE,
645 max_alignment: MAP_HEADER_ALIGNMENT,
646 }
647}
648
649#[must_use]
650pub const fn map_iter_type() -> BasicType {
651 BasicType {
652 id: BasicTypeId::EMPTY,
653 kind: BasicTypeKind::InternalMapIterator,
654 total_size: MAP_ITERATOR_SIZE,
655 max_alignment: MAP_ITERATOR_ALIGNMENT,
656 }
657}
658
659#[must_use]
661pub fn u32_type() -> BasicTypeRef {
662 Rc::new(BasicType {
663 id: BasicTypeId::EMPTY,
664 kind: BasicTypeKind::U32,
665 total_size: MemorySize(4),
666 max_alignment: MemoryAlignment::U32,
667 })
668}
669
670#[must_use]
671pub fn u16_type() -> BasicTypeRef {
672 Rc::new(BasicType {
673 id: BasicTypeId::EMPTY,
674 kind: BasicTypeKind::U16,
675 total_size: MemorySize(2),
676 max_alignment: MemoryAlignment::U16,
677 })
678}
679
680#[must_use]
682pub fn u8_type() -> BasicTypeRef {
683 Rc::new(BasicType {
684 id: BasicTypeId::EMPTY,
685 kind: BasicTypeKind::U8,
686 total_size: MemorySize(1),
687 max_alignment: MemoryAlignment::U8,
688 })
689}
690
691#[must_use]
693pub fn b8_type() -> BasicTypeRef {
694 Rc::new(BasicType {
695 id: BasicTypeId::EMPTY,
696 kind: BasicTypeKind::B8,
697 total_size: MemorySize(1),
698 max_alignment: MemoryAlignment::U8,
699 })
700}
701
702#[must_use]
705pub fn pointer_type() -> BasicTypeRef {
706 Rc::new(BasicType {
708 id: BasicTypeId::EMPTY,
709 kind: BasicTypeKind::InternalStringPointer, total_size: HEAP_PTR_ON_FRAME_SIZE,
711 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
712 })
713}
714
715#[derive(Clone, Debug)]
717pub struct HeapPlacedArray {
718 addr: HeapMemoryAddress,
719 byte_count: u32,
720}
721
722impl HeapPlacedArray {
723 #[must_use]
724 pub const fn new(addr: HeapMemoryAddress, byte_count: u32) -> Self {
725 Self { addr, byte_count }
726 }
727
728 #[must_use]
729 pub const fn addr(&self) -> HeapMemoryAddress {
730 self.addr
731 }
732
733 #[must_use]
734 pub const fn byte_count(&self) -> u32 {
735 self.byte_count
736 }
737}
738
739#[derive(Clone, Debug)]
741pub struct HeapPlacedType {
742 addr: HeapMemoryAddress,
743 ty: BasicTypeRef,
744}
745
746impl HeapPlacedType {
747 #[must_use]
748 pub const fn new(addr: HeapMemoryAddress, ty: BasicTypeRef) -> Self {
749 Self { addr, ty }
750 }
751
752 #[must_use]
753 pub fn region(&self) -> HeapMemoryRegion {
754 HeapMemoryRegion {
755 addr: self.addr,
756 size: self.ty.total_size,
757 }
758 }
759
760 #[must_use]
761 pub const fn addr(&self) -> HeapMemoryAddress {
762 self.addr
763 }
764
765 #[must_use]
766 pub fn size(&self) -> MemorySize {
767 self.ty.total_size
768 }
769
770 #[must_use]
771 pub const fn ty(&self) -> &BasicTypeRef {
772 &self.ty
773 }
774}
775
776#[derive(Clone, Debug)]
777pub enum Destination {
778 Unit, Register(TypedRegister),
780 Memory(MemoryLocation),
781}
782
783impl Destination {
784 #[must_use]
785 pub const fn vm_type(&self) -> Option<&VmType> {
786 match self {
787 Self::Unit => None,
788 Self::Register(reg) => Some(®.ty),
789 Self::Memory(mem) => Some(&mem.ty),
790 }
791 }
792}
793
794impl Display for Destination {
795 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
796 match self {
797 Self::Unit => write!(f, "unit ()"),
798 Self::Register(reg) => write!(f, "reg: {reg}"),
799 Self::Memory(memory_location) => write!(f, "memory_location {memory_location:?}"),
800 }
801 }
802}
803
804impl Destination {
805 #[must_use]
806 pub const fn memory_location(&self) -> Option<&MemoryLocation> {
807 match self {
808 Self::Unit => None,
809 Self::Register(_) => None,
810 Self::Memory(memory_location) => Some(memory_location),
811 }
812 }
813}
814
815impl Destination {
816 #[must_use]
817 pub fn add_offset(&self, offset: MemoryOffset, vm_type: VmType) -> Self {
818 match self {
819 Self::Unit => {
820 panic!("add_offset")
821 }
822 Self::Register(reg) => {
823 if reg.ty.is_aggregate() {
824 Self::Memory(MemoryLocation {
825 base_ptr_reg: reg.clone(),
826 offset,
827 ty: vm_type,
828 })
829 } else {
830 panic!(
831 "can not add offset to a register since it wasn't an aggregate {}",
832 reg.ty
833 )
834 }
835 }
836 Self::Memory(memory_location) => Self::Memory(MemoryLocation {
837 base_ptr_reg: memory_location.base_ptr_reg.clone(),
838 offset: memory_location.offset + offset,
839 ty: vm_type,
840 }),
841 }
842 }
843 #[must_use]
844 pub const fn new_unit() -> Self {
845 Self::Unit
846 }
847 #[must_use]
848 pub const fn new_reg(register: TypedRegister) -> Self {
849 Self::Register(register)
850 }
851 #[must_use]
852 pub const fn new_location(memory_location: MemoryLocation) -> Self {
853 Self::Memory(memory_location)
854 }
855
856 #[must_use]
857 pub const fn is_unit(&self) -> bool {
858 matches!(self, Self::Unit)
859 }
860 #[must_use]
861 pub const fn is_memory_location(&self) -> bool {
862 matches!(self, Self::Memory(_))
863 }
864
865 #[must_use]
866 pub const fn is_register(&self) -> bool {
867 matches!(self, Self::Register(_))
868 }
869 #[must_use]
870 pub fn ty(&self) -> &BasicTypeRef {
871 match self {
872 Self::Unit => panic!("no type"),
873 Self::Register(reg) => ®.ty.basic_type,
874 Self::Memory(location) => &location.ty.basic_type,
875 }
876 }
877
878 #[must_use]
879 pub const fn register(&self) -> Option<&TypedRegister> {
880 match self {
881 Self::Register(reg) => Some(reg),
882 _ => None,
883 }
884 }
885
886 #[must_use]
887 pub const fn register_involved_in_destination(&self) -> Option<&TypedRegister> {
888 match self {
889 Self::Register(reg) => Some(reg),
890 Self::Memory(memory_location) => Some(memory_location.reg()),
891 Self::Unit => None,
892 }
893 }
894
895 #[must_use]
896 pub fn grab_register(&self) -> &TypedRegister {
897 match self {
898 Self::Register(reg) => reg,
899 Self::Memory(_) => {
900 panic!("assumed it would be a register")
901 }
902 Self::Unit => panic!("assumed it would be a register, but was unit"),
903 }
904 }
905
906 #[must_use]
907 pub fn grab_memory_location(&self) -> &MemoryLocation {
908 match self {
909 Self::Register(reg) => panic!("assumed it was a memory location"),
910 Self::Memory(location) => location,
911 Self::Unit => {
912 panic!("assumed it would be a memory location, but was unit")
913 }
914 }
915 }
916
917 #[must_use]
920 pub fn memory_location_or_pointer_reg(&self) -> MemoryLocation {
921 match self {
922 Self::Register(reg) => MemoryLocation {
923 base_ptr_reg: reg.clone(),
924 offset: MemoryOffset(0),
925 ty: reg.ty.clone(),
926 },
927 Self::Memory(location) => location.clone(),
928 Self::Unit => {
929 panic!("assumed it would be a memory location, but was unit")
930 }
931 }
932 }
933
934 #[must_use]
935 pub fn grab_aggregate_memory_location_or_pointer_reg(&self) -> AggregateMemoryLocation {
936 AggregateMemoryLocation {
937 location: self.memory_location_or_pointer_reg(),
938 }
939 }
940 #[must_use]
941 pub fn grab_aggregate_memory_location(&self) -> AggregateMemoryLocation {
942 AggregateMemoryLocation {
943 location: self.grab_memory_location().clone(),
944 }
945 }
946}
947
948#[derive(Clone)]
949pub struct TypedRegister {
950 pub index: u8,
951 pub ty: VmType,
952 pub comment: String,
953}
954
955impl PartialEq<Self> for TypedRegister {
956 fn eq(&self, other: &Self) -> bool {
957 self.index == other.index
958 }
959}
960
961impl Eq for TypedRegister {}
962
963impl Ord for TypedRegister {
964 fn cmp(&self, other: &Self) -> Ordering {
965 self.index.cmp(&other.index)
966 }
967}
968impl PartialOrd<Self> for TypedRegister {
969 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
970 self.index.partial_cmp(&other.index)
971 }
972}
973
974impl TypedRegister {
975 #[must_use]
976 pub fn comment(&self) -> &str {
977 &self.comment
978 }
979}
980
981impl TypedRegister {
982 #[must_use]
983 pub fn new_empty_reserved() -> Self {
984 Self {
985 index: 0xff,
986 ty: VmType::new_unknown_placement(BasicTypeRef::from(unknown_type())),
987 comment: String::new(),
988 }
989 }
990}
991
992impl TypedRegister {
993 #[must_use]
994 pub fn final_type(&self) -> BasicTypeRef {
995 self.ty.basic_type.clone()
996 }
997}
998
999impl Debug for TypedRegister {
1000 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1001 write!(f, "r{} ({} - {})", self.index, self.ty, self.comment)
1002 }
1003}
1004
1005impl Display for TypedRegister {
1006 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1007 write!(f, "r{}", self.index)
1008 }
1009}
1010
1011impl TypedRegister {
1012 #[must_use]
1013 pub fn new_frame_placed(index: u8, frame_placed: FramePlacedType) -> Self {
1014 Self {
1015 index,
1016 ty: VmType::new_frame_placed(frame_placed),
1017 comment: String::new(),
1018 }
1019 }
1020
1021 #[must_use]
1022 pub const fn new_vm_type(index: u8, ty: VmType) -> Self {
1023 Self {
1024 index,
1025 ty,
1026 comment: String::new(),
1027 }
1028 }
1029
1030 pub fn with_comment(&mut self, comment: &str) -> &mut Self {
1031 self.comment = comment.to_string();
1032 self
1033 }
1034 #[must_use]
1035 pub const fn addressing(&self) -> u8 {
1036 self.index
1037 }
1038
1039 #[must_use]
1040 pub const fn ty(&self) -> &BasicTypeRef {
1041 &self.ty.basic_type
1042 }
1043
1044 #[must_use]
1045 pub fn frame_placed(&self) -> FramePlacedType {
1046 if let Some(fp) = self.ty.frame_placed_type() {
1047 fp
1048 } else {
1049 panic!("")
1050 }
1051 }
1052
1053 #[must_use]
1054 pub fn size(&self) -> MemorySize {
1055 self.ty.basic_type.total_size
1056 }
1057
1058 #[must_use]
1059 pub fn addr(&self) -> FrameMemoryAddress {
1060 self.frame_placed().addr
1061 }
1062
1063 #[must_use]
1064 pub fn region(&self) -> FrameMemoryRegion {
1065 self.frame_placed().region()
1066 }
1067
1068 #[must_use]
1069 pub fn underlying(&self) -> BasicTypeRef {
1070 self.ty.basic_type.clone()
1071 }
1072}
1073
1074#[derive(Clone, Debug)]
1075pub enum VmTypeOrigin {
1076 Unknown,
1077 InsideReg,
1078 Frame(FrameMemoryRegion),
1079 Heap(HeapMemoryRegion), }
1081
1082impl Display for VmTypeOrigin {
1083 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1084 match self {
1085 Self::Unknown => Ok(()),
1086 Self::Frame(region) => write!(f, "frame {region}"),
1087 Self::Heap(region) => write!(f, "heap {region}"),
1088 Self::InsideReg => write!(f, "reg"),
1089 }
1090 }
1091}
1092
1093#[derive(Clone, Debug)]
1094pub struct VmType {
1095 pub basic_type: BasicTypeRef,
1096 pub origin: VmTypeOrigin,
1097}
1098
1099impl VmType {}
1100
1101impl VmType {
1102 #[must_use]
1103 pub fn is_collection_like(&self) -> bool {
1104 self.basic_type.is_collection_like()
1105 }
1106}
1107
1108impl VmType {
1109 #[must_use]
1110 pub fn is_mutable_primitive(&self) -> bool {
1111 self.basic_type.is_mutable_reference()
1112 && self
1113 .basic_type
1114 .should_be_copied_back_when_mutable_arg_or_return()
1115 }
1116
1117 #[must_use]
1118 pub fn element_count_always_same_as_capacity(&self) -> bool {
1119 self.basic_type.element_count_always_same_as_capacity()
1120 }
1121}
1122
1123impl Display for VmType {
1124 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1125 write!(
1126 f,
1127 "{} {} {}",
1128 tinter::bright_green(&self.basic_type),
1129 self.origin,
1130 tinter::bright_magenta(self.manifestation())
1131 )
1132 }
1133}
1134
1135impl VmType {
1136 #[must_use]
1137 pub fn new_frame_placed(frame_placed: FramePlacedType) -> Self {
1138 Self {
1139 basic_type: frame_placed.ty.clone(),
1140 origin: VmTypeOrigin::Frame(frame_placed.region()),
1141 }
1142 }
1143 #[must_use]
1144 pub fn is_immutable(&self) -> bool {
1145 self.basic_type.kind.is_immutable()
1146 }
1147
1148 #[must_use]
1149 pub fn manifestation(&self) -> Manifestation {
1150 self.basic_type.manifestation()
1151 }
1152
1153 #[must_use]
1154 pub const fn new_heap_placement(
1155 basic_type: BasicTypeRef,
1156 heap_region: HeapMemoryRegion,
1157 ) -> Self {
1158 Self {
1159 basic_type,
1160 origin: VmTypeOrigin::Heap(heap_region),
1161 }
1162 }
1163
1164 #[must_use]
1165 pub const fn new_contained_in_register(basic_type: BasicTypeRef) -> Self {
1166 Self {
1167 basic_type,
1168 origin: VmTypeOrigin::InsideReg,
1169 }
1170 }
1171
1172 #[must_use]
1173 pub const fn new_unknown_placement(basic_type: BasicTypeRef) -> Self {
1174 Self {
1175 basic_type,
1176 origin: VmTypeOrigin::Unknown,
1177 }
1178 }
1179
1180 #[must_use]
1181 pub const fn new_basic_with_origin(basic_type: BasicTypeRef, origin: VmTypeOrigin) -> Self {
1182 Self { basic_type, origin }
1183 }
1184
1185 #[must_use]
1186 pub fn frame_placed_type(&self) -> Option<FramePlacedType> {
1187 if let VmTypeOrigin::Frame(region) = self.origin {
1188 Some(FramePlacedType {
1189 addr: region.addr,
1190 ty: self.basic_type.clone(),
1191 })
1192 } else {
1193 None
1194 }
1195 }
1196
1197 #[must_use]
1198 pub fn is_mutable_reference_semantic(&self) -> bool {
1199 self.basic_type.is_mutable_reference()
1200 }
1201
1202 #[must_use]
1203 pub fn is_aggregate(&self) -> bool {
1204 self.basic_type.is_aggregate()
1205 }
1206
1207 #[must_use]
1208 pub fn is_scalar(&self) -> bool {
1209 self.basic_type.is_scalar()
1210 }
1211
1212 #[must_use]
1213 pub fn needs_allocated_space_for_return_in_reg0(&self) -> bool {
1214 self.basic_type.is_aggregate()
1215 && !matches!(self.basic_type.kind, BasicTypeKind::InternalStringPointer)
1216 }
1217
1218 #[must_use]
1219 pub fn needs_copy_back_for_mutable(&self) -> bool {
1220 !self.basic_type.is_aggregate()
1221 || matches!(self.basic_type.kind, BasicTypeKind::InternalStringPointer)
1222 }
1223 #[must_use]
1224 pub const fn basic_type(&self) -> &BasicTypeRef {
1225 &self.basic_type
1226 }
1227}
1228
1229#[derive(Clone, Debug)]
1231pub struct FramePlacedType {
1232 addr: FrameMemoryAddress,
1233 ty: BasicTypeRef,
1234}
1235
1236const FRAME_MEMORY_ADDRESS_IS_POINTER_TAG: u16 = 0x8000;
1237
1238impl FramePlacedType {
1239 #[must_use]
1240 pub const fn new(addr: FrameMemoryAddress, ty: BasicTypeRef) -> Self {
1241 Self { addr, ty }
1242 }
1243
1244 #[must_use]
1245 pub fn region(&self) -> FrameMemoryRegion {
1246 FrameMemoryRegion {
1247 addr: self.addr,
1248 size: self.ty.total_size,
1249 }
1250 }
1251
1252 #[must_use]
1253 pub const fn addr(&self) -> FrameMemoryAddress {
1254 self.addr
1255 }
1256
1257 #[must_use]
1258 pub fn size(&self) -> MemorySize {
1259 self.ty.total_size
1260 }
1261
1262 #[must_use]
1263 pub fn ty(&self) -> &BasicType {
1264 &self.ty
1265 }
1266
1267 #[must_use]
1268 pub fn final_type(&self) -> BasicTypeRef {
1269 self.ty.clone()
1270 }
1271
1272 #[must_use]
1273 pub fn move_with_offset(&self, offset: MemoryOffset, ty: BasicTypeRef) -> Self {
1274 Self {
1275 addr: self.addr + offset,
1276 ty,
1277 }
1278 }
1279
1280 #[must_use]
1281 pub fn move_to_field(&self, index: usize) -> Self {
1282 let offset_info = self.ty.get_field_offset(index).unwrap();
1283 Self {
1284 addr: self.addr + offset_info.offset,
1285 ty: offset_info.ty.clone(),
1286 }
1287 }
1288
1289 #[must_use]
1290 pub fn move_to_optional_some_payload(&self) -> Self {
1291 self.move_to_optional_payload_variant(1)
1292 }
1293
1294 #[must_use]
1295 pub fn move_to_optional_none_payload(&self) -> Self {
1296 self.move_to_optional_payload_variant(0)
1297 }
1298
1299 #[must_use]
1300 pub fn move_to_optional_payload_variant(&self, index: usize) -> Self {
1301 let optional_info = self.ty.optional_info().unwrap();
1302 Self::new(
1303 self.addr + optional_info.payload_offset,
1304 optional_info.get_variant_by_index(index).ty.clone(),
1305 )
1306 }
1307
1308 #[must_use]
1309 pub fn move_to_optional_tag(&self) -> Self {
1310 let optional_info = self.ty().optional_info().unwrap();
1311
1312 let addr = self.addr() + optional_info.tag_offset;
1313 assert_eq!(optional_info.tag_size.0, 1);
1314
1315 let tag_type = Rc::new(BasicType {
1316 id: BasicTypeId::EMPTY,
1317 kind: BasicTypeKind::B8,
1318 total_size: MemorySize(1),
1319 max_alignment: MemoryAlignment::U8,
1320 });
1321
1322 Self::new(addr, tag_type)
1323 }
1324}
1325
1326pub enum BoundsCheck {
1327 KnownSizeAtCompileTime(u16),
1328 RegisterWithMaxCount(TypedRegister),
1329}
1330
1331#[derive(Clone, Debug)]
1332pub struct BasicTypeId(pub u32);
1333
1334impl BasicTypeId {
1335 pub const EMPTY: Self = Self(0xffff_ffff);
1336}
1337
1338#[derive(Clone, Debug)]
1339pub struct BasicType {
1340 pub id: BasicTypeId,
1341 pub kind: BasicTypeKind,
1342 pub total_size: MemorySize,
1343 pub max_alignment: MemoryAlignment,
1344}
1345
1346impl BasicType {
1347 #[must_use]
1348 pub const fn is_vec_like(&self) -> bool {
1349 matches!(
1350 self.kind,
1351 BasicTypeKind::VecStorage(..)
1352 | BasicTypeKind::SliceView(..)
1353 | BasicTypeKind::FixedCapacityArray(..)
1354 | BasicTypeKind::DynamicLengthVecView(..)
1355 )
1356 }
1357
1358 #[must_use]
1359 pub const fn is_collection(&self) -> bool {
1360 matches!(
1361 self.kind,
1362 BasicTypeKind::VecStorage(..)
1363 | BasicTypeKind::SliceView(..)
1364 | BasicTypeKind::FixedCapacityArray(..)
1365 | BasicTypeKind::DynamicLengthVecView(..)
1366 | BasicTypeKind::MapStorage { .. }
1367 | BasicTypeKind::DynamicLengthMapView(..)
1368 | BasicTypeKind::GridStorage(..)
1369 | BasicTypeKind::GridView(..)
1370 | BasicTypeKind::SparseStorage(..)
1371 | BasicTypeKind::SparseView(..)
1372 | BasicTypeKind::StackStorage(..)
1373 | BasicTypeKind::QueueStorage(..)
1374 )
1375 }
1376
1377 #[must_use]
1378 pub fn might_contain_collections(&self) -> bool {
1379 match &self.kind {
1380 BasicTypeKind::Struct(struct_type) => struct_type
1381 .fields
1382 .iter()
1383 .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1384 BasicTypeKind::Tuple(tuple_type) => tuple_type
1385 .fields
1386 .iter()
1387 .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1388 BasicTypeKind::TaggedUnion(union_type) => union_type.variants.iter().any(|variant| {
1389 variant.ty.is_collection() || variant.ty.might_contain_collections()
1390 }),
1391 BasicTypeKind::Optional(union_type) => union_type.variants.iter().any(|variant| {
1392 variant.ty.is_collection() || variant.ty.might_contain_collections()
1393 }),
1394 BasicTypeKind::MapStorage { value_type, .. } => {
1395 value_type.is_collection() || value_type.might_contain_collections()
1396 }
1397 _ => false,
1398 }
1399 }
1400
1401 pub(crate) const fn element_count_always_same_as_capacity(&self) -> bool {
1402 matches!(self.kind, BasicTypeKind::FixedCapacityArray(..))
1403 }
1404 #[must_use]
1405 pub const fn is_collection_like(&self) -> bool {
1406 matches!(
1407 self.kind,
1408 BasicTypeKind::FixedCapacityArray(..)
1409 | BasicTypeKind::VecStorage(..)
1411 | BasicTypeKind::DynamicLengthVecView(..)
1412 | BasicTypeKind::MapStorage { ..}
1414 | BasicTypeKind::DynamicLengthMapView(..)
1415 )
1416 }
1417 #[must_use]
1418 pub const fn is_collection_with_capacity(&self) -> bool {
1419 matches!(
1420 self.kind,
1421 BasicTypeKind::FixedCapacityArray(..)
1422 | BasicTypeKind::VecStorage(..)
1424 | BasicTypeKind::MapStorage { ..}
1426 )
1427 }
1428
1429 #[must_use]
1430
1431 pub const fn get_vec_slice_like_capacity(&self) -> Option<MemorySize> {
1432 match &self.kind {
1433 BasicTypeKind::FixedCapacityArray(_element_type, capacity) => {
1434 Some(MemorySize(*capacity as u32))
1435 }
1436 BasicTypeKind::VecStorage(_element_type, capacity) => {
1437 Some(MemorySize(*capacity as u32))
1438 }
1439 _ => None,
1440 }
1441 }
1442}
1443
1444impl BasicType {
1445 pub(crate) const fn manifestation(&self) -> Manifestation {
1446 self.kind.manifestation()
1447 }
1448}
1449
1450impl BasicType {
1451 #[must_use]
1452 pub const fn should_be_copied_back_when_mutable_arg_or_return(&self) -> bool {
1453 !self.is_aggregate()
1454 }
1455}
1456
1457impl BasicType {
1458 #[must_use]
1459 pub fn referenced_type(&self) -> &Self {
1460 panic!("referenced_type() is no longer supported - MutablePointer was removed")
1462 }
1463}
1464
1465impl BasicType {
1466 #[must_use]
1467 pub const fn make_pointer(&self) -> Self {
1468 Self {
1470 id: BasicTypeId::EMPTY,
1471 kind: BasicTypeKind::InternalStringPointer,
1472 total_size: HEAP_PTR_ON_FRAME_SIZE,
1473 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1474 }
1475 }
1476}
1477
1478impl BasicType {}
1479
1480impl BasicType {
1481 #[must_use]
1482 pub fn get_variant(&self, variant_index: usize) -> &TaggedUnionVariant {
1483 match &self.kind {
1484 BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => {
1485 tagged.get_variant_by_index(variant_index)
1486 }
1487 _ => panic!("type is not a tagged union"),
1488 }
1489 }
1490}
1491
1492impl BasicType {
1493 #[must_use]
1494 pub const fn is_scalar(&self) -> bool {
1495 self.kind.is_scalar()
1496 }
1497
1498 #[must_use]
1499 pub const fn is_mutable_reference(&self) -> bool {
1500 self.kind.is_mutable_reference()
1501 }
1502}
1503
1504impl BasicType {
1505 #[must_use]
1506 pub const fn unwrap_info(
1507 &self,
1508 ) -> Option<(MemoryOffset, MemorySize, MemoryOffset, MemorySize)> {
1509 match &self.kind {
1510 BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => Some((
1511 tagged.tag_offset,
1512 tagged.tag_size,
1513 tagged.payload_offset,
1514 tagged.payload_max_size,
1515 )),
1516 _ => None,
1517 }
1518 }
1519
1520 #[must_use]
1521 pub fn union_info(&self) -> &TaggedUnion {
1522 self.kind.union_info()
1523 }
1524
1525 #[must_use]
1526 pub fn create_mutable_pointer(&self) -> Self {
1527 debug_assert!(!self.is_mutable_reference());
1529
1530 Self {
1531 id: BasicTypeId::EMPTY,
1532 kind: BasicTypeKind::InternalStringPointer,
1533 total_size: HEAP_PTR_ON_FRAME_SIZE,
1534 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1535 }
1536 }
1537
1538 #[must_use]
1539 pub const fn is_aggregate(&self) -> bool {
1540 self.kind.is_aggregate()
1541 }
1542
1543 #[must_use]
1544 pub const fn optional_info(&self) -> Option<&TaggedUnion> {
1545 match &self.kind {
1546 BasicTypeKind::Optional(tagged_union) => Some(tagged_union),
1547 _ => None,
1548 }
1549 }
1550
1551 #[must_use]
1552 pub fn get_field_offset(&self, index: usize) -> Option<&OffsetMemoryItem> {
1553 match &self.kind {
1554 BasicTypeKind::Struct(struct_type) => struct_type.fields.get(index),
1555 BasicTypeKind::Tuple(tuple_type) => tuple_type.fields.get(index),
1556 _ => {
1557 error!(?self, "not a type with fields");
1558 None
1559 }
1560 }
1561 }
1562
1563 #[must_use]
1564 pub fn bucket_size_for_vec_like(&self) -> Option<MemorySize> {
1565 match &self.kind {
1566 BasicTypeKind::FixedCapacityArray(inner, capacity) => Some(inner.total_size),
1567 BasicTypeKind::SliceView(inner) => Some(inner.total_size),
1568 BasicTypeKind::VecStorage(inner, _) => Some(inner.total_size),
1569 BasicTypeKind::DynamicLengthVecView(inner) => Some(inner.total_size),
1570 _ => None,
1571 }
1572 }
1573
1574 #[must_use]
1575 pub const fn element(&self) -> Option<&BasicTypeRef> {
1576 match &self.kind {
1577 BasicTypeKind::StackStorage(inner, _)
1578 | BasicTypeKind::GridView(inner)
1579 | BasicTypeKind::GridStorage(inner, ..)
1580 | BasicTypeKind::SparseStorage(inner, _)
1581 | BasicTypeKind::SparseView(inner)
1582 | BasicTypeKind::QueueStorage(inner, _)
1583 | BasicTypeKind::DynamicLengthVecView(inner)
1584 | BasicTypeKind::FixedCapacityArray(inner, _)
1585 | BasicTypeKind::VecStorage(inner, _)
1586 | BasicTypeKind::SliceView(inner) => Some(inner),
1587 _ => None,
1588 }
1589 }
1590
1591 #[must_use]
1592 pub const fn header_size_for_vec_like(&self) -> Option<MemorySize> {
1593 match &self.kind {
1594 BasicTypeKind::SliceView(_)
1595 | BasicTypeKind::DynamicLengthVecView(_)
1596 | BasicTypeKind::VecStorage(_, _) => Some(VEC_HEADER_SIZE),
1597 BasicTypeKind::DynamicLengthMapView(..) => Some(MAP_HEADER_SIZE),
1598 _ => None,
1599 }
1600 }
1601
1602 #[must_use]
1603 pub fn element_pair(&self) -> Option<(&OffsetMemoryItem, &OffsetMemoryItem)> {
1604 match &self.kind {
1605 BasicTypeKind::DynamicLengthMapView(a, b) => Some((a, b)),
1606 _ => None,
1607 }
1608 }
1609
1610 #[must_use]
1611 pub fn is_int(&self) -> bool {
1612 matches!(self.kind, BasicTypeKind::S32)
1613 && self.total_size.0 == 4
1614 && self.max_alignment == MemoryAlignment::U32
1615 }
1616 #[must_use]
1617 pub fn is_float(&self) -> bool {
1618 matches!(self.kind, BasicTypeKind::Fixed32)
1619 && self.total_size.0 == 4
1620 && self.max_alignment == MemoryAlignment::U32
1621 }
1622
1623 #[must_use]
1624 pub fn is_str(&self) -> bool {
1625 matches!(self.kind, BasicTypeKind::InternalStringPointer)
1626 && self.total_size == STRING_PTR_SIZE
1627 && self.max_alignment == STRING_PTR_ALIGNMENT
1628 }
1629
1630 #[must_use]
1631 pub fn is_bool(&self) -> bool {
1632 matches!(self.kind, BasicTypeKind::B8)
1633 && self.total_size.0 == 1
1634 && self.max_alignment == MemoryAlignment::U8
1635 }
1636}
1637
1638impl Display for BasicType {
1639 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1640 write!(f, "{}", self.kind)
1641 }
1642}
1643
1644#[derive(Clone, Debug)]
1645pub struct VariableInfo {
1646 pub is_mutable: bool,
1647 pub name: String,
1648}
1649
1650impl Display for VariableInfo {
1651 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1652 let mut_prefix = if self.is_mutable { "mut " } else { "" };
1653
1654 let name = &self.name;
1655 write!(f, "{mut_prefix}{name}")
1656 }
1657}
1658
1659#[derive(Clone, Debug)]
1660pub enum VariableInfoKind {
1661 Variable(VariableInfo),
1662 Parameter(VariableInfo),
1663 Return,
1664}
1665
1666impl Display for VariableInfoKind {
1667 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1668 match self {
1669 Self::Variable(var_info) => {
1670 write!(f, "{} {var_info}", "var:".white())
1671 }
1672 Self::Parameter(var_info) => {
1673 write!(f, "{} {var_info}", "param:".white())
1674 }
1675 Self::Return => {
1676 write!(f, "{}", "return".white())
1677 }
1678 }
1679 }
1680}
1681
1682#[derive(Clone, Debug)]
1683pub struct FrameAddressInfo {
1684 pub kind: VariableInfoKind,
1685 pub frame_placed_type: FramePlacedType,
1686}
1687
1688#[derive(Clone, Debug)]
1689pub struct VariableRegister {
1690 pub unique_id_in_function: usize,
1691 pub variable: VariableInfo,
1692 pub register: TypedRegister,
1693}
1694
1695impl Display for VariableRegister {
1696 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1697 write!(f, "{}: {}", self.register, self.variable)
1698 }
1699}
1700
1701#[derive(Clone, Debug)]
1702pub struct VariableRegisterRange {
1703 pub start: u8,
1704 pub count: u8,
1705}
1706
1707#[derive(Clone, Debug)]
1708pub struct FrameMemoryInfo {
1709 pub infos: Vec<FrameAddressInfo>,
1710 pub total_frame_size: FrameMemorySize,
1711 pub variable_frame_size: FrameMemorySize,
1712 pub variable_registers: Vec<VariableRegister>,
1713 pub frame_size_for_variables_except_temp: FrameMemorySize,
1715}
1716
1717#[derive(Clone)]
1718pub struct FrameRelativeInfo {
1719 pub frame_memory_region: FrameMemoryRegion,
1720 pub kind: FrameAddressInfo,
1721}
1722
1723#[derive(Clone, Debug)]
1724pub struct PathInfo {
1725 pub steps: Vec<PathStep>,
1726}
1727
1728impl PathInfo {
1729 #[must_use]
1730 pub fn convert_to_string(&self) -> String {
1731 let path = &self.steps;
1732
1733 let last = path.last().unwrap();
1734
1735 let names: Vec<_> = path.iter().map(|x| x.item.name.to_string()).collect();
1736
1737 let types: Vec<_> = path.iter().map(|x| format!("{}", x.item.ty.kind)).collect();
1738
1739 let names_path = names.join(".");
1740 let types_path = types.join("->");
1741
1742 format!(
1743 "{:04X}:{:X} {} ({})",
1744 (last.origin + last.item.offset).0.bright_cyan(),
1745 last.item.ty.total_size.0.yellow(),
1746 names_path.bright_blue(),
1747 types_path.yellow(),
1748 )
1749 }
1750}
1751
1752#[derive(Clone, Debug)]
1753pub struct PathStep {
1754 pub item: OffsetMemoryItem,
1755 pub origin: FrameMemoryAddress,
1756}
1757
1758impl PathStep {
1759 #[must_use]
1760 pub const fn absolute_address(&self) -> FrameMemoryAddress {
1761 FrameMemoryAddress(self.origin.0 + self.item.offset.0)
1762 }
1763}
1764
1765impl FrameMemoryInfo {
1766 #[must_use]
1767 pub const fn size(&self) -> FrameMemorySize {
1768 self.total_frame_size
1769 }
1770
1771 #[must_use]
1773 pub fn find_path_to_address_items(&self, target: FrameMemoryAddress) -> Option<PathInfo> {
1774 for info in &self.infos {
1775 let root_item = OffsetMemoryItem {
1777 offset: MemoryOffset(0),
1778 size: info.frame_placed_type.ty.total_size,
1779 name: info.kind.to_string(),
1780 ty: info.frame_placed_type.ty.clone(),
1781 };
1782 let base_addr = info.frame_placed_type.addr;
1783 let mut path = Vec::new();
1784 if find_in_item(&root_item, base_addr, target, &mut path) {
1785 return Some(PathInfo { steps: path });
1786 }
1787 }
1788 None
1789 }
1790}
1791fn find_in_item(
1792 item: &OffsetMemoryItem,
1793 base_addr: FrameMemoryAddress,
1794 target: FrameMemoryAddress,
1795 path: &mut Vec<PathStep>,
1796) -> bool {
1797 let item_addr = FrameMemoryAddress(base_addr.0 + item.offset.0);
1798 path.push(PathStep {
1799 item: item.clone(),
1800 origin: base_addr,
1801 });
1802
1803 if item_addr.0 == target.0 {
1804 return true;
1805 }
1806
1807 match &item.ty.kind {
1808 BasicTypeKind::Struct(st) => {
1809 for field in &st.fields {
1810 if find_in_item(field, item_addr, target, path) {
1811 return true;
1812 }
1813 }
1814 }
1815 BasicTypeKind::Tuple(tt) => {
1816 for field in &tt.fields {
1817 if find_in_item(field, item_addr, target, path) {
1818 return true;
1819 }
1820 }
1821 }
1822 BasicTypeKind::TaggedUnion(tu) => {
1823 for variant in &tu.variants {
1824 let variant_item = OffsetMemoryItem {
1826 offset: MemoryOffset(0),
1827 size: variant.ty.total_size,
1828 name: variant.name.clone(),
1829 ty: variant.ty.clone(),
1830 };
1831 if find_in_item(&variant_item, item_addr, target, path) {
1832 return true;
1833 }
1834 }
1835 }
1836 BasicTypeKind::Optional(tu) => {
1837 for variant in &tu.variants {
1838 let variant_item = OffsetMemoryItem {
1839 offset: MemoryOffset(0),
1840 size: variant.ty.total_size,
1841 name: variant.name.clone(),
1842 ty: variant.ty.clone(),
1843 };
1844 if find_in_item(&variant_item, item_addr, target, path) {
1845 return true;
1846 }
1847 }
1848 }
1849 BasicTypeKind::SliceView(inner) => {
1850 let slice_item = OffsetMemoryItem {
1851 offset: MemoryOffset(0),
1852 size: inner.total_size,
1853 name: "slice".to_string(),
1854 ty: inner.clone(),
1855 };
1856 if find_in_item(&slice_item, item_addr, target, path) {
1857 return true;
1858 }
1859 }
1860 BasicTypeKind::DynamicLengthMapView(a, b) => {
1861 if find_in_item(a, item_addr, target, path) {
1862 return true;
1863 }
1864 if find_in_item(b, item_addr, target, path) {
1865 return true;
1866 }
1867 }
1868 _ => {}
1869 }
1870
1871 path.pop();
1872 false
1873}
1874
1875#[derive(Clone, Debug)]
1876pub enum FunctionInfoKind {
1877 Constant(usize),
1878 Normal(usize),
1879}
1880
1881#[derive(Clone, Debug)]
1882pub struct FunctionInfo {
1883 pub kind: FunctionInfoKind,
1884 pub frame_memory: FrameMemoryInfo,
1885 pub return_type: VmType,
1886 pub name: String,
1887 pub ip_range: InstructionRange,
1888}
1889
1890#[derive(Clone, Debug)]
1891pub struct CompleteFunctionInfo {
1892 pub ip: InstructionPosition,
1893 pub size: InstructionPositionOffset,
1894 pub info: FunctionInfo,
1895}
1896
1897pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1898 let tab_str = " ".repeat(tabs);
1899 writeln!(f)?;
1900 write!(f, "{tab_str}")
1901}
1902
1903pub fn show_memory_offset(
1904 offset: MemoryOffset,
1905 origin: FrameMemoryAddress,
1906 f: &mut dyn Write,
1907 _tabs: usize,
1908) -> std::fmt::Result {
1909 let result = origin + offset;
1910 write!(f, "{}+{:04X}", result, offset.0.yellow())
1911}
1912fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1913 write!(f, "{} ({})", size.green(), size.0)
1914}
1915
1916pub fn show_offset_item(
1917 offset_item: &OffsetMemoryItem,
1918 origin: FrameMemoryAddress,
1919 f: &mut dyn Write,
1920 tabs: usize,
1921) -> std::fmt::Result {
1922 show_memory_offset(offset_item.offset, origin, f, tabs)?;
1923 write!(f, ":")?;
1924 show_memory_size(offset_item.size, f, tabs)?;
1925 write!(f, " ")?;
1926 write_identifier_and_colon(&offset_item.name, f)?;
1927 let adjusted_origin = origin + offset_item.offset;
1928 write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1929}
1930
1931pub fn show_tagged_union(
1932 tagged_union: &TaggedUnion,
1933 origin: FrameMemoryAddress,
1934 f: &mut dyn Write,
1935 tabs: usize,
1936) -> std::fmt::Result {
1937 write!(f, "union tag_size:")?;
1938 show_memory_size(tagged_union.tag_size, f, tabs)?;
1939 write!(f, " max payload:")?;
1940 show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1941
1942 let adjusted_payload_origin = origin + tagged_union.payload_offset;
1943
1944 for (index, union_data) in tagged_union
1945 .variants
1946 .clone()
1947 .into_iter()
1948 .take(4)
1949 .enumerate()
1950 {
1951 new_line_and_tab(f, tabs + 1)?;
1953 write!(f, "{}> ", index.bright_magenta())?;
1954 write_identifier_and_colon(&union_data.name, f)?;
1955 write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1956 }
1957 Ok(())
1958}
1959
1960pub fn show_struct_type(
1961 s: &StructType,
1962 origin: FrameMemoryAddress,
1963 f: &mut dyn Write,
1964 tabs: usize,
1965) -> std::fmt::Result {
1966 write!(f, "{} {{", s.name)?;
1967 for offset_item in &s.fields {
1968 new_line_and_tab(f, tabs + 1)?;
1969 show_offset_item(offset_item, origin, f, tabs + 1)?;
1970 }
1971 write!(f, " }}")
1972}
1973
1974pub fn show_tuple_type(
1975 s: &TupleType,
1976 origin: FrameMemoryAddress,
1977 f: &mut dyn Write,
1978 tabs: usize,
1979) -> std::fmt::Result {
1980 write!(f, "(")?;
1981 for offset_item in &s.fields {
1982 new_line_and_tab(f, tabs + 1)?;
1983 show_offset_item(offset_item, origin, f, tabs + 1)?;
1984 }
1985 write!(f, " )")
1986}
1987
1988pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1989 write!(f, "{}: ", identifier.blue())
1990}
1991
1992pub fn write_basic_type(
1993 ty: &BasicType,
1994 origin: FrameMemoryAddress,
1995 f: &mut dyn Write,
1996 tabs: usize,
1997) -> std::fmt::Result {
1998 match &ty.kind {
1999 BasicTypeKind::Empty => write!(f, "()"),
2000 BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
2001 BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
2002 BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
2003 BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
2004 BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
2005 BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
2006 BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
2007 BasicTypeKind::TaggedUnion(tagged_union) => {
2008 show_tagged_union(tagged_union, origin, f, tabs)
2009 }
2010 BasicTypeKind::Optional(tagged_union) => {
2011 write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
2012 show_tagged_union(tagged_union, origin, f, tabs)
2013 }
2014 BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
2015
2016 BasicTypeKind::SliceView(slice_inner_type) => {
2017 write!(f, "[|")?;
2018 write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
2019 write!(f, "|]")
2020 }
2021 BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
2022 write!(f, "[|")?;
2023 show_offset_item(key_type, origin, f, tabs + 1)?;
2024 write!(f, ", ")?;
2025 show_offset_item(value_type, origin, f, tabs + 1)?;
2026 write!(f, "|]")
2027 }
2028 BasicTypeKind::InternalStringPointer => {
2029 write!(f, "str")
2030 }
2031 BasicTypeKind::InternalRangeHeader => {
2032 write!(f, "range")
2033 }
2034
2035 BasicTypeKind::FixedCapacityArray(element_type, size) => {
2036 write!(f, "[{element_type}, {size}]")
2037 }
2038 BasicTypeKind::DynamicLengthVecView(element_type) => {
2039 write!(f, "Vec<{element_type}>")
2040 }
2041 BasicTypeKind::VecStorage(element_type, size) => {
2042 write!(f, "VecStorage<{element_type}, {size}>")
2043 }
2044 BasicTypeKind::QueueStorage(element_type, size) => {
2045 write!(f, "QueueStorage<{element_type}, {size}>")
2046 }
2047 BasicTypeKind::GridStorage(element_type, width, height) => {
2048 write!(f, "GridStorage<{element_type}, ({width},{height})>")
2049 }
2050 BasicTypeKind::StackStorage(element_type, size) => {
2051 write!(f, "StackStorage<{element_type}, {size}>")
2052 }
2053 BasicTypeKind::SparseView(element_type) => {
2054 write!(f, "Sparse<{element_type}>")
2055 }
2056 BasicTypeKind::GridView(element_type) => {
2057 write!(f, "grid<{element_type}>")
2058 }
2059 BasicTypeKind::SparseStorage(element_type, size) => {
2060 write!(f, "SparseStorage<{element_type}, {size}>")
2061 }
2062 BasicTypeKind::DynamicLengthMapView(key, value) => {
2063 write!(f, "Map<{key}, {value}>")
2064 }
2065 BasicTypeKind::MapStorage {
2066 logical_limit: logical_size,
2067 key_type,
2068 value_type,
2069 ..
2070 } => {
2071 write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>",)
2072 }
2073 BasicTypeKind::InternalGridPointer => {
2074 write!(f, "Grid<>")
2075 }
2076 BasicTypeKind::InternalVecIterator => {
2077 write!(f, "vec_iter")
2078 }
2079 BasicTypeKind::InternalRangeIterator => {
2080 write!(f, "range_iter")
2081 }
2082 BasicTypeKind::InternalMapIterator => {
2083 write!(f, "map_iter")
2084 }
2085 BasicTypeKind::InternalSparseIterator => {
2086 write!(f, "sparse_iter")
2087 }
2088 }
2089}
2090
2091pub fn show_frame_addr(
2092 addr: FrameMemoryAddress,
2093 f: &mut dyn Write,
2094 _tabs: usize,
2095) -> std::fmt::Result {
2096 write!(f, "{:04X}", addr.0.blue())
2097}
2098
2099pub fn show_frame_region(
2100 region: FrameMemoryRegion,
2101 f: &mut dyn Write,
2102 tabs: usize,
2103) -> std::fmt::Result {
2104 show_frame_addr(region.addr, f, tabs)?;
2105 write!(f, ":")?;
2106 show_memory_size(region.size, f, tabs)
2107}
2108
2109pub fn show_frame_memory(
2110 frame_relative_infos: &FrameMemoryInfo,
2111 f: &mut dyn Write,
2112) -> std::fmt::Result {
2113 for mem in &frame_relative_infos.infos {
2114 let addr = mem.frame_placed_type.addr;
2115 show_frame_region(mem.frame_placed_type.region(), f, 0)?;
2116 write!(f, " ")?;
2117 match &mem.kind {
2118 VariableInfoKind::Variable(v) => {
2119 write!(f, "var ")?;
2120 write_identifier_and_colon(&v.name, f)?;
2121 }
2122 VariableInfoKind::Parameter(v) => {
2123 write!(f, "param ")?;
2124 write_identifier_and_colon(&v.name, f)?;
2125 }
2126 VariableInfoKind::Return => {
2127 write!(f, "return:")?;
2128 }
2129 }
2130 write!(f, " ")?;
2131 write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2132 writeln!(f)?;
2133 }
2134
2135 writeln!(
2136 f,
2137 "frame size for variables: {:0}",
2138 frame_relative_infos.frame_size_for_variables_except_temp
2139 )?;
2140 Ok(())
2141}