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