1#![cfg_attr(feature = "nightly", allow(internal_features))]
3#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
4#![cfg_attr(feature = "nightly", feature(step_trait))]
5use std::fmt;
40#[cfg(feature = "nightly")]
41use std::iter::Step;
42use std::num::{NonZeroUsize, ParseIntError};
43use std::ops::{Add, AddAssign, Deref, Mul, RangeFull, Sub};
44use std::range::RangeInclusive;
45use std::str::FromStr;
46
47use bitflags::bitflags;
48#[cfg(feature = "nightly")]
49use rustc_data_structures::stable_hash::StableOrd;
50#[cfg(feature = "nightly")]
51use rustc_error_messages::{DiagArgValue, IntoDiagArg};
52#[cfg(feature = "nightly")]
53use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
54use rustc_hashes::Hash64;
55use rustc_index::{Idx, IndexSlice, IndexVec};
56#[cfg(feature = "nightly")]
57use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash};
58#[cfg(feature = "nightly")]
59use rustc_span::{Symbol, sym};
60
61mod callconv;
62mod canon_abi;
63mod extern_abi;
64mod layout;
65#[cfg(test)]
66mod tests;
67
68pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
69pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
70#[cfg(feature = "nightly")]
71pub use extern_abi::CVariadicStatus;
72pub use extern_abi::{ExternAbi, all_names};
73pub use layout::{FIRST_VARIANT, FieldIdx, LayoutCalculator, LayoutCalculatorError, VariantIdx};
74#[cfg(feature = "nightly")]
75pub use layout::{Layout, TyAbiInterface, TyAndLayout};
76
77#[derive(Clone, Copy, PartialEq, Eq, Default)]
78#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
79pub struct ReprFlags(u8);
80
81bitflags! {
82 impl ReprFlags: u8 {
83 const IS_C = 1 << 0;
84 const IS_SIMD = 1 << 1;
85 const IS_TRANSPARENT = 1 << 2;
86 const IS_LINEAR = 1 << 3;
89 const RANDOMIZE_LAYOUT = 1 << 4;
93 const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
96 const IS_SCALABLE = 1 << 6;
97 const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
99 | ReprFlags::IS_SIMD.bits()
100 | ReprFlags::IS_SCALABLE.bits()
101 | ReprFlags::IS_LINEAR.bits();
102 const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
103 }
104}
105
106impl std::fmt::Debug for ReprFlags {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 bitflags::parser::to_writer(self, f)
111 }
112}
113
114#[derive(Copy, Clone, Debug, Eq, PartialEq)]
115#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
116pub enum IntegerType {
117 Pointer(bool),
120 Fixed(Integer, bool),
123}
124
125impl IntegerType {
126 pub fn is_signed(&self) -> bool {
127 match self {
128 IntegerType::Pointer(b) => *b,
129 IntegerType::Fixed(_, b) => *b,
130 }
131 }
132}
133
134#[derive(Copy, Clone, Debug, Eq, PartialEq)]
135#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
136pub enum ScalableElt {
137 ElementCount(u16),
139 Container,
142}
143
144#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
146#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
147pub struct ReprOptions {
148 pub int: Option<IntegerType>,
149 pub align: Option<Align>,
150 pub pack: Option<Align>,
151 pub flags: ReprFlags,
152 pub scalable: Option<ScalableElt>,
154 pub field_shuffle_seed: Hash64,
162}
163
164impl ReprOptions {
165 #[inline]
166 pub fn simd(&self) -> bool {
167 self.flags.contains(ReprFlags::IS_SIMD)
168 }
169
170 #[inline]
171 pub fn scalable(&self) -> bool {
172 self.flags.contains(ReprFlags::IS_SCALABLE)
173 }
174
175 #[inline]
176 pub fn c(&self) -> bool {
177 self.flags.contains(ReprFlags::IS_C)
178 }
179
180 #[inline]
181 pub fn packed(&self) -> bool {
182 self.pack.is_some()
183 }
184
185 #[inline]
186 pub fn transparent(&self) -> bool {
187 self.flags.contains(ReprFlags::IS_TRANSPARENT)
188 }
189
190 #[inline]
191 pub fn linear(&self) -> bool {
192 self.flags.contains(ReprFlags::IS_LINEAR)
193 }
194
195 pub fn discr_type(&self) -> IntegerType {
203 self.int.unwrap_or(IntegerType::Pointer(true))
204 }
205
206 pub fn inhibit_enum_layout_opt(&self) -> bool {
210 self.c() || self.int.is_some()
211 }
212
213 pub fn inhibit_newtype_abi_optimization(&self) -> bool {
214 self.flags.intersects(ReprFlags::ABI_UNOPTIMIZABLE)
215 }
216
217 pub fn inhibit_struct_field_reordering(&self) -> bool {
220 self.flags.intersects(ReprFlags::FIELD_ORDER_UNOPTIMIZABLE) || self.int.is_some()
221 }
222
223 pub fn can_randomize_type_layout(&self) -> bool {
226 !self.inhibit_struct_field_reordering() && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
227 }
228
229 pub fn inhibits_union_abi_opt(&self) -> bool {
231 self.c()
232 }
233}
234
235pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
241
242#[derive(Copy, Clone, Debug, PartialEq, Eq)]
244pub struct PointerSpec {
245 pointer_size: Size,
247 pointer_align: Align,
249 pointer_offset: Size,
251 _is_fat: bool,
254}
255
256#[derive(Debug, PartialEq, Eq)]
259pub struct TargetDataLayout {
260 pub endian: Endian,
261 pub i1_align: Align,
262 pub i8_align: Align,
263 pub i16_align: Align,
264 pub i32_align: Align,
265 pub i64_align: Align,
266 pub i128_align: Align,
267 pub f16_align: Align,
268 pub f32_align: Align,
269 pub f64_align: Align,
270 pub f128_align: Align,
271 pub aggregate_align: Align,
272
273 pub vector_align: Vec<(Size, Align)>,
275
276 pub default_address_space: AddressSpace,
277 pub default_address_space_pointer_spec: PointerSpec,
278
279 address_space_info: Vec<(AddressSpace, PointerSpec)>,
286
287 pub instruction_address_space: AddressSpace,
288
289 pub c_enum_min_size: Integer,
293}
294
295impl Default for TargetDataLayout {
296 fn default() -> TargetDataLayout {
298 let align = |bits| Align::from_bits(bits).unwrap();
299 TargetDataLayout {
300 endian: Endian::Big,
301 i1_align: align(8),
302 i8_align: align(8),
303 i16_align: align(16),
304 i32_align: align(32),
305 i64_align: align(32),
306 i128_align: align(32),
307 f16_align: align(16),
308 f32_align: align(32),
309 f64_align: align(64),
310 f128_align: align(128),
311 aggregate_align: align(8),
312 vector_align: vec![
313 (Size::from_bits(64), align(64)),
314 (Size::from_bits(128), align(128)),
315 ],
316 default_address_space: AddressSpace::ZERO,
317 default_address_space_pointer_spec: PointerSpec {
318 pointer_size: Size::from_bits(64),
319 pointer_align: align(64),
320 pointer_offset: Size::from_bits(64),
321 _is_fat: false,
322 },
323 address_space_info: vec![],
324 instruction_address_space: AddressSpace::ZERO,
325 c_enum_min_size: Integer::I32,
326 }
327 }
328}
329
330pub enum TargetDataLayoutError<'a> {
331 InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
332 InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
333 MissingAlignment { cause: &'a str },
334 InvalidAlignment { cause: &'a str, err: AlignFromBytesError },
335 InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
336 InconsistentTargetPointerWidth { pointer_size: u64, target: u16 },
337 InvalidBitsSize { err: String },
338 UnknownPointerSpecification { err: String },
339}
340
341#[cfg(feature = "nightly")]
342impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutError<'_> {
343 fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
344 match self {
345 TargetDataLayoutError::InvalidAddressSpace { addr_space, err, cause } => {
346 Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
347 .with_arg("addr_space", addr_space)
348 .with_arg("cause", cause)
349 .with_arg("err", err)
350 }
351 TargetDataLayoutError::InvalidBits { kind, bit, cause, err } => {
352 Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
353 .with_arg("kind", kind)
354 .with_arg("bit", bit)
355 .with_arg("cause", cause)
356 .with_arg("err", err)
357 }
358 TargetDataLayoutError::MissingAlignment { cause } => {
359 Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
360 .with_arg("cause", cause)
361 }
362 TargetDataLayoutError::InvalidAlignment { cause, err } => {
363 Diag::new(dcx, level, msg!("invalid alignment for `{$cause}` in \"data-layout\": {$err}"))
364 .with_arg("cause", cause)
365 .with_arg("err", err.to_string())
366 }
367 TargetDataLayoutError::InconsistentTargetArchitecture { dl, target } => {
368 Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"))
369 .with_arg("dl", dl).with_arg("target", target)
370 }
371 TargetDataLayoutError::InconsistentTargetPointerWidth { pointer_size, target } => {
372 Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"))
373 .with_arg("pointer_size", pointer_size).with_arg("target", target)
374 }
375 TargetDataLayoutError::InvalidBitsSize { err } => {
376 Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
377 }
378 TargetDataLayoutError::UnknownPointerSpecification { err } => {
379 Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
380 .with_arg("err", err)
381 }
382 }
383 }
384}
385
386impl TargetDataLayout {
387 pub fn parse_from_llvm_datalayout_string<'a>(
393 input: &'a str,
394 default_address_space: AddressSpace,
395 ) -> Result<TargetDataLayout, TargetDataLayoutError<'a>> {
396 let parse_address_space = |s: &'a str, cause: &'a str| {
398 s.parse::<u32>().map(AddressSpace).map_err(|err| {
399 TargetDataLayoutError::InvalidAddressSpace { addr_space: s, cause, err }
400 })
401 };
402
403 let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
405 s.parse::<u64>().map_err(|err| TargetDataLayoutError::InvalidBits {
406 kind,
407 bit: s,
408 cause,
409 err,
410 })
411 };
412
413 let parse_size =
415 |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
416
417 let parse_align_str = |s: &'a str, cause: &'a str| {
419 let align_from_bits = |bits| {
420 Align::from_bits(bits)
421 .map_err(|err| TargetDataLayoutError::InvalidAlignment { cause, err })
422 };
423 let abi = parse_bits(s, "alignment", cause)?;
424 Ok(align_from_bits(abi)?)
425 };
426
427 let parse_align_seq = |s: &[&'a str], cause: &'a str| {
430 if s.is_empty() {
431 return Err(TargetDataLayoutError::MissingAlignment { cause });
432 }
433 parse_align_str(s[0], cause)
434 };
435
436 let mut dl = TargetDataLayout::default();
437 dl.default_address_space = default_address_space;
438
439 let mut i128_align_src = 64;
440 for spec in input.split('-') {
441 let spec_parts = spec.split(':').collect::<Vec<_>>();
442
443 match &*spec_parts {
444 ["e"] => dl.endian = Endian::Little,
445 ["E"] => dl.endian = Endian::Big,
446 [p] if p.starts_with('P') => {
447 dl.instruction_address_space = parse_address_space(&p[1..], "P")?
448 }
449 ["a", a @ ..] => dl.aggregate_align = parse_align_seq(a, "a")?,
450 ["f16", a @ ..] => dl.f16_align = parse_align_seq(a, "f16")?,
451 ["f32", a @ ..] => dl.f32_align = parse_align_seq(a, "f32")?,
452 ["f64", a @ ..] => dl.f64_align = parse_align_seq(a, "f64")?,
453 ["f128", a @ ..] => dl.f128_align = parse_align_seq(a, "f128")?,
454 [p, s, a @ ..] if p.starts_with("p") => {
455 let mut p = p.strip_prefix('p').unwrap();
456 let mut _is_fat = false;
457
458 if p.starts_with('f') {
462 p = p.strip_prefix('f').unwrap();
463 _is_fat = true;
464 }
465
466 if p.starts_with(char::is_alphabetic) {
469 return Err(TargetDataLayoutError::UnknownPointerSpecification {
470 err: p.to_string(),
471 });
472 }
473
474 let addr_space = if !p.is_empty() {
475 parse_address_space(p, "p-")?
476 } else {
477 AddressSpace::ZERO
478 };
479
480 let pointer_size = parse_size(s, "p-")?;
481 let pointer_align = parse_align_seq(a, "p-")?;
482 let info = PointerSpec {
483 pointer_offset: pointer_size,
484 pointer_size,
485 pointer_align,
486 _is_fat,
487 };
488 if addr_space == default_address_space {
489 dl.default_address_space_pointer_spec = info;
490 } else {
491 match dl.address_space_info.iter_mut().find(|(a, _)| *a == addr_space) {
492 Some(e) => e.1 = info,
493 None => {
494 dl.address_space_info.push((addr_space, info));
495 }
496 }
497 }
498 }
499 [p, s, a, _pr, i] if p.starts_with("p") => {
500 let mut p = p.strip_prefix('p').unwrap();
501 let mut _is_fat = false;
502
503 if p.starts_with('f') {
507 p = p.strip_prefix('f').unwrap();
508 _is_fat = true;
509 }
510
511 if p.starts_with(char::is_alphabetic) {
514 return Err(TargetDataLayoutError::UnknownPointerSpecification {
515 err: p.to_string(),
516 });
517 }
518
519 let addr_space = if !p.is_empty() {
520 parse_address_space(p, "p")?
521 } else {
522 AddressSpace::ZERO
523 };
524
525 let info = PointerSpec {
526 pointer_size: parse_size(s, "p-")?,
527 pointer_align: parse_align_str(a, "p-")?,
528 pointer_offset: parse_size(i, "p-")?,
529 _is_fat,
530 };
531
532 if addr_space == default_address_space {
533 dl.default_address_space_pointer_spec = info;
534 } else {
535 match dl.address_space_info.iter_mut().find(|(a, _)| *a == addr_space) {
536 Some(e) => e.1 = info,
537 None => {
538 dl.address_space_info.push((addr_space, info));
539 }
540 }
541 }
542 }
543
544 [s, a @ ..] if s.starts_with('i') => {
545 let Ok(bits) = s[1..].parse::<u64>() else {
546 parse_size(&s[1..], "i")?; continue;
548 };
549 let a = parse_align_seq(a, s)?;
550 match bits {
551 1 => dl.i1_align = a,
552 8 => dl.i8_align = a,
553 16 => dl.i16_align = a,
554 32 => dl.i32_align = a,
555 64 => dl.i64_align = a,
556 _ => {}
557 }
558 if bits >= i128_align_src && bits <= 128 {
559 i128_align_src = bits;
562 dl.i128_align = a;
563 }
564 }
565 [s, a @ ..] if s.starts_with('v') => {
566 let v_size = parse_size(&s[1..], "v")?;
567 let a = parse_align_seq(a, s)?;
568 if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
569 v.1 = a;
570 continue;
571 }
572 dl.vector_align.push((v_size, a));
574 }
575 _ => {} }
577 }
578
579 if (dl.instruction_address_space != dl.default_address_space)
582 && dl
583 .address_space_info
584 .iter()
585 .find(|(a, _)| *a == dl.instruction_address_space)
586 .is_none()
587 {
588 dl.address_space_info.push((
589 dl.instruction_address_space,
590 dl.default_address_space_pointer_spec.clone(),
591 ));
592 }
593
594 Ok(dl)
595 }
596
597 #[inline]
608 pub fn obj_size_bound(&self) -> u64 {
609 match self.pointer_size().bits() {
610 16 => 1 << 15,
611 32 => 1 << 31,
612 64 => 1 << 61,
613 bits => panic!("obj_size_bound: unknown pointer bit size {bits}"),
614 }
615 }
616
617 #[inline]
627 pub fn obj_size_bound_in(&self, address_space: AddressSpace) -> u64 {
628 match self.pointer_size_in(address_space).bits() {
629 16 => 1 << 15,
630 32 => 1 << 31,
631 64 => 1 << 61,
632 bits => panic!("obj_size_bound: unknown pointer bit size {bits}"),
633 }
634 }
635
636 #[inline]
637 pub fn ptr_sized_integer(&self) -> Integer {
638 use Integer::*;
639 match self.pointer_offset().bits() {
640 16 => I16,
641 32 => I32,
642 64 => I64,
643 bits => panic!("ptr_sized_integer: unknown pointer bit size {bits}"),
644 }
645 }
646
647 #[inline]
648 pub fn ptr_sized_integer_in(&self, address_space: AddressSpace) -> Integer {
649 use Integer::*;
650 match self.pointer_offset_in(address_space).bits() {
651 16 => I16,
652 32 => I32,
653 64 => I64,
654 bits => panic!("ptr_sized_integer: unknown pointer bit size {bits}"),
655 }
656 }
657
658 #[inline]
660 fn cabi_vector_align(&self, vec_size: Size) -> Option<Align> {
661 self.vector_align
662 .iter()
663 .find(|(size, _align)| *size == vec_size)
664 .map(|(_size, align)| *align)
665 }
666
667 #[inline]
669 pub fn llvmlike_vector_align(&self, vec_size: Size) -> Align {
670 self.cabi_vector_align(vec_size)
671 .unwrap_or(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
672 }
673
674 #[inline]
676 pub fn pointer_size(&self) -> Size {
677 self.default_address_space_pointer_spec.pointer_size
678 }
679
680 #[inline]
682 pub fn pointer_size_in(&self, c: AddressSpace) -> Size {
683 if c == self.default_address_space {
684 return self.default_address_space_pointer_spec.pointer_size;
685 }
686
687 if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
688 e.1.pointer_size
689 } else {
690 panic!("Use of unknown address space {c:?}");
691 }
692 }
693
694 #[inline]
696 pub fn pointer_offset(&self) -> Size {
697 self.default_address_space_pointer_spec.pointer_offset
698 }
699
700 #[inline]
702 pub fn pointer_offset_in(&self, c: AddressSpace) -> Size {
703 if c == self.default_address_space {
704 return self.default_address_space_pointer_spec.pointer_offset;
705 }
706
707 if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
708 e.1.pointer_offset
709 } else {
710 panic!("Use of unknown address space {c:?}");
711 }
712 }
713
714 #[inline]
716 pub fn pointer_align(&self) -> AbiAlign {
717 AbiAlign::new(self.default_address_space_pointer_spec.pointer_align)
718 }
719
720 #[inline]
722 pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign {
723 AbiAlign::new(if c == self.default_address_space {
724 self.default_address_space_pointer_spec.pointer_align
725 } else if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
726 e.1.pointer_align
727 } else {
728 panic!("Use of unknown address space {c:?}");
729 })
730 }
731}
732
733pub trait HasDataLayout {
734 fn data_layout(&self) -> &TargetDataLayout;
735}
736
737impl HasDataLayout for TargetDataLayout {
738 #[inline]
739 fn data_layout(&self) -> &TargetDataLayout {
740 self
741 }
742}
743
744impl HasDataLayout for &TargetDataLayout {
746 #[inline]
747 fn data_layout(&self) -> &TargetDataLayout {
748 (**self).data_layout()
749 }
750}
751
752#[derive(Copy, Clone, PartialEq, Eq)]
754pub enum Endian {
755 Little,
756 Big,
757}
758
759impl Endian {
760 pub fn as_str(&self) -> &'static str {
761 match self {
762 Self::Little => "little",
763 Self::Big => "big",
764 }
765 }
766
767 #[cfg(feature = "nightly")]
768 pub fn desc_symbol(&self) -> Symbol {
769 match self {
770 Self::Little => sym::little,
771 Self::Big => sym::big,
772 }
773 }
774}
775
776impl fmt::Debug for Endian {
777 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778 f.write_str(self.as_str())
779 }
780}
781
782impl FromStr for Endian {
783 type Err = String;
784
785 fn from_str(s: &str) -> Result<Self, Self::Err> {
786 match s {
787 "little" => Ok(Self::Little),
788 "big" => Ok(Self::Big),
789 _ => Err(format!(r#"unknown endian: "{s}""#)),
790 }
791 }
792}
793
794#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
796#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
797pub struct Size {
798 raw: u64,
799}
800
801#[cfg(feature = "nightly")]
802impl StableOrd for Size {
803 const CAN_USE_UNSTABLE_SORT: bool = true;
804
805 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
808}
809
810impl fmt::Debug for Size {
812 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
813 write!(f, "Size({} bytes)", self.bytes())
814 }
815}
816
817impl Size {
818 pub const ZERO: Size = Size { raw: 0 };
819
820 pub fn from_bits(bits: impl TryInto<u64>) -> Size {
823 let bits = bits.try_into().ok().unwrap();
824 Size { raw: bits.div_ceil(8) }
825 }
826
827 #[inline]
828 pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
829 let bytes: u64 = bytes.try_into().ok().unwrap();
830 Size { raw: bytes }
831 }
832
833 #[inline]
834 pub fn bytes(self) -> u64 {
835 self.raw
836 }
837
838 #[inline]
839 pub fn bytes_usize(self) -> usize {
840 self.bytes().try_into().unwrap()
841 }
842
843 #[inline]
844 pub fn bits(self) -> u64 {
845 #[cold]
846 fn overflow(bytes: u64) -> ! {
847 panic!("Size::bits: {bytes} bytes in bits doesn't fit in u64")
848 }
849
850 self.bytes().checked_mul(8).unwrap_or_else(|| overflow(self.bytes()))
851 }
852
853 #[inline]
854 pub fn bits_usize(self) -> usize {
855 self.bits().try_into().unwrap()
856 }
857
858 #[inline]
859 pub fn align_to(self, align: Align) -> Size {
860 let mask = align.bytes() - 1;
861 Size::from_bytes((self.bytes() + mask) & !mask)
862 }
863
864 #[inline]
865 pub fn is_aligned(self, align: Align) -> bool {
866 let mask = align.bytes() - 1;
867 self.bytes() & mask == 0
868 }
869
870 #[inline]
871 pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: &C) -> Option<Size> {
872 let dl = cx.data_layout();
873
874 let bytes = self.bytes().checked_add(offset.bytes())?;
875
876 if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
877 }
878
879 #[inline]
880 pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: &C) -> Option<Size> {
881 let dl = cx.data_layout();
882
883 let bytes = self.bytes().checked_mul(count)?;
884 if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
885 }
886
887 #[inline]
890 pub fn sign_extend(self, value: u128) -> i128 {
891 let size = self.bits();
892 if size == 0 {
893 return 0;
895 }
896 let shift = 128 - size;
898 ((value << shift) as i128) >> shift
901 }
902
903 #[inline]
905 pub fn truncate(self, value: u128) -> u128 {
906 let size = self.bits();
907 if size == 0 {
908 return 0;
910 }
911 let shift = 128 - size;
912 (value << shift) >> shift
914 }
915
916 #[inline]
917 pub fn signed_int_min(&self) -> i128 {
918 self.sign_extend(1_u128 << (self.bits() - 1))
919 }
920
921 #[inline]
922 pub fn signed_int_max(&self) -> i128 {
923 i128::MAX >> (128 - self.bits())
924 }
925
926 #[inline]
927 pub fn unsigned_int_max(&self) -> u128 {
928 u128::MAX >> (128 - self.bits())
929 }
930}
931
932impl Add for Size {
936 type Output = Size;
937 #[inline]
938 fn add(self, other: Size) -> Size {
939 Size::from_bytes(self.bytes().checked_add(other.bytes()).unwrap_or_else(|| {
940 panic!("Size::add: {} + {} doesn't fit in u64", self.bytes(), other.bytes())
941 }))
942 }
943}
944
945impl Sub for Size {
946 type Output = Size;
947 #[inline]
948 fn sub(self, other: Size) -> Size {
949 Size::from_bytes(self.bytes().checked_sub(other.bytes()).unwrap_or_else(|| {
950 panic!("Size::sub: {} - {} would result in negative size", self.bytes(), other.bytes())
951 }))
952 }
953}
954
955impl Mul<Size> for u64 {
956 type Output = Size;
957 #[inline]
958 fn mul(self, size: Size) -> Size {
959 size * self
960 }
961}
962
963impl Mul<u64> for Size {
964 type Output = Size;
965 #[inline]
966 fn mul(self, count: u64) -> Size {
967 match self.bytes().checked_mul(count) {
968 Some(bytes) => Size::from_bytes(bytes),
969 None => panic!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count),
970 }
971 }
972}
973
974impl AddAssign for Size {
975 #[inline]
976 fn add_assign(&mut self, other: Size) {
977 *self = *self + other;
978 }
979}
980
981#[cfg(feature = "nightly")]
982impl Step for Size {
983 #[inline]
984 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
985 u64::steps_between(&start.bytes(), &end.bytes())
986 }
987
988 #[inline]
989 fn forward_checked(start: Self, count: usize) -> Option<Self> {
990 u64::forward_checked(start.bytes(), count).map(Self::from_bytes)
991 }
992
993 #[inline]
994 fn forward(start: Self, count: usize) -> Self {
995 Self::from_bytes(u64::forward(start.bytes(), count))
996 }
997
998 #[inline]
999 unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
1000 Self::from_bytes(unsafe { u64::forward_unchecked(start.bytes(), count) })
1001 }
1002
1003 #[inline]
1004 fn backward_checked(start: Self, count: usize) -> Option<Self> {
1005 u64::backward_checked(start.bytes(), count).map(Self::from_bytes)
1006 }
1007
1008 #[inline]
1009 fn backward(start: Self, count: usize) -> Self {
1010 Self::from_bytes(u64::backward(start.bytes(), count))
1011 }
1012
1013 #[inline]
1014 unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
1015 Self::from_bytes(unsafe { u64::backward_unchecked(start.bytes(), count) })
1016 }
1017}
1018
1019#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1021#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
1022pub struct Align {
1023 pow2: u8,
1024}
1025
1026impl fmt::Debug for Align {
1028 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1029 write!(f, "Align({} bytes)", self.bytes())
1030 }
1031}
1032
1033#[derive(Clone, Copy)]
1034pub enum AlignFromBytesError {
1035 NotPowerOfTwo(u64),
1036 TooLarge(u64),
1037}
1038
1039impl fmt::Debug for AlignFromBytesError {
1040 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1041 fmt::Display::fmt(self, f)
1042 }
1043}
1044
1045impl fmt::Display for AlignFromBytesError {
1046 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1047 match self {
1048 AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "{align} is not a power of 2"),
1049 AlignFromBytesError::TooLarge(align) => write!(f, "{align} is too large"),
1050 }
1051 }
1052}
1053
1054impl Align {
1055 pub const ONE: Align = Align { pow2: 0 };
1056 pub const EIGHT: Align = Align { pow2: 3 };
1057 pub const MAX: Align = Align { pow2: 29 };
1059
1060 #[inline]
1062 pub fn max_for_target(tdl: &TargetDataLayout) -> Align {
1063 let pointer_bits = tdl.pointer_size().bits();
1064 if let Ok(pointer_bits) = u8::try_from(pointer_bits)
1065 && pointer_bits <= Align::MAX.pow2
1066 {
1067 Align { pow2: pointer_bits - 1 }
1068 } else {
1069 Align::MAX
1070 }
1071 }
1072
1073 #[inline]
1074 pub fn from_bits(bits: u64) -> Result<Align, AlignFromBytesError> {
1075 Align::from_bytes(Size::from_bits(bits).bytes())
1076 }
1077
1078 #[inline]
1079 pub const fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
1080 if align == 0 {
1082 return Ok(Align::ONE);
1083 }
1084
1085 #[cold]
1086 const fn not_power_of_2(align: u64) -> AlignFromBytesError {
1087 AlignFromBytesError::NotPowerOfTwo(align)
1088 }
1089
1090 #[cold]
1091 const fn too_large(align: u64) -> AlignFromBytesError {
1092 AlignFromBytesError::TooLarge(align)
1093 }
1094
1095 let tz = align.trailing_zeros();
1096 if align != (1 << tz) {
1097 return Err(not_power_of_2(align));
1098 }
1099
1100 let pow2 = tz as u8;
1101 if pow2 > Self::MAX.pow2 {
1102 return Err(too_large(align));
1103 }
1104
1105 Ok(Align { pow2 })
1106 }
1107
1108 #[inline]
1109 pub const fn bytes(self) -> u64 {
1110 1 << self.pow2
1111 }
1112
1113 #[inline]
1114 pub fn bytes_usize(self) -> usize {
1115 self.bytes().try_into().unwrap()
1116 }
1117
1118 #[inline]
1119 pub const fn bits(self) -> u64 {
1120 self.bytes() * 8
1121 }
1122
1123 #[inline]
1124 pub fn bits_usize(self) -> usize {
1125 self.bits().try_into().unwrap()
1126 }
1127
1128 #[inline]
1133 pub fn max_aligned_factor(size: Size) -> Align {
1134 Align { pow2: size.bytes().trailing_zeros() as u8 }
1135 }
1136
1137 #[inline]
1139 pub fn restrict_for_offset(self, size: Size) -> Align {
1140 self.min(Align::max_aligned_factor(size))
1141 }
1142}
1143
1144#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1154#[cfg_attr(feature = "nightly", derive(StableHash))]
1155pub struct AbiAlign {
1156 pub abi: Align,
1157}
1158
1159impl AbiAlign {
1160 #[inline]
1161 pub fn new(align: Align) -> AbiAlign {
1162 AbiAlign { abi: align }
1163 }
1164
1165 #[inline]
1166 pub fn min(self, other: AbiAlign) -> AbiAlign {
1167 AbiAlign { abi: self.abi.min(other.abi) }
1168 }
1169
1170 #[inline]
1171 pub fn max(self, other: AbiAlign) -> AbiAlign {
1172 AbiAlign { abi: self.abi.max(other.abi) }
1173 }
1174}
1175
1176impl Deref for AbiAlign {
1177 type Target = Align;
1178
1179 fn deref(&self) -> &Self::Target {
1180 &self.abi
1181 }
1182}
1183
1184#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
1186#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
1187pub enum Integer {
1188 I8,
1189 I16,
1190 I32,
1191 I64,
1192 I128,
1193}
1194
1195impl Integer {
1196 pub fn int_ty_str(self) -> &'static str {
1197 use Integer::*;
1198 match self {
1199 I8 => "i8",
1200 I16 => "i16",
1201 I32 => "i32",
1202 I64 => "i64",
1203 I128 => "i128",
1204 }
1205 }
1206
1207 pub fn uint_ty_str(self) -> &'static str {
1208 use Integer::*;
1209 match self {
1210 I8 => "u8",
1211 I16 => "u16",
1212 I32 => "u32",
1213 I64 => "u64",
1214 I128 => "u128",
1215 }
1216 }
1217
1218 #[inline]
1219 pub fn size(self) -> Size {
1220 use Integer::*;
1221 match self {
1222 I8 => Size::from_bytes(1),
1223 I16 => Size::from_bytes(2),
1224 I32 => Size::from_bytes(4),
1225 I64 => Size::from_bytes(8),
1226 I128 => Size::from_bytes(16),
1227 }
1228 }
1229
1230 pub fn from_attr<C: HasDataLayout>(cx: &C, ity: IntegerType) -> Integer {
1232 let dl = cx.data_layout();
1233
1234 match ity {
1235 IntegerType::Pointer(_) => dl.ptr_sized_integer(),
1236 IntegerType::Fixed(x, _) => x,
1237 }
1238 }
1239
1240 pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAlign {
1241 use Integer::*;
1242 let dl = cx.data_layout();
1243
1244 AbiAlign::new(match self {
1245 I8 => dl.i8_align,
1246 I16 => dl.i16_align,
1247 I32 => dl.i32_align,
1248 I64 => dl.i64_align,
1249 I128 => dl.i128_align,
1250 })
1251 }
1252
1253 #[inline]
1255 pub fn signed_max(self) -> i128 {
1256 use Integer::*;
1257 match self {
1258 I8 => i8::MAX as i128,
1259 I16 => i16::MAX as i128,
1260 I32 => i32::MAX as i128,
1261 I64 => i64::MAX as i128,
1262 I128 => i128::MAX,
1263 }
1264 }
1265
1266 #[inline]
1268 pub fn signed_min(self) -> i128 {
1269 use Integer::*;
1270 match self {
1271 I8 => i8::MIN as i128,
1272 I16 => i16::MIN as i128,
1273 I32 => i32::MIN as i128,
1274 I64 => i64::MIN as i128,
1275 I128 => i128::MIN,
1276 }
1277 }
1278
1279 #[inline]
1281 pub fn fit_signed(x: i128) -> Integer {
1282 use Integer::*;
1283 match x {
1284 -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8,
1285 -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16,
1286 -0x0000_0000_8000_0000..=0x0000_0000_7fff_ffff => I32,
1287 -0x8000_0000_0000_0000..=0x7fff_ffff_ffff_ffff => I64,
1288 _ => I128,
1289 }
1290 }
1291
1292 #[inline]
1294 pub fn fit_unsigned(x: u128) -> Integer {
1295 use Integer::*;
1296 match x {
1297 0..=0x0000_0000_0000_00ff => I8,
1298 0..=0x0000_0000_0000_ffff => I16,
1299 0..=0x0000_0000_ffff_ffff => I32,
1300 0..=0xffff_ffff_ffff_ffff => I64,
1301 _ => I128,
1302 }
1303 }
1304
1305 pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
1307 use Integer::*;
1308 let dl = cx.data_layout();
1309
1310 [I8, I16, I32, I64, I128].into_iter().find(|&candidate| {
1311 wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes()
1312 })
1313 }
1314
1315 pub fn approximate_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Integer {
1317 use Integer::*;
1318 let dl = cx.data_layout();
1319
1320 for candidate in [I64, I32, I16] {
1322 if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
1323 return candidate;
1324 }
1325 }
1326 I8
1327 }
1328
1329 #[inline]
1332 pub fn from_size(size: Size) -> Result<Self, String> {
1333 match size.bits() {
1334 8 => Ok(Integer::I8),
1335 16 => Ok(Integer::I16),
1336 32 => Ok(Integer::I32),
1337 64 => Ok(Integer::I64),
1338 128 => Ok(Integer::I128),
1339 _ => Err(format!("rust does not support integers with {} bits", size.bits())),
1340 }
1341 }
1342}
1343
1344#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
1346#[cfg_attr(feature = "nightly", derive(StableHash))]
1347pub enum Float {
1348 F16,
1349 F32,
1350 F64,
1351 F128,
1352}
1353
1354impl Float {
1355 pub fn size(self) -> Size {
1356 use Float::*;
1357
1358 match self {
1359 F16 => Size::from_bits(16),
1360 F32 => Size::from_bits(32),
1361 F64 => Size::from_bits(64),
1362 F128 => Size::from_bits(128),
1363 }
1364 }
1365
1366 pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAlign {
1367 use Float::*;
1368 let dl = cx.data_layout();
1369
1370 AbiAlign::new(match self {
1371 F16 => dl.f16_align,
1372 F32 => dl.f32_align,
1373 F64 => dl.f64_align,
1374 F128 => dl.f128_align,
1375 })
1376 }
1377}
1378
1379#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1381#[cfg_attr(feature = "nightly", derive(StableHash))]
1382pub enum Primitive {
1383 Int(Integer, bool),
1391 Float(Float),
1392 Pointer(AddressSpace),
1393}
1394
1395impl Primitive {
1396 pub fn size<C: HasDataLayout>(self, cx: &C) -> Size {
1397 use Primitive::*;
1398 let dl = cx.data_layout();
1399
1400 match self {
1401 Int(i, _) => i.size(),
1402 Float(f) => f.size(),
1403 Pointer(a) => dl.pointer_size_in(a),
1404 }
1405 }
1406
1407 pub fn default_align<C: HasDataLayout>(self, cx: &C) -> AbiAlign {
1412 use Primitive::*;
1413 let dl = cx.data_layout();
1414
1415 match self {
1416 Int(i, _) => i.align(dl),
1417 Float(f) => f.align(dl),
1418 Pointer(a) => dl.pointer_align_in(a),
1419 }
1420 }
1421}
1422
1423#[derive(Clone, Copy, PartialEq, Eq, Hash)]
1433#[cfg_attr(feature = "nightly", derive(StableHash))]
1434pub struct WrappingRange {
1435 pub start: u128,
1436 pub end: u128,
1437}
1438
1439impl WrappingRange {
1440 pub fn full(size: Size) -> Self {
1441 Self { start: 0, end: size.unsigned_int_max() }
1442 }
1443
1444 #[inline(always)]
1446 pub fn contains(&self, v: u128) -> bool {
1447 if self.start <= self.end {
1448 self.start <= v && v <= self.end
1449 } else {
1450 self.start <= v || v <= self.end
1451 }
1452 }
1453
1454 #[inline(always)]
1457 pub fn contains_range(&self, other: Self, size: Size) -> bool {
1458 if self.is_full_for(size) {
1459 true
1460 } else {
1461 let trunc = |x| size.truncate(x);
1462
1463 let delta = self.start;
1464 let max = trunc(self.end.wrapping_sub(delta));
1465
1466 let other_start = trunc(other.start.wrapping_sub(delta));
1467 let other_end = trunc(other.end.wrapping_sub(delta));
1468
1469 (other_start <= other_end) && (other_end <= max)
1473 }
1474 }
1475
1476 #[inline(always)]
1478 fn with_start(mut self, start: u128) -> Self {
1479 self.start = start;
1480 self
1481 }
1482
1483 #[inline(always)]
1485 fn with_end(mut self, end: u128) -> Self {
1486 self.end = end;
1487 self
1488 }
1489
1490 #[inline]
1496 fn is_full_for(&self, size: Size) -> bool {
1497 let max_value = size.unsigned_int_max();
1498 debug_assert!(self.start <= max_value && self.end <= max_value);
1499 self.start == (self.end.wrapping_add(1) & max_value)
1500 }
1501
1502 #[inline]
1508 pub fn no_unsigned_wraparound(&self, size: Size) -> Result<bool, RangeFull> {
1509 if self.is_full_for(size) { Err(..) } else { Ok(self.start <= self.end) }
1510 }
1511
1512 #[inline]
1521 pub fn no_signed_wraparound(&self, size: Size) -> Result<bool, RangeFull> {
1522 if self.is_full_for(size) {
1523 Err(..)
1524 } else {
1525 let start: i128 = size.sign_extend(self.start);
1526 let end: i128 = size.sign_extend(self.end);
1527 Ok(start <= end)
1528 }
1529 }
1530}
1531
1532impl fmt::Debug for WrappingRange {
1533 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1534 if self.start > self.end {
1535 write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
1536 } else {
1537 write!(fmt, "{}..={}", self.start, self.end)?;
1538 }
1539 Ok(())
1540 }
1541}
1542
1543#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1545#[cfg_attr(feature = "nightly", derive(StableHash))]
1546pub enum Scalar {
1547 Initialized {
1548 value: Primitive,
1549
1550 valid_range: WrappingRange,
1554 },
1555 Union {
1556 value: Primitive,
1562 },
1563}
1564
1565impl Scalar {
1566 #[inline]
1567 pub fn is_bool(&self) -> bool {
1568 use Integer::*;
1569 matches!(
1570 self,
1571 Scalar::Initialized {
1572 value: Primitive::Int(I8, false),
1573 valid_range: WrappingRange { start: 0, end: 1 }
1574 }
1575 )
1576 }
1577
1578 pub fn primitive(&self) -> Primitive {
1581 match *self {
1582 Scalar::Initialized { value, .. } | Scalar::Union { value } => value,
1583 }
1584 }
1585
1586 pub fn default_align(self, cx: &impl HasDataLayout) -> AbiAlign {
1591 self.primitive().default_align(cx)
1592 }
1593
1594 pub fn size(self, cx: &impl HasDataLayout) -> Size {
1595 self.primitive().size(cx)
1596 }
1597
1598 #[inline]
1599 pub fn to_union(&self) -> Self {
1600 Self::Union { value: self.primitive() }
1601 }
1602
1603 #[inline]
1604 pub fn valid_range(&self, cx: &impl HasDataLayout) -> WrappingRange {
1605 match *self {
1606 Scalar::Initialized { valid_range, .. } => valid_range,
1607 Scalar::Union { value } => WrappingRange::full(value.size(cx)),
1608 }
1609 }
1610
1611 #[inline]
1612 pub fn valid_range_mut(&mut self) -> &mut WrappingRange {
1615 match self {
1616 Scalar::Initialized { valid_range, .. } => valid_range,
1617 Scalar::Union { .. } => panic!("cannot change the valid range of a union"),
1618 }
1619 }
1620
1621 #[inline]
1624 pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
1625 match *self {
1626 Scalar::Initialized { valid_range, .. } => valid_range.is_full_for(self.size(cx)),
1627 Scalar::Union { .. } => true,
1628 }
1629 }
1630
1631 #[inline]
1633 pub fn is_uninit_valid(&self) -> bool {
1634 match *self {
1635 Scalar::Initialized { .. } => false,
1636 Scalar::Union { .. } => true,
1637 }
1638 }
1639
1640 #[inline]
1642 pub fn is_signed(&self) -> bool {
1643 match self.primitive() {
1644 Primitive::Int(_, signed) => signed,
1645 _ => false,
1646 }
1647 }
1648}
1649
1650#[derive(PartialEq, Eq, Hash, Clone, Debug)]
1653#[cfg_attr(feature = "nightly", derive(StableHash))]
1654pub enum FieldsShape<FieldIdx: Idx> {
1655 Primitive,
1657
1658 Union(NonZeroUsize),
1660
1661 Array { stride: Size, count: u64 },
1663
1664 Arbitrary {
1672 offsets: IndexVec<FieldIdx, Size>,
1677
1678 in_memory_order: IndexVec<u32, FieldIdx>,
1686 },
1687}
1688
1689impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
1690 #[inline]
1691 pub fn count(&self) -> usize {
1692 match *self {
1693 FieldsShape::Primitive => 0,
1694 FieldsShape::Union(count) => count.get(),
1695 FieldsShape::Array { count, .. } => count.try_into().unwrap(),
1696 FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
1697 }
1698 }
1699
1700 #[inline]
1701 pub fn offset(&self, i: usize) -> Size {
1702 match *self {
1703 FieldsShape::Primitive => {
1704 unreachable!("FieldsShape::offset: `Primitive`s have no fields")
1705 }
1706 FieldsShape::Union(count) => {
1707 assert!(i < count.get(), "tried to access field {i} of union with {count} fields");
1708 Size::ZERO
1709 }
1710 FieldsShape::Array { stride, count } => {
1711 let i = u64::try_from(i).unwrap();
1712 assert!(i < count, "tried to access field {i} of array with {count} fields");
1713 stride * i
1714 }
1715 FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::new(i)],
1716 }
1717 }
1718
1719 #[inline]
1721 pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> {
1722 let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() };
1726
1727 (0..pseudofield_count).map(move |i| match self {
1728 FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
1729 FieldsShape::Arbitrary { in_memory_order, .. } => in_memory_order[i as u32].index(),
1730 })
1731 }
1732}
1733
1734#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1738#[cfg_attr(feature = "nightly", derive(StableHash))]
1739pub struct AddressSpace(pub u32);
1740
1741impl AddressSpace {
1742 pub const ZERO: Self = AddressSpace(0);
1744 pub const GPU_WORKGROUP: Self = AddressSpace(3);
1747}
1748
1749#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1751#[cfg_attr(feature = "nightly", derive(StableHash))]
1752pub struct NumScalableVectors(pub u8);
1753
1754impl NumScalableVectors {
1755 pub fn for_non_tuple() -> Self {
1757 NumScalableVectors(1)
1758 }
1759
1760 pub fn from_field_count(count: usize) -> Option<Self> {
1764 match count {
1765 2..8 => Some(NumScalableVectors(count as u8)),
1766 _ => None,
1767 }
1768 }
1769}
1770
1771#[cfg(feature = "nightly")]
1772impl IntoDiagArg for NumScalableVectors {
1773 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
1774 DiagArgValue::Str(std::borrow::Cow::Borrowed(match self.0 {
1775 0 => panic!("`NumScalableVectors(0)` is illformed"),
1776 1 => "one",
1777 2 => "two",
1778 3 => "three",
1779 4 => "four",
1780 5 => "five",
1781 6 => "six",
1782 7 => "seven",
1783 8 => "eight",
1784 _ => panic!("`NumScalableVectors(N)` for N>8 is illformed"),
1785 }))
1786 }
1787}
1788
1789#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1800#[cfg_attr(feature = "nightly", derive(StableHash))]
1801pub enum BackendRepr {
1802 Scalar(Scalar),
1803 ScalarPair(Scalar, Scalar),
1812 SimdScalableVector {
1813 element: Scalar,
1814 count: u64,
1815 number_of_vectors: NumScalableVectors,
1816 },
1817 SimdVector {
1818 element: Scalar,
1819 count: u64,
1820 },
1821 Memory {
1823 sized: bool,
1825 },
1826}
1827
1828impl BackendRepr {
1829 #[inline]
1831 pub fn is_unsized(&self) -> bool {
1832 match *self {
1833 BackendRepr::Scalar(_)
1834 | BackendRepr::ScalarPair(..)
1835 | BackendRepr::SimdScalableVector { .. }
1841 | BackendRepr::SimdVector { .. } => false,
1842 BackendRepr::Memory { sized } => !sized,
1843 }
1844 }
1845
1846 #[inline]
1847 pub fn is_sized(&self) -> bool {
1848 !self.is_unsized()
1849 }
1850
1851 #[inline]
1854 pub fn is_signed(&self) -> bool {
1855 match self {
1856 BackendRepr::Scalar(scal) => scal.is_signed(),
1857 _ => panic!("`is_signed` on non-scalar ABI {self:?}"),
1858 }
1859 }
1860
1861 #[inline]
1863 pub fn is_scalar(&self) -> bool {
1864 matches!(*self, BackendRepr::Scalar(_))
1865 }
1866
1867 #[inline]
1869 pub fn is_bool(&self) -> bool {
1870 matches!(*self, BackendRepr::Scalar(s) if s.is_bool())
1871 }
1872
1873 pub fn scalar_platform_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
1881 match *self {
1882 BackendRepr::Scalar(s) => Some(s.default_align(cx).abi),
1883 BackendRepr::ScalarPair(s1, s2) => {
1884 Some(s1.default_align(cx).max(s2.default_align(cx)).abi)
1885 }
1886 BackendRepr::SimdVector { .. }
1888 | BackendRepr::Memory { .. }
1889 | BackendRepr::SimdScalableVector { .. } => None,
1890 }
1891 }
1892
1893 pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
1897 match *self {
1898 BackendRepr::Scalar(s) => Some(s.size(cx)),
1900 BackendRepr::ScalarPair(s1, s2) => {
1902 let field2_offset = s1.size(cx).align_to(s2.default_align(cx).abi);
1903 let size = (field2_offset + s2.size(cx)).align_to(
1904 self.scalar_platform_align(cx)
1905 .unwrap(),
1907 );
1908 Some(size)
1909 }
1910 BackendRepr::SimdVector { .. }
1912 | BackendRepr::Memory { .. }
1913 | BackendRepr::SimdScalableVector { .. } => None,
1914 }
1915 }
1916
1917 pub fn to_union(&self) -> Self {
1919 match *self {
1920 BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()),
1921 BackendRepr::ScalarPair(s1, s2) => {
1922 BackendRepr::ScalarPair(s1.to_union(), s2.to_union())
1923 }
1924 BackendRepr::SimdVector { element, count } => {
1925 BackendRepr::SimdVector { element: element.to_union(), count }
1926 }
1927 BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
1928 BackendRepr::SimdScalableVector { element, count, number_of_vectors } => {
1929 BackendRepr::SimdScalableVector {
1930 element: element.to_union(),
1931 count,
1932 number_of_vectors,
1933 }
1934 }
1935 }
1936 }
1937
1938 pub fn eq_up_to_validity(&self, other: &Self) -> bool {
1939 match (self, other) {
1940 (BackendRepr::Scalar(l), BackendRepr::Scalar(r)) => l.primitive() == r.primitive(),
1943 (
1944 BackendRepr::SimdVector { element: element_l, count: count_l },
1945 BackendRepr::SimdVector { element: element_r, count: count_r },
1946 ) => element_l.primitive() == element_r.primitive() && count_l == count_r,
1947 (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => {
1948 l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive()
1949 }
1950 _ => self == other,
1952 }
1953 }
1954}
1955
1956#[derive(PartialEq, Eq, Hash, Clone, Debug)]
1958#[cfg_attr(feature = "nightly", derive(StableHash))]
1959pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
1960 Empty,
1962
1963 Single {
1965 index: VariantIdx,
1967 },
1968
1969 Multiple {
1976 tag: Scalar,
1977 tag_encoding: TagEncoding<VariantIdx>,
1978 tag_field: FieldIdx,
1979 variants: IndexVec<VariantIdx, VariantLayout<FieldIdx>>,
1980 },
1981}
1982
1983#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
1985#[cfg_attr(feature = "nightly", derive(StableHash))]
1986pub enum TagEncoding<VariantIdx: Idx> {
1987 Direct,
1990
1991 Niche {
2015 untagged_variant: VariantIdx,
2016 niche_variants: RangeInclusive<VariantIdx>,
2019 niche_start: u128,
2022 },
2023}
2024
2025#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
2026#[cfg_attr(feature = "nightly", derive(StableHash))]
2027pub struct Niche {
2028 pub offset: Size,
2029 pub value: Primitive,
2030 pub valid_range: WrappingRange,
2031}
2032
2033impl Niche {
2034 pub fn from_scalar<C: HasDataLayout>(cx: &C, offset: Size, scalar: Scalar) -> Option<Self> {
2035 let Scalar::Initialized { value, valid_range } = scalar else { return None };
2036 let niche = Niche { offset, value, valid_range };
2037 if niche.available(cx) > 0 { Some(niche) } else { None }
2038 }
2039
2040 pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
2041 let Self { value, valid_range: v, .. } = *self;
2042 let size = value.size(cx);
2043 assert!(size.bits() <= 128);
2044 let max_value = size.unsigned_int_max();
2045
2046 let niche = v.end.wrapping_add(1)..v.start;
2048 niche.end.wrapping_sub(niche.start) & max_value
2049 }
2050
2051 pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
2052 assert!(count > 0);
2053
2054 let Self { value, valid_range: v, .. } = *self;
2055 let size = value.size(cx);
2056 assert!(size.bits() <= 128);
2057 let max_value = size.unsigned_int_max();
2058
2059 let available = v.start.wrapping_sub(v.end).wrapping_sub(1) & max_value;
2060 if count > available {
2061 return None;
2062 }
2063
2064 let move_start = |v: WrappingRange| {
2078 let start = v.start.wrapping_sub(count) & max_value;
2079 Some((start, Scalar::Initialized { value, valid_range: v.with_start(start) }))
2080 };
2081 let move_end = |v: WrappingRange| {
2082 let start = v.end.wrapping_add(1) & max_value;
2083 let end = v.end.wrapping_add(count) & max_value;
2084 Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
2085 };
2086 let distance_end_zero = max_value - v.end;
2087 let is_bool = size.bytes() == 1 && v == WrappingRange { start: 0, end: 1 };
2090 if count == 1 && !is_bool {
2091 let next_up = size.sign_extend(v.end.wrapping_add(1)).unsigned_abs();
2096 let next_down = size.sign_extend(v.start.wrapping_sub(1)).unsigned_abs();
2097 if next_down <= next_up { move_start(v) } else { move_end(v) }
2098 } else if v.start > v.end {
2099 move_end(v)
2101 } else if v.start <= distance_end_zero {
2102 if count <= v.start {
2103 move_start(v)
2104 } else {
2105 move_end(v)
2107 }
2108 } else {
2109 let end = v.end.wrapping_add(count) & max_value;
2110 let overshot_zero = (1..=v.end).contains(&end);
2111 if overshot_zero {
2112 move_start(v)
2114 } else {
2115 move_end(v)
2116 }
2117 }
2118 }
2119}
2120
2121#[derive(PartialEq, Eq, Hash, Clone)]
2123#[cfg_attr(feature = "nightly", derive(StableHash))]
2124pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
2125 pub fields: FieldsShape<FieldIdx>,
2127
2128 pub variants: Variants<FieldIdx, VariantIdx>,
2136
2137 pub backend_repr: BackendRepr,
2145
2146 pub largest_niche: Option<Niche>,
2149 pub uninhabited: bool,
2154
2155 pub align: AbiAlign,
2156 pub size: Size,
2157
2158 pub max_repr_align: Option<Align>,
2162
2163 pub unadjusted_abi_align: Align,
2167
2168 pub randomization_seed: Hash64,
2179}
2180
2181impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
2182 pub fn is_aggregate(&self) -> bool {
2184 match self.backend_repr {
2185 BackendRepr::Scalar(_)
2186 | BackendRepr::SimdVector { .. }
2187 | BackendRepr::SimdScalableVector { .. } => false,
2188 BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
2189 }
2190 }
2191
2192 pub fn is_uninhabited(&self) -> bool {
2194 self.uninhabited
2195 }
2196}
2197
2198impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
2199where
2200 FieldsShape<FieldIdx>: fmt::Debug,
2201 Variants<FieldIdx, VariantIdx>: fmt::Debug,
2202{
2203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2204 let LayoutData {
2208 size,
2209 align,
2210 backend_repr,
2211 fields,
2212 largest_niche,
2213 uninhabited,
2214 variants,
2215 max_repr_align,
2216 unadjusted_abi_align,
2217 randomization_seed,
2218 } = self;
2219 f.debug_struct("Layout")
2220 .field("size", size)
2221 .field("align", align)
2222 .field("backend_repr", backend_repr)
2223 .field("fields", fields)
2224 .field("largest_niche", largest_niche)
2225 .field("uninhabited", uninhabited)
2226 .field("variants", variants)
2227 .field("max_repr_align", max_repr_align)
2228 .field("unadjusted_abi_align", unadjusted_abi_align)
2229 .field("randomization_seed", randomization_seed)
2230 .finish()
2231 }
2232}
2233
2234#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2235pub enum PointerKind {
2236 SharedRef { frozen: bool },
2238 MutableRef { unpin: bool },
2240 Box { unpin: bool, global: bool },
2243}
2244
2245#[derive(Copy, Clone, Debug)]
2251pub struct PointeeInfo {
2252 pub safe: Option<PointerKind>,
2254 pub size: Size,
2261 pub align: Align,
2263}
2264
2265impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
2266 #[inline]
2268 pub fn is_unsized(&self) -> bool {
2269 self.backend_repr.is_unsized()
2270 }
2271
2272 #[inline]
2273 pub fn is_sized(&self) -> bool {
2274 self.backend_repr.is_sized()
2275 }
2276
2277 pub fn is_1zst(&self) -> bool {
2279 self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1
2280 }
2281
2282 pub fn is_scalable_vector(&self) -> bool {
2284 matches!(self.backend_repr, BackendRepr::SimdScalableVector { .. })
2285 }
2286
2287 pub fn scalable_vector_element_count(&self) -> Option<u64> {
2289 match self.backend_repr {
2290 BackendRepr::SimdScalableVector { count, .. } => Some(count),
2291 _ => None,
2292 }
2293 }
2294
2295 pub fn is_zst(&self) -> bool {
2300 match self.backend_repr {
2301 BackendRepr::Scalar(_)
2302 | BackendRepr::ScalarPair(..)
2303 | BackendRepr::SimdScalableVector { .. }
2304 | BackendRepr::SimdVector { .. } => false,
2305 BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
2306 }
2307 }
2308
2309 pub fn eq_abi(&self, other: &Self) -> bool {
2315 self.size == other.size
2319 && self.is_sized() == other.is_sized()
2320 && self.backend_repr.eq_up_to_validity(&other.backend_repr)
2321 && self.backend_repr.is_bool() == other.backend_repr.is_bool()
2322 && self.align.abi == other.align.abi
2323 && self.max_repr_align == other.max_repr_align
2324 && self.unadjusted_abi_align == other.unadjusted_abi_align
2325 }
2326}
2327
2328#[derive(Copy, Clone, Debug)]
2329pub enum StructKind {
2330 AlwaysSized,
2332 MaybeUnsized,
2334 Prefixed(Size, Align),
2336}
2337
2338#[derive(Clone, Debug)]
2339pub enum AbiFromStrErr {
2340 Unknown,
2342 NoExplicitUnwind,
2344}
2345
2346#[derive(PartialEq, Eq, Hash, Clone, Debug)]
2348#[cfg_attr(feature = "nightly", derive(StableHash))]
2349pub struct VariantLayout<FieldIdx: Idx> {
2350 pub size: Size,
2351 pub backend_repr: BackendRepr,
2352 pub field_offsets: IndexVec<FieldIdx, Size>,
2353 fields_in_memory_order: IndexVec<u32, FieldIdx>,
2354 largest_niche: Option<Niche>,
2355 uninhabited: bool,
2356}
2357
2358impl<FieldIdx: Idx> VariantLayout<FieldIdx> {
2359 pub fn from_layout(layout: LayoutData<FieldIdx, impl Idx>) -> Self {
2360 let FieldsShape::Arbitrary { offsets, in_memory_order } = layout.fields else {
2361 panic!("Layout of fields should be Arbitrary for variants");
2362 };
2363
2364 Self {
2365 size: layout.size,
2366 backend_repr: layout.backend_repr,
2367 field_offsets: offsets,
2368 fields_in_memory_order: in_memory_order,
2369 largest_niche: layout.largest_niche,
2370 uninhabited: layout.uninhabited,
2371 }
2372 }
2373
2374 pub fn is_uninhabited(&self) -> bool {
2375 self.uninhabited
2376 }
2377
2378 pub fn has_fields(&self) -> bool {
2379 self.field_offsets.len() > 0
2380 }
2381}