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