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