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::DynamicLengthVecView(..)
1295 | BasicTypeKind::MapStorage { ..}
1297 | BasicTypeKind::DynamicLengthMapView(..)
1298 )
1299 }
1300 #[must_use]
1301 pub const fn is_collection_with_capacity(&self) -> bool {
1302 matches!(
1303 self.kind,
1304 BasicTypeKind::FixedCapacityArray(..)
1305 | BasicTypeKind::VecStorage(..)
1307 | BasicTypeKind::MapStorage { ..}
1309 )
1310 }
1311
1312 #[must_use]
1313
1314 pub const fn get_vec_slice_like_capacity(&self) -> Option<MemorySize> {
1315 match &self.kind {
1316 BasicTypeKind::FixedCapacityArray(_element_type, capacity) => {
1317 Some(MemorySize(*capacity as u32))
1318 }
1319 BasicTypeKind::VecStorage(_element_type, capacity) => {
1320 Some(MemorySize(*capacity as u32))
1321 }
1322 _ => None,
1323 }
1324 }
1325}
1326
1327impl BasicType {
1328 pub(crate) const fn manifestation(&self) -> Manifestation {
1329 self.kind.manifestation()
1330 }
1331}
1332
1333impl BasicType {
1334 #[must_use]
1335 pub const fn should_be_copied_back_when_mutable_arg_or_return(&self) -> bool {
1336 !self.is_aggregate()
1337 }
1338}
1339
1340impl BasicType {
1341 #[must_use]
1342 pub fn referenced_type(&self) -> &Self {
1343 panic!("referenced_type() is no longer supported - MutablePointer was removed")
1345 }
1346}
1347
1348impl BasicType {
1349 #[must_use]
1350 pub const fn make_pointer(&self) -> Self {
1351 Self {
1353 id: BasicTypeId::EMPTY,
1354 kind: BasicTypeKind::U8,
1355 total_size: HEAP_PTR_ON_FRAME_SIZE,
1356 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1357 }
1358 }
1359}
1360
1361impl BasicType {}
1362
1363impl BasicType {
1364 #[must_use]
1365 pub fn get_variant(&self, variant_index: usize) -> &TaggedUnionVariant {
1366 match &self.kind {
1367 BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => {
1368 tagged.get_variant_by_index(variant_index)
1369 }
1370 _ => panic!("type is not a tagged union"),
1371 }
1372 }
1373}
1374
1375impl BasicType {
1376 #[must_use]
1377 pub const fn is_scalar(&self) -> bool {
1378 self.kind.is_scalar()
1379 }
1380
1381 #[must_use]
1382 pub const fn is_mutable_reference(&self) -> bool {
1383 self.kind.is_mutable_reference()
1384 }
1385}
1386
1387impl BasicType {
1388 #[must_use]
1389 pub const fn unwrap_info(
1390 &self,
1391 ) -> Option<(MemoryOffset, MemorySize, MemoryOffset, MemorySize)> {
1392 match &self.kind {
1393 BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => Some((
1394 tagged.tag_offset,
1395 tagged.tag_size,
1396 tagged.payload_offset,
1397 tagged.payload_max_size,
1398 )),
1399 _ => None,
1400 }
1401 }
1402
1403 #[must_use]
1404 pub fn union_info(&self) -> &TaggedUnion {
1405 self.kind.union_info()
1406 }
1407
1408 #[must_use]
1409 pub fn create_mutable_pointer(&self) -> Self {
1410 debug_assert!(!self.is_mutable_reference());
1412
1413 Self {
1414 id: BasicTypeId::EMPTY,
1415 kind: BasicTypeKind::U8,
1416 total_size: HEAP_PTR_ON_FRAME_SIZE,
1417 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1418 }
1419 }
1420
1421 #[must_use]
1422 pub const fn is_aggregate(&self) -> bool {
1423 self.kind.is_aggregate()
1424 }
1425
1426 #[must_use]
1427 pub const fn optional_info(&self) -> Option<&TaggedUnion> {
1428 match &self.kind {
1429 BasicTypeKind::Optional(tagged_union) => Some(tagged_union),
1430 _ => None,
1431 }
1432 }
1433
1434 #[must_use]
1435 pub fn get_field_offset(&self, index: usize) -> Option<&OffsetMemoryItem> {
1436 match &self.kind {
1437 BasicTypeKind::Struct(struct_type) => struct_type.fields.get(index),
1438 BasicTypeKind::Tuple(tuple_type) => tuple_type.fields.get(index),
1439 _ => {
1440 error!(?self, "not a type with fields");
1441 None
1442 }
1443 }
1444 }
1445
1446 #[must_use]
1447 pub fn bucket_size_for_vec_like(&self) -> Option<MemorySize> {
1448 match &self.kind {
1449 BasicTypeKind::FixedCapacityArray(inner, capacity) => Some(inner.total_size),
1450 BasicTypeKind::SliceView(inner) => Some(inner.total_size),
1451 BasicTypeKind::VecStorage(inner, _) => Some(inner.total_size),
1452 BasicTypeKind::StringStorage(inner, _) => Some(inner.total_size),
1453 BasicTypeKind::DynamicLengthVecView(inner) => Some(inner.total_size),
1454 BasicTypeKind::StringView => Some(MemorySize(1)), _ => None,
1456 }
1457 }
1458
1459 #[must_use]
1460 pub fn element(&self) -> Option<BasicTypeRef> {
1461 match &self.kind {
1462 BasicTypeKind::StackStorage(inner, _)
1463 | BasicTypeKind::GridView(inner)
1464 | BasicTypeKind::GridStorage(inner, ..)
1465 | BasicTypeKind::SparseStorage(inner, _)
1466 | BasicTypeKind::SparseView(inner)
1467 | BasicTypeKind::QueueStorage(inner, _)
1468 | BasicTypeKind::DynamicLengthVecView(inner)
1469 | BasicTypeKind::FixedCapacityArray(inner, _)
1470 | BasicTypeKind::VecStorage(inner, _)
1471 | BasicTypeKind::SliceView(inner) => Some(inner.clone()),
1472 BasicTypeKind::StringView => Some(Rc::new(self.clone())),
1473 _ => None,
1474 }
1475 }
1476
1477 #[must_use]
1478 pub const fn header_size_for_vec_like(&self) -> Option<MemorySize> {
1479 match &self.kind {
1480 BasicTypeKind::SliceView(_)
1481 | BasicTypeKind::DynamicLengthVecView(_)
1482 | BasicTypeKind::VecStorage(_, _)
1483 | BasicTypeKind::StringStorage(_, _)
1484 | BasicTypeKind::StringView => Some(VEC_HEADER_SIZE),
1485 BasicTypeKind::DynamicLengthMapView(..) => Some(MAP_HEADER_SIZE),
1486 _ => None,
1487 }
1488 }
1489
1490 #[must_use]
1491 pub fn element_pair(&self) -> Option<(&OffsetMemoryItem, &OffsetMemoryItem)> {
1492 match &self.kind {
1493 BasicTypeKind::DynamicLengthMapView(a, b) => Some((a, b)),
1494 _ => None,
1495 }
1496 }
1497
1498 #[must_use]
1499 pub fn is_int(&self) -> bool {
1500 matches!(self.kind, BasicTypeKind::S32)
1501 && self.total_size.0 == 4
1502 && self.max_alignment == MemoryAlignment::U32
1503 }
1504 #[must_use]
1505 pub fn is_float(&self) -> bool {
1506 matches!(self.kind, BasicTypeKind::Fixed32)
1507 && self.total_size.0 == 4
1508 && self.max_alignment == MemoryAlignment::U32
1509 }
1510
1511 #[must_use]
1512 pub fn is_str(&self) -> bool {
1513 matches!(self.kind, BasicTypeKind::StringView)
1514 && self.total_size == STRING_PTR_SIZE
1515 && self.max_alignment == STRING_PTR_ALIGNMENT
1516 }
1517
1518 #[must_use]
1519 pub fn is_bool(&self) -> bool {
1520 matches!(self.kind, BasicTypeKind::B8)
1521 && self.total_size.0 == 1
1522 && self.max_alignment == MemoryAlignment::U8
1523 }
1524 #[must_use]
1525 pub fn is_byte(&self) -> bool {
1526 matches!(self.kind, BasicTypeKind::U8)
1527 && self.total_size.0 == 1
1528 && self.max_alignment == MemoryAlignment::U8
1529 }
1530}
1531
1532impl Display for BasicType {
1533 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1534 write!(f, "{}", self.kind)
1535 }
1536}
1537
1538#[derive(Clone, Debug)]
1539pub struct VariableInfo {
1540 pub is_mutable: bool,
1541 pub name: String,
1542}
1543
1544impl Display for VariableInfo {
1545 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1546 let mut_prefix = if self.is_mutable { "mut " } else { "" };
1547
1548 let name = &self.name;
1549 write!(f, "{mut_prefix}{name}")
1550 }
1551}
1552
1553#[derive(Clone, Debug)]
1554pub enum VariableInfoKind {
1555 Variable(VariableInfo),
1556 Parameter(VariableInfo),
1557 Return,
1558}
1559
1560impl Display for VariableInfoKind {
1561 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1562 match self {
1563 Self::Variable(var_info) => {
1564 write!(f, "{} {var_info}", "var:".white())
1565 }
1566 Self::Parameter(var_info) => {
1567 write!(f, "{} {var_info}", "param:".white())
1568 }
1569 Self::Return => {
1570 write!(f, "{}", "return".white())
1571 }
1572 }
1573 }
1574}
1575
1576#[derive(Clone, Debug)]
1577pub struct FrameAddressInfo {
1578 pub kind: VariableInfoKind,
1579 pub frame_placed_type: FramePlacedType,
1580}
1581
1582#[derive(Clone, Debug)]
1583pub struct VariableRegister {
1584 pub unique_id_in_function: usize,
1585 pub variable: VariableInfo,
1586 pub register: TypedRegister,
1587}
1588
1589impl Display for VariableRegister {
1590 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1591 write!(f, "{}: {}", self.register, self.variable)
1592 }
1593}
1594
1595#[derive(Clone, Debug)]
1596pub struct VariableRegisterRange {
1597 pub start: u8,
1598 pub count: u8,
1599}
1600
1601#[derive(Clone, Debug)]
1602pub struct FrameMemoryInfo {
1603 pub infos: Vec<FrameAddressInfo>,
1604 pub total_frame_size: FrameMemorySize,
1605 pub variable_frame_size: FrameMemorySize,
1606 pub variable_registers: Vec<VariableRegister>,
1607 pub frame_size_for_variables_except_temp: FrameMemorySize,
1609}
1610
1611#[derive(Clone)]
1612pub struct FrameRelativeInfo {
1613 pub frame_memory_region: FrameMemoryRegion,
1614 pub kind: FrameAddressInfo,
1615}
1616
1617#[derive(Clone, Debug)]
1618pub struct PathInfo {
1619 pub steps: Vec<PathStep>,
1620}
1621
1622impl PathInfo {
1623 #[must_use]
1624 pub fn convert_to_string(&self) -> String {
1625 let path = &self.steps;
1626
1627 let last = path.last().unwrap();
1628
1629 let names: Vec<_> = path.iter().map(|x| x.item.name.to_string()).collect();
1630
1631 let types: Vec<_> = path.iter().map(|x| format!("{}", x.item.ty.kind)).collect();
1632
1633 let names_path = names.join(".");
1634 let types_path = types.join("->");
1635
1636 format!(
1637 "{:04X}:{:X} {} ({})",
1638 (last.origin + last.item.offset).0.bright_cyan(),
1639 last.item.ty.total_size.0.yellow(),
1640 names_path.bright_blue(),
1641 types_path.yellow(),
1642 )
1643 }
1644}
1645
1646#[derive(Clone, Debug)]
1647pub struct PathStep {
1648 pub item: OffsetMemoryItem,
1649 pub origin: FrameMemoryAddress,
1650}
1651
1652impl PathStep {
1653 #[must_use]
1654 pub const fn absolute_address(&self) -> FrameMemoryAddress {
1655 FrameMemoryAddress(self.origin.0 + self.item.offset.0)
1656 }
1657}
1658
1659impl FrameMemoryInfo {
1660 #[must_use]
1661 pub const fn size(&self) -> FrameMemorySize {
1662 self.total_frame_size
1663 }
1664
1665 #[must_use]
1667 pub fn find_path_to_address_items(&self, target: FrameMemoryAddress) -> Option<PathInfo> {
1668 for info in &self.infos {
1669 let root_item = OffsetMemoryItem {
1671 offset: MemoryOffset(0),
1672 size: info.frame_placed_type.ty.total_size,
1673 name: info.kind.to_string(),
1674 ty: info.frame_placed_type.ty.clone(),
1675 };
1676 let base_addr = info.frame_placed_type.addr;
1677 let mut path = Vec::new();
1678 if find_in_item(&root_item, base_addr, target, &mut path) {
1679 return Some(PathInfo { steps: path });
1680 }
1681 }
1682 None
1683 }
1684}
1685fn find_in_item(
1686 item: &OffsetMemoryItem,
1687 base_addr: FrameMemoryAddress,
1688 target: FrameMemoryAddress,
1689 path: &mut Vec<PathStep>,
1690) -> bool {
1691 let item_addr = FrameMemoryAddress(base_addr.0 + item.offset.0);
1692 path.push(PathStep {
1693 item: item.clone(),
1694 origin: base_addr,
1695 });
1696
1697 if item_addr.0 == target.0 {
1698 return true;
1699 }
1700
1701 match &item.ty.kind {
1702 BasicTypeKind::Struct(st) => {
1703 for field in &st.fields {
1704 if find_in_item(field, item_addr, target, path) {
1705 return true;
1706 }
1707 }
1708 }
1709 BasicTypeKind::Tuple(tt) => {
1710 for field in &tt.fields {
1711 if find_in_item(field, item_addr, target, path) {
1712 return true;
1713 }
1714 }
1715 }
1716 BasicTypeKind::TaggedUnion(tu) => {
1717 for variant in &tu.variants {
1718 let variant_item = OffsetMemoryItem {
1720 offset: MemoryOffset(0),
1721 size: variant.ty.total_size,
1722 name: variant.name.clone(),
1723 ty: variant.ty.clone(),
1724 };
1725 if find_in_item(&variant_item, item_addr, target, path) {
1726 return true;
1727 }
1728 }
1729 }
1730 BasicTypeKind::Optional(tu) => {
1731 for variant in &tu.variants {
1732 let variant_item = OffsetMemoryItem {
1733 offset: MemoryOffset(0),
1734 size: variant.ty.total_size,
1735 name: variant.name.clone(),
1736 ty: variant.ty.clone(),
1737 };
1738 if find_in_item(&variant_item, item_addr, target, path) {
1739 return true;
1740 }
1741 }
1742 }
1743 BasicTypeKind::SliceView(inner) => {
1744 let slice_item = OffsetMemoryItem {
1745 offset: MemoryOffset(0),
1746 size: inner.total_size,
1747 name: "slice".to_string(),
1748 ty: inner.clone(),
1749 };
1750 if find_in_item(&slice_item, item_addr, target, path) {
1751 return true;
1752 }
1753 }
1754 BasicTypeKind::DynamicLengthMapView(a, b) => {
1755 if find_in_item(a, item_addr, target, path) {
1756 return true;
1757 }
1758 if find_in_item(b, item_addr, target, path) {
1759 return true;
1760 }
1761 }
1762 _ => {}
1763 }
1764
1765 path.pop();
1766 false
1767}
1768
1769#[derive(Clone, Debug)]
1770pub enum FunctionInfoKind {
1771 Constant(usize),
1772 Normal(usize),
1773}
1774
1775#[derive(Clone, Debug)]
1776pub struct FunctionInfo {
1777 pub kind: FunctionInfoKind,
1778 pub frame_memory: FrameMemoryInfo,
1779 pub return_type: VmType,
1780 pub name: String,
1781 pub ip_range: InstructionRange,
1782}
1783
1784#[derive(Clone, Debug)]
1785pub struct CompleteFunctionInfo {
1786 pub ip: InstructionPosition,
1787 pub size: InstructionPositionOffset,
1788 pub info: FunctionInfo,
1789}
1790
1791pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1792 let tab_str = " ".repeat(tabs);
1793 writeln!(f)?;
1794 write!(f, "{tab_str}")
1795}
1796
1797pub fn show_memory_offset(
1798 offset: MemoryOffset,
1799 origin: FrameMemoryAddress,
1800 f: &mut dyn Write,
1801 _tabs: usize,
1802) -> std::fmt::Result {
1803 let result = origin + offset;
1804 write!(f, "{}+{:04X}", result, offset.0.yellow())
1805}
1806fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1807 write!(f, "{} ({})", size.green(), size.0)
1808}
1809
1810pub fn show_offset_item(
1811 offset_item: &OffsetMemoryItem,
1812 origin: FrameMemoryAddress,
1813 f: &mut dyn Write,
1814 tabs: usize,
1815) -> std::fmt::Result {
1816 show_memory_offset(offset_item.offset, origin, f, tabs)?;
1817 write!(f, ":")?;
1818 show_memory_size(offset_item.size, f, tabs)?;
1819 write!(f, " ")?;
1820 write_identifier_and_colon(&offset_item.name, f)?;
1821 let adjusted_origin = origin + offset_item.offset;
1822 write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1823}
1824
1825pub fn show_tagged_union(
1826 tagged_union: &TaggedUnion,
1827 origin: FrameMemoryAddress,
1828 f: &mut dyn Write,
1829 tabs: usize,
1830) -> std::fmt::Result {
1831 write!(f, "union tag_size:")?;
1832 show_memory_size(tagged_union.tag_size, f, tabs)?;
1833 write!(f, " max payload:")?;
1834 show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1835
1836 let adjusted_payload_origin = origin + tagged_union.payload_offset;
1837
1838 for (index, union_data) in tagged_union
1839 .variants
1840 .clone()
1841 .into_iter()
1842 .take(4)
1843 .enumerate()
1844 {
1845 new_line_and_tab(f, tabs + 1)?;
1847 write!(f, "{}> ", index.bright_magenta())?;
1848 write_identifier_and_colon(&union_data.name, f)?;
1849 write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1850 }
1851 Ok(())
1852}
1853
1854pub fn show_struct_type(
1855 s: &StructType,
1856 origin: FrameMemoryAddress,
1857 f: &mut dyn Write,
1858 tabs: usize,
1859) -> std::fmt::Result {
1860 write!(f, "{} {{", s.name)?;
1861 for offset_item in &s.fields {
1862 new_line_and_tab(f, tabs + 1)?;
1863 show_offset_item(offset_item, origin, f, tabs + 1)?;
1864 }
1865 write!(f, " }}")
1866}
1867
1868pub fn show_tuple_type(
1869 s: &TupleType,
1870 origin: FrameMemoryAddress,
1871 f: &mut dyn Write,
1872 tabs: usize,
1873) -> std::fmt::Result {
1874 write!(f, "(")?;
1875 for offset_item in &s.fields {
1876 new_line_and_tab(f, tabs + 1)?;
1877 show_offset_item(offset_item, origin, f, tabs + 1)?;
1878 }
1879 write!(f, " )")
1880}
1881
1882pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1883 write!(f, "{}: ", identifier.blue())
1884}
1885
1886pub fn write_basic_type(
1887 ty: &BasicType,
1888 origin: FrameMemoryAddress,
1889 f: &mut dyn Write,
1890 tabs: usize,
1891) -> std::fmt::Result {
1892 match &ty.kind {
1893 BasicTypeKind::Empty => write!(f, "()"),
1894 BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
1895 BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
1896 BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
1897 BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
1898 BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
1899 BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
1900 BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
1901 BasicTypeKind::TaggedUnion(tagged_union) => {
1902 show_tagged_union(tagged_union, origin, f, tabs)
1903 }
1904 BasicTypeKind::Optional(tagged_union) => {
1905 write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
1906 show_tagged_union(tagged_union, origin, f, tabs)
1907 }
1908 BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
1909
1910 BasicTypeKind::SliceView(slice_inner_type) => {
1911 write!(f, "[|")?;
1912 write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
1913 write!(f, "|]")
1914 }
1915 BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
1916 write!(f, "[|")?;
1917 show_offset_item(key_type, origin, f, tabs + 1)?;
1918 write!(f, ", ")?;
1919 show_offset_item(value_type, origin, f, tabs + 1)?;
1920 write!(f, "|]")
1921 }
1922 BasicTypeKind::StringView => {
1923 write!(f, "str")
1924 }
1925 BasicTypeKind::InternalRangeHeader => {
1926 write!(f, "range")
1927 }
1928
1929 BasicTypeKind::FixedCapacityArray(element_type, size) => {
1930 write!(f, "[{element_type}, {size}]")
1931 }
1932 BasicTypeKind::DynamicLengthVecView(element_type) => {
1933 write!(f, "Vec<{element_type}>")
1934 }
1935 BasicTypeKind::VecStorage(element_type, size) => {
1936 write!(f, "VecStorage<{element_type}, {size}>")
1937 }
1938 BasicTypeKind::StringStorage(element_type, size) => {
1939 write!(f, "StringStorage<{element_type}, {size}>")
1940 }
1941 BasicTypeKind::QueueStorage(element_type, size) => {
1942 write!(f, "QueueStorage<{element_type}, {size}>")
1943 }
1944 BasicTypeKind::GridStorage(element_type, width, height) => {
1945 write!(f, "GridStorage<{element_type}, ({width},{height})>")
1946 }
1947 BasicTypeKind::StackStorage(element_type, size) => {
1948 write!(f, "StackStorage<{element_type}, {size}>")
1949 }
1950 BasicTypeKind::SparseView(element_type) => {
1951 write!(f, "Sparse<{element_type}>")
1952 }
1953 BasicTypeKind::GridView(element_type) => {
1954 write!(f, "grid<{element_type}>")
1955 }
1956 BasicTypeKind::SparseStorage(element_type, size) => {
1957 write!(f, "SparseStorage<{element_type}, {size}>")
1958 }
1959 BasicTypeKind::DynamicLengthMapView(key, value) => {
1960 write!(f, "Map<{key}, {value}>")
1961 }
1962 BasicTypeKind::MapStorage {
1963 logical_limit: logical_size,
1964 key_type,
1965 value_type,
1966 ..
1967 } => {
1968 write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>",)
1969 }
1970 BasicTypeKind::InternalVecIterator => {
1971 write!(f, "vec_iter")
1972 }
1973 BasicTypeKind::InternalStringIterator => {
1974 write!(f, "str_iter")
1975 }
1976 BasicTypeKind::InternalRangeIterator => {
1977 write!(f, "range_iter")
1978 }
1979 BasicTypeKind::InternalMapIterator => {
1980 write!(f, "map_iter")
1981 }
1982 BasicTypeKind::InternalSparseIterator => {
1983 write!(f, "sparse_iter")
1984 }
1985 }
1986}
1987
1988pub fn show_frame_addr(
1989 addr: FrameMemoryAddress,
1990 f: &mut dyn Write,
1991 _tabs: usize,
1992) -> std::fmt::Result {
1993 write!(f, "{:04X}", addr.0.blue())
1994}
1995
1996pub fn show_frame_region(
1997 region: FrameMemoryRegion,
1998 f: &mut dyn Write,
1999 tabs: usize,
2000) -> std::fmt::Result {
2001 show_frame_addr(region.addr, f, tabs)?;
2002 write!(f, ":")?;
2003 show_memory_size(region.size, f, tabs)
2004}
2005
2006pub fn show_frame_memory(
2007 frame_relative_infos: &FrameMemoryInfo,
2008 f: &mut dyn Write,
2009) -> std::fmt::Result {
2010 for mem in &frame_relative_infos.infos {
2011 let addr = mem.frame_placed_type.addr;
2012 show_frame_region(mem.frame_placed_type.region(), f, 0)?;
2013 write!(f, " ")?;
2014 match &mem.kind {
2015 VariableInfoKind::Variable(v) => {
2016 write!(f, "var ")?;
2017 write_identifier_and_colon(&v.name, f)?;
2018 }
2019 VariableInfoKind::Parameter(v) => {
2020 write!(f, "param ")?;
2021 write_identifier_and_colon(&v.name, f)?;
2022 }
2023 VariableInfoKind::Return => {
2024 write!(f, "return:")?;
2025 }
2026 }
2027 write!(f, " ")?;
2028 write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2029 writeln!(f)?;
2030 }
2031
2032 writeln!(
2033 f,
2034 "frame size for variables: {:0}",
2035 frame_relative_infos.frame_size_for_variables_except_temp
2036 )?;
2037 Ok(())
2038}