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