• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))]
2 
3 use std::fmt;
4 #[cfg(feature = "nightly")]
5 use std::iter::Step;
6 use std::num::{NonZeroUsize, ParseIntError};
7 use std::ops::{Add, AddAssign, Mul, RangeInclusive, Sub};
8 use std::str::FromStr;
9 
10 use bitflags::bitflags;
11 use rustc_data_structures::intern::Interned;
12 use rustc_data_structures::stable_hasher::Hash64;
13 #[cfg(feature = "nightly")]
14 use rustc_data_structures::stable_hasher::StableOrd;
15 use rustc_index::{IndexSlice, IndexVec};
16 #[cfg(feature = "nightly")]
17 use rustc_macros::HashStable_Generic;
18 #[cfg(feature = "nightly")]
19 use rustc_macros::{Decodable, Encodable};
20 
21 mod layout;
22 
23 pub use layout::LayoutCalculator;
24 
25 /// Requirements for a `StableHashingContext` to be used in this crate.
26 /// This is a hack to allow using the `HashStable_Generic` derive macro
27 /// instead of implementing everything in `rustc_middle`.
28 pub trait HashStableContext {}
29 
30 use Integer::*;
31 use Primitive::*;
32 
33 bitflags! {
34     #[derive(Default)]
35     #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
36     pub struct ReprFlags: u8 {
37         const IS_C               = 1 << 0;
38         const IS_SIMD            = 1 << 1;
39         const IS_TRANSPARENT     = 1 << 2;
40         // Internal only for now. If true, don't reorder fields.
41         const IS_LINEAR          = 1 << 3;
42         // If true, the type's layout can be randomized using
43         // the seed stored in `ReprOptions.layout_seed`
44         const RANDOMIZE_LAYOUT   = 1 << 4;
45         // Any of these flags being set prevent field reordering optimisation.
46         const IS_UNOPTIMISABLE   = ReprFlags::IS_C.bits
47                                  | ReprFlags::IS_SIMD.bits
48                                  | ReprFlags::IS_LINEAR.bits;
49     }
50 }
51 
52 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
53 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
54 pub enum IntegerType {
55     /// Pointer sized integer type, i.e. isize and usize. The field shows signedness, that
56     /// is, `Pointer(true)` is isize.
57     Pointer(bool),
58     /// Fix sized integer type, e.g. i8, u32, i128 The bool field shows signedness, `Fixed(I8, false)` means `u8`
59     Fixed(Integer, bool),
60 }
61 
62 impl IntegerType {
is_signed(&self) -> bool63     pub fn is_signed(&self) -> bool {
64         match self {
65             IntegerType::Pointer(b) => *b,
66             IntegerType::Fixed(_, b) => *b,
67         }
68     }
69 }
70 
71 /// Represents the repr options provided by the user,
72 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
73 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
74 pub struct ReprOptions {
75     pub int: Option<IntegerType>,
76     pub align: Option<Align>,
77     pub pack: Option<Align>,
78     pub flags: ReprFlags,
79     /// The seed to be used for randomizing a type's layout
80     ///
81     /// Note: This could technically be a `Hash128` which would
82     /// be the "most accurate" hash as it'd encompass the item and crate
83     /// hash without loss, but it does pay the price of being larger.
84     /// Everything's a tradeoff, a 64-bit seed should be sufficient for our
85     /// purposes (primarily `-Z randomize-layout`)
86     pub field_shuffle_seed: Hash64,
87 }
88 
89 impl ReprOptions {
90     #[inline]
simd(&self) -> bool91     pub fn simd(&self) -> bool {
92         self.flags.contains(ReprFlags::IS_SIMD)
93     }
94 
95     #[inline]
c(&self) -> bool96     pub fn c(&self) -> bool {
97         self.flags.contains(ReprFlags::IS_C)
98     }
99 
100     #[inline]
packed(&self) -> bool101     pub fn packed(&self) -> bool {
102         self.pack.is_some()
103     }
104 
105     #[inline]
transparent(&self) -> bool106     pub fn transparent(&self) -> bool {
107         self.flags.contains(ReprFlags::IS_TRANSPARENT)
108     }
109 
110     #[inline]
linear(&self) -> bool111     pub fn linear(&self) -> bool {
112         self.flags.contains(ReprFlags::IS_LINEAR)
113     }
114 
115     /// Returns the discriminant type, given these `repr` options.
116     /// This must only be called on enums!
discr_type(&self) -> IntegerType117     pub fn discr_type(&self) -> IntegerType {
118         self.int.unwrap_or(IntegerType::Pointer(true))
119     }
120 
121     /// Returns `true` if this `#[repr()]` should inhabit "smart enum
122     /// layout" optimizations, such as representing `Foo<&T>` as a
123     /// single pointer.
inhibit_enum_layout_opt(&self) -> bool124     pub fn inhibit_enum_layout_opt(&self) -> bool {
125         self.c() || self.int.is_some()
126     }
127 
128     /// Returns `true` if this `#[repr()]` should inhibit struct field reordering
129     /// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr(<int>)`.
inhibit_struct_field_reordering_opt(&self) -> bool130     pub fn inhibit_struct_field_reordering_opt(&self) -> bool {
131         if let Some(pack) = self.pack {
132             if pack.bytes() == 1 {
133                 return true;
134             }
135         }
136 
137         self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
138     }
139 
140     /// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
141     /// was enabled for its declaration crate
can_randomize_type_layout(&self) -> bool142     pub fn can_randomize_type_layout(&self) -> bool {
143         !self.inhibit_struct_field_reordering_opt()
144             && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
145     }
146 
147     /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
inhibit_union_abi_opt(&self) -> bool148     pub fn inhibit_union_abi_opt(&self) -> bool {
149         self.c()
150     }
151 }
152 
153 /// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
154 /// for a target, which contains everything needed to compute layouts.
155 #[derive(Debug, PartialEq, Eq)]
156 pub struct TargetDataLayout {
157     pub endian: Endian,
158     pub i1_align: AbiAndPrefAlign,
159     pub i8_align: AbiAndPrefAlign,
160     pub i16_align: AbiAndPrefAlign,
161     pub i32_align: AbiAndPrefAlign,
162     pub i64_align: AbiAndPrefAlign,
163     pub i128_align: AbiAndPrefAlign,
164     pub f32_align: AbiAndPrefAlign,
165     pub f64_align: AbiAndPrefAlign,
166     pub pointer_size: Size,
167     pub pointer_align: AbiAndPrefAlign,
168     pub aggregate_align: AbiAndPrefAlign,
169 
170     /// Alignments for vector types.
171     pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
172 
173     pub instruction_address_space: AddressSpace,
174 
175     /// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
176     /// Note: This isn't in LLVM's data layout string, it is `short_enum`
177     /// so the only valid spec for LLVM is c_int::BITS or 8
178     pub c_enum_min_size: Integer,
179 }
180 
181 impl Default for TargetDataLayout {
182     /// Creates an instance of `TargetDataLayout`.
default() -> TargetDataLayout183     fn default() -> TargetDataLayout {
184         let align = |bits| Align::from_bits(bits).unwrap();
185         TargetDataLayout {
186             endian: Endian::Big,
187             i1_align: AbiAndPrefAlign::new(align(8)),
188             i8_align: AbiAndPrefAlign::new(align(8)),
189             i16_align: AbiAndPrefAlign::new(align(16)),
190             i32_align: AbiAndPrefAlign::new(align(32)),
191             i64_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
192             i128_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
193             f32_align: AbiAndPrefAlign::new(align(32)),
194             f64_align: AbiAndPrefAlign::new(align(64)),
195             pointer_size: Size::from_bits(64),
196             pointer_align: AbiAndPrefAlign::new(align(64)),
197             aggregate_align: AbiAndPrefAlign { abi: align(0), pref: align(64) },
198             vector_align: vec![
199                 (Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
200                 (Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
201             ],
202             instruction_address_space: AddressSpace::DATA,
203             c_enum_min_size: Integer::I32,
204         }
205     }
206 }
207 
208 pub enum TargetDataLayoutErrors<'a> {
209     InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
210     InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
211     MissingAlignment { cause: &'a str },
212     InvalidAlignment { cause: &'a str, err: AlignFromBytesError },
213     InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
214     InconsistentTargetPointerWidth { pointer_size: u64, target: u32 },
215     InvalidBitsSize { err: String },
216 }
217 
218 impl TargetDataLayout {
219     /// Parse data layout from an [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
220     ///
221     /// This function doesn't fill `c_enum_min_size` and it will always be `I32` since it can not be
222     /// determined from llvm string.
parse_from_llvm_datalayout_string<'a>( input: &'a str, ) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>>223     pub fn parse_from_llvm_datalayout_string<'a>(
224         input: &'a str,
225     ) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
226         // Parse an address space index from a string.
227         let parse_address_space = |s: &'a str, cause: &'a str| {
228             s.parse::<u32>().map(AddressSpace).map_err(|err| {
229                 TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
230             })
231         };
232 
233         // Parse a bit count from a string.
234         let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
235             s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
236                 kind,
237                 bit: s,
238                 cause,
239                 err,
240             })
241         };
242 
243         // Parse a size string.
244         let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
245 
246         // Parse an alignment string.
247         let align = |s: &[&'a str], cause: &'a str| {
248             if s.is_empty() {
249                 return Err(TargetDataLayoutErrors::MissingAlignment { cause });
250             }
251             let align_from_bits = |bits| {
252                 Align::from_bits(bits)
253                     .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
254             };
255             let abi = parse_bits(s[0], "alignment", cause)?;
256             let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?;
257             Ok(AbiAndPrefAlign { abi: align_from_bits(abi)?, pref: align_from_bits(pref)? })
258         };
259 
260         let mut dl = TargetDataLayout::default();
261         let mut i128_align_src = 64;
262         for spec in input.split('-') {
263             let spec_parts = spec.split(':').collect::<Vec<_>>();
264 
265             match &*spec_parts {
266                 ["e"] => dl.endian = Endian::Little,
267                 ["E"] => dl.endian = Endian::Big,
268                 [p] if p.starts_with('P') => {
269                     dl.instruction_address_space = parse_address_space(&p[1..], "P")?
270                 }
271                 ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
272                 ["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
273                 ["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
274                 // FIXME(erikdesjardins): we should be parsing nonzero address spaces
275                 // this will require replacing TargetDataLayout::{pointer_size,pointer_align}
276                 // with e.g. `fn pointer_size_in(AddressSpace)`
277                 [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
278                     dl.pointer_size = size(s, p)?;
279                     dl.pointer_align = align(a, p)?;
280                 }
281                 [s, ref a @ ..] if s.starts_with('i') => {
282                     let Ok(bits) = s[1..].parse::<u64>() else {
283                         size(&s[1..], "i")?; // For the user error.
284                         continue;
285                     };
286                     let a = align(a, s)?;
287                     match bits {
288                         1 => dl.i1_align = a,
289                         8 => dl.i8_align = a,
290                         16 => dl.i16_align = a,
291                         32 => dl.i32_align = a,
292                         64 => dl.i64_align = a,
293                         _ => {}
294                     }
295                     if bits >= i128_align_src && bits <= 128 {
296                         // Default alignment for i128 is decided by taking the alignment of
297                         // largest-sized i{64..=128}.
298                         i128_align_src = bits;
299                         dl.i128_align = a;
300                     }
301                 }
302                 [s, ref a @ ..] if s.starts_with('v') => {
303                     let v_size = size(&s[1..], "v")?;
304                     let a = align(a, s)?;
305                     if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
306                         v.1 = a;
307                         continue;
308                     }
309                     // No existing entry, add a new one.
310                     dl.vector_align.push((v_size, a));
311                 }
312                 _ => {} // Ignore everything else.
313             }
314         }
315         Ok(dl)
316     }
317 
318     /// Returns exclusive upper bound on object size.
319     ///
320     /// The theoretical maximum object size is defined as the maximum positive `isize` value.
321     /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
322     /// index every address within an object along with one byte past the end, along with allowing
323     /// `isize` to store the difference between any two pointers into an object.
324     ///
325     /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer
326     /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is
327     /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
328     /// address space on 64-bit ARMv8 and x86_64.
329     #[inline]
obj_size_bound(&self) -> u64330     pub fn obj_size_bound(&self) -> u64 {
331         match self.pointer_size.bits() {
332             16 => 1 << 15,
333             32 => 1 << 31,
334             64 => 1 << 47,
335             bits => panic!("obj_size_bound: unknown pointer bit size {}", bits),
336         }
337     }
338 
339     #[inline]
ptr_sized_integer(&self) -> Integer340     pub fn ptr_sized_integer(&self) -> Integer {
341         match self.pointer_size.bits() {
342             16 => I16,
343             32 => I32,
344             64 => I64,
345             bits => panic!("ptr_sized_integer: unknown pointer bit size {}", bits),
346         }
347     }
348 
349     #[inline]
vector_align(&self, vec_size: Size) -> AbiAndPrefAlign350     pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
351         for &(size, align) in &self.vector_align {
352             if size == vec_size {
353                 return align;
354             }
355         }
356         // Default to natural alignment, which is what LLVM does.
357         // That is, use the size, rounded up to a power of 2.
358         AbiAndPrefAlign::new(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
359     }
360 }
361 
362 pub trait HasDataLayout {
data_layout(&self) -> &TargetDataLayout363     fn data_layout(&self) -> &TargetDataLayout;
364 }
365 
366 impl HasDataLayout for TargetDataLayout {
367     #[inline]
data_layout(&self) -> &TargetDataLayout368     fn data_layout(&self) -> &TargetDataLayout {
369         self
370     }
371 }
372 
373 /// Endianness of the target, which must match cfg(target-endian).
374 #[derive(Copy, Clone, PartialEq, Eq)]
375 pub enum Endian {
376     Little,
377     Big,
378 }
379 
380 impl Endian {
as_str(&self) -> &'static str381     pub fn as_str(&self) -> &'static str {
382         match self {
383             Self::Little => "little",
384             Self::Big => "big",
385         }
386     }
387 }
388 
389 impl fmt::Debug for Endian {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result390     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391         f.write_str(self.as_str())
392     }
393 }
394 
395 impl FromStr for Endian {
396     type Err = String;
397 
from_str(s: &str) -> Result<Self, Self::Err>398     fn from_str(s: &str) -> Result<Self, Self::Err> {
399         match s {
400             "little" => Ok(Self::Little),
401             "big" => Ok(Self::Big),
402             _ => Err(format!(r#"unknown endian: "{}""#, s)),
403         }
404     }
405 }
406 
407 /// Size of a type in bytes.
408 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
409 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
410 pub struct Size {
411     raw: u64,
412 }
413 
414 // Safety: Ord is implement as just comparing numerical values and numerical values
415 // are not changed by (de-)serialization.
416 #[cfg(feature = "nightly")]
417 unsafe impl StableOrd for Size {
418     const CAN_USE_UNSTABLE_SORT: bool = true;
419 }
420 
421 // This is debug-printed a lot in larger structs, don't waste too much space there
422 impl fmt::Debug for Size {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result423     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424         write!(f, "Size({} bytes)", self.bytes())
425     }
426 }
427 
428 impl Size {
429     pub const ZERO: Size = Size { raw: 0 };
430 
431     /// Rounds `bits` up to the next-higher byte boundary, if `bits` is
432     /// not a multiple of 8.
from_bits(bits: impl TryInto<u64>) -> Size433     pub fn from_bits(bits: impl TryInto<u64>) -> Size {
434         let bits = bits.try_into().ok().unwrap();
435         // Avoid potential overflow from `bits + 7`.
436         Size { raw: bits / 8 + ((bits % 8) + 7) / 8 }
437     }
438 
439     #[inline]
from_bytes(bytes: impl TryInto<u64>) -> Size440     pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
441         let bytes: u64 = bytes.try_into().ok().unwrap();
442         Size { raw: bytes }
443     }
444 
445     #[inline]
bytes(self) -> u64446     pub fn bytes(self) -> u64 {
447         self.raw
448     }
449 
450     #[inline]
bytes_usize(self) -> usize451     pub fn bytes_usize(self) -> usize {
452         self.bytes().try_into().unwrap()
453     }
454 
455     #[inline]
bits(self) -> u64456     pub fn bits(self) -> u64 {
457         #[cold]
458         fn overflow(bytes: u64) -> ! {
459             panic!("Size::bits: {} bytes in bits doesn't fit in u64", bytes)
460         }
461 
462         self.bytes().checked_mul(8).unwrap_or_else(|| overflow(self.bytes()))
463     }
464 
465     #[inline]
bits_usize(self) -> usize466     pub fn bits_usize(self) -> usize {
467         self.bits().try_into().unwrap()
468     }
469 
470     #[inline]
align_to(self, align: Align) -> Size471     pub fn align_to(self, align: Align) -> Size {
472         let mask = align.bytes() - 1;
473         Size::from_bytes((self.bytes() + mask) & !mask)
474     }
475 
476     #[inline]
is_aligned(self, align: Align) -> bool477     pub fn is_aligned(self, align: Align) -> bool {
478         let mask = align.bytes() - 1;
479         self.bytes() & mask == 0
480     }
481 
482     #[inline]
checked_add<C: HasDataLayout>(self, offset: Size, cx: &C) -> Option<Size>483     pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: &C) -> Option<Size> {
484         let dl = cx.data_layout();
485 
486         let bytes = self.bytes().checked_add(offset.bytes())?;
487 
488         if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
489     }
490 
491     #[inline]
checked_mul<C: HasDataLayout>(self, count: u64, cx: &C) -> Option<Size>492     pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: &C) -> Option<Size> {
493         let dl = cx.data_layout();
494 
495         let bytes = self.bytes().checked_mul(count)?;
496         if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
497     }
498 
499     /// Truncates `value` to `self` bits and then sign-extends it to 128 bits
500     /// (i.e., if it is negative, fill with 1's on the left).
501     #[inline]
sign_extend(self, value: u128) -> u128502     pub fn sign_extend(self, value: u128) -> u128 {
503         let size = self.bits();
504         if size == 0 {
505             // Truncated until nothing is left.
506             return 0;
507         }
508         // Sign-extend it.
509         let shift = 128 - size;
510         // Shift the unsigned value to the left, then shift back to the right as signed
511         // (essentially fills with sign bit on the left).
512         (((value << shift) as i128) >> shift) as u128
513     }
514 
515     /// Truncates `value` to `self` bits.
516     #[inline]
truncate(self, value: u128) -> u128517     pub fn truncate(self, value: u128) -> u128 {
518         let size = self.bits();
519         if size == 0 {
520             // Truncated until nothing is left.
521             return 0;
522         }
523         let shift = 128 - size;
524         // Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
525         (value << shift) >> shift
526     }
527 
528     #[inline]
signed_int_min(&self) -> i128529     pub fn signed_int_min(&self) -> i128 {
530         self.sign_extend(1_u128 << (self.bits() - 1)) as i128
531     }
532 
533     #[inline]
signed_int_max(&self) -> i128534     pub fn signed_int_max(&self) -> i128 {
535         i128::MAX >> (128 - self.bits())
536     }
537 
538     #[inline]
unsigned_int_max(&self) -> u128539     pub fn unsigned_int_max(&self) -> u128 {
540         u128::MAX >> (128 - self.bits())
541     }
542 }
543 
544 // Panicking addition, subtraction and multiplication for convenience.
545 // Avoid during layout computation, return `LayoutError` instead.
546 
547 impl Add for Size {
548     type Output = Size;
549     #[inline]
add(self, other: Size) -> Size550     fn add(self, other: Size) -> Size {
551         Size::from_bytes(self.bytes().checked_add(other.bytes()).unwrap_or_else(|| {
552             panic!("Size::add: {} + {} doesn't fit in u64", self.bytes(), other.bytes())
553         }))
554     }
555 }
556 
557 impl Sub for Size {
558     type Output = Size;
559     #[inline]
sub(self, other: Size) -> Size560     fn sub(self, other: Size) -> Size {
561         Size::from_bytes(self.bytes().checked_sub(other.bytes()).unwrap_or_else(|| {
562             panic!("Size::sub: {} - {} would result in negative size", self.bytes(), other.bytes())
563         }))
564     }
565 }
566 
567 impl Mul<Size> for u64 {
568     type Output = Size;
569     #[inline]
mul(self, size: Size) -> Size570     fn mul(self, size: Size) -> Size {
571         size * self
572     }
573 }
574 
575 impl Mul<u64> for Size {
576     type Output = Size;
577     #[inline]
mul(self, count: u64) -> Size578     fn mul(self, count: u64) -> Size {
579         match self.bytes().checked_mul(count) {
580             Some(bytes) => Size::from_bytes(bytes),
581             None => panic!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count),
582         }
583     }
584 }
585 
586 impl AddAssign for Size {
587     #[inline]
add_assign(&mut self, other: Size)588     fn add_assign(&mut self, other: Size) {
589         *self = *self + other;
590     }
591 }
592 
593 #[cfg(feature = "nightly")]
594 impl Step for Size {
595     #[inline]
steps_between(start: &Self, end: &Self) -> Option<usize>596     fn steps_between(start: &Self, end: &Self) -> Option<usize> {
597         u64::steps_between(&start.bytes(), &end.bytes())
598     }
599 
600     #[inline]
forward_checked(start: Self, count: usize) -> Option<Self>601     fn forward_checked(start: Self, count: usize) -> Option<Self> {
602         u64::forward_checked(start.bytes(), count).map(Self::from_bytes)
603     }
604 
605     #[inline]
forward(start: Self, count: usize) -> Self606     fn forward(start: Self, count: usize) -> Self {
607         Self::from_bytes(u64::forward(start.bytes(), count))
608     }
609 
610     #[inline]
forward_unchecked(start: Self, count: usize) -> Self611     unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
612         Self::from_bytes(u64::forward_unchecked(start.bytes(), count))
613     }
614 
615     #[inline]
backward_checked(start: Self, count: usize) -> Option<Self>616     fn backward_checked(start: Self, count: usize) -> Option<Self> {
617         u64::backward_checked(start.bytes(), count).map(Self::from_bytes)
618     }
619 
620     #[inline]
backward(start: Self, count: usize) -> Self621     fn backward(start: Self, count: usize) -> Self {
622         Self::from_bytes(u64::backward(start.bytes(), count))
623     }
624 
625     #[inline]
backward_unchecked(start: Self, count: usize) -> Self626     unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
627         Self::from_bytes(u64::backward_unchecked(start.bytes(), count))
628     }
629 }
630 
631 /// Alignment of a type in bytes (always a power of two).
632 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
633 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
634 pub struct Align {
635     pow2: u8,
636 }
637 
638 // This is debug-printed a lot in larger structs, don't waste too much space there
639 impl fmt::Debug for Align {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result640     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
641         write!(f, "Align({} bytes)", self.bytes())
642     }
643 }
644 
645 #[derive(Clone, Copy)]
646 pub enum AlignFromBytesError {
647     NotPowerOfTwo(u64),
648     TooLarge(u64),
649 }
650 
651 impl AlignFromBytesError {
diag_ident(self) -> &'static str652     pub fn diag_ident(self) -> &'static str {
653         match self {
654             Self::NotPowerOfTwo(_) => "not_power_of_two",
655             Self::TooLarge(_) => "too_large",
656         }
657     }
658 
align(self) -> u64659     pub fn align(self) -> u64 {
660         let (Self::NotPowerOfTwo(align) | Self::TooLarge(align)) = self;
661         align
662     }
663 }
664 
665 impl fmt::Debug for AlignFromBytesError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result666     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
667         fmt::Display::fmt(self, f)
668     }
669 }
670 
671 impl fmt::Display for AlignFromBytesError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result672     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
673         match self {
674             AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "`{align}` is not a power of 2"),
675             AlignFromBytesError::TooLarge(align) => write!(f, "`{align}` is too large"),
676         }
677     }
678 }
679 
680 impl Align {
681     pub const ONE: Align = Align { pow2: 0 };
682     pub const MAX: Align = Align { pow2: 29 };
683 
684     #[inline]
from_bits(bits: u64) -> Result<Align, AlignFromBytesError>685     pub fn from_bits(bits: u64) -> Result<Align, AlignFromBytesError> {
686         Align::from_bytes(Size::from_bits(bits).bytes())
687     }
688 
689     #[inline]
from_bytes(align: u64) -> Result<Align, AlignFromBytesError>690     pub fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
691         // Treat an alignment of 0 bytes like 1-byte alignment.
692         if align == 0 {
693             return Ok(Align::ONE);
694         }
695 
696         #[cold]
697         fn not_power_of_2(align: u64) -> AlignFromBytesError {
698             AlignFromBytesError::NotPowerOfTwo(align)
699         }
700 
701         #[cold]
702         fn too_large(align: u64) -> AlignFromBytesError {
703             AlignFromBytesError::TooLarge(align)
704         }
705 
706         let tz = align.trailing_zeros();
707         if align != (1 << tz) {
708             return Err(not_power_of_2(align));
709         }
710 
711         let pow2 = tz as u8;
712         if pow2 > Self::MAX.pow2 {
713             return Err(too_large(align));
714         }
715 
716         Ok(Align { pow2 })
717     }
718 
719     #[inline]
bytes(self) -> u64720     pub fn bytes(self) -> u64 {
721         1 << self.pow2
722     }
723 
724     #[inline]
bits(self) -> u64725     pub fn bits(self) -> u64 {
726         self.bytes() * 8
727     }
728 
729     /// Computes the best alignment possible for the given offset
730     /// (the largest power of two that the offset is a multiple of).
731     ///
732     /// N.B., for an offset of `0`, this happens to return `2^64`.
733     #[inline]
max_for_offset(offset: Size) -> Align734     pub fn max_for_offset(offset: Size) -> Align {
735         Align { pow2: offset.bytes().trailing_zeros() as u8 }
736     }
737 
738     /// Lower the alignment, if necessary, such that the given offset
739     /// is aligned to it (the offset is a multiple of the alignment).
740     #[inline]
restrict_for_offset(self, offset: Size) -> Align741     pub fn restrict_for_offset(self, offset: Size) -> Align {
742         self.min(Align::max_for_offset(offset))
743     }
744 }
745 
746 /// A pair of alignments, ABI-mandated and preferred.
747 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
748 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
749 
750 pub struct AbiAndPrefAlign {
751     pub abi: Align,
752     pub pref: Align,
753 }
754 
755 impl AbiAndPrefAlign {
756     #[inline]
new(align: Align) -> AbiAndPrefAlign757     pub fn new(align: Align) -> AbiAndPrefAlign {
758         AbiAndPrefAlign { abi: align, pref: align }
759     }
760 
761     #[inline]
min(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign762     pub fn min(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
763         AbiAndPrefAlign { abi: self.abi.min(other.abi), pref: self.pref.min(other.pref) }
764     }
765 
766     #[inline]
max(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign767     pub fn max(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
768         AbiAndPrefAlign { abi: self.abi.max(other.abi), pref: self.pref.max(other.pref) }
769     }
770 }
771 
772 /// Integers, also used for enum discriminants.
773 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
774 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
775 
776 pub enum Integer {
777     I8,
778     I16,
779     I32,
780     I64,
781     I128,
782 }
783 
784 impl Integer {
785     #[inline]
size(self) -> Size786     pub fn size(self) -> Size {
787         match self {
788             I8 => Size::from_bytes(1),
789             I16 => Size::from_bytes(2),
790             I32 => Size::from_bytes(4),
791             I64 => Size::from_bytes(8),
792             I128 => Size::from_bytes(16),
793         }
794     }
795 
796     /// Gets the Integer type from an IntegerType.
from_attr<C: HasDataLayout>(cx: &C, ity: IntegerType) -> Integer797     pub fn from_attr<C: HasDataLayout>(cx: &C, ity: IntegerType) -> Integer {
798         let dl = cx.data_layout();
799 
800         match ity {
801             IntegerType::Pointer(_) => dl.ptr_sized_integer(),
802             IntegerType::Fixed(x, _) => x,
803         }
804     }
805 
align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign806     pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
807         let dl = cx.data_layout();
808 
809         match self {
810             I8 => dl.i8_align,
811             I16 => dl.i16_align,
812             I32 => dl.i32_align,
813             I64 => dl.i64_align,
814             I128 => dl.i128_align,
815         }
816     }
817 
818     /// Returns the largest signed value that can be represented by this Integer.
819     #[inline]
signed_max(self) -> i128820     pub fn signed_max(self) -> i128 {
821         match self {
822             I8 => i8::MAX as i128,
823             I16 => i16::MAX as i128,
824             I32 => i32::MAX as i128,
825             I64 => i64::MAX as i128,
826             I128 => i128::MAX,
827         }
828     }
829 
830     /// Finds the smallest Integer type which can represent the signed value.
831     #[inline]
fit_signed(x: i128) -> Integer832     pub fn fit_signed(x: i128) -> Integer {
833         match x {
834             -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8,
835             -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16,
836             -0x0000_0000_8000_0000..=0x0000_0000_7fff_ffff => I32,
837             -0x8000_0000_0000_0000..=0x7fff_ffff_ffff_ffff => I64,
838             _ => I128,
839         }
840     }
841 
842     /// Finds the smallest Integer type which can represent the unsigned value.
843     #[inline]
fit_unsigned(x: u128) -> Integer844     pub fn fit_unsigned(x: u128) -> Integer {
845         match x {
846             0..=0x0000_0000_0000_00ff => I8,
847             0..=0x0000_0000_0000_ffff => I16,
848             0..=0x0000_0000_ffff_ffff => I32,
849             0..=0xffff_ffff_ffff_ffff => I64,
850             _ => I128,
851         }
852     }
853 
854     /// Finds the smallest integer with the given alignment.
for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer>855     pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
856         let dl = cx.data_layout();
857 
858         [I8, I16, I32, I64, I128].into_iter().find(|&candidate| {
859             wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes()
860         })
861     }
862 
863     /// Find the largest integer with the given alignment or less.
approximate_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Integer864     pub fn approximate_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Integer {
865         let dl = cx.data_layout();
866 
867         // FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
868         for candidate in [I64, I32, I16] {
869             if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
870                 return candidate;
871             }
872         }
873         I8
874     }
875 
876     // FIXME(eddyb) consolidate this and other methods that find the appropriate
877     // `Integer` given some requirements.
878     #[inline]
from_size(size: Size) -> Result<Self, String>879     pub fn from_size(size: Size) -> Result<Self, String> {
880         match size.bits() {
881             8 => Ok(Integer::I8),
882             16 => Ok(Integer::I16),
883             32 => Ok(Integer::I32),
884             64 => Ok(Integer::I64),
885             128 => Ok(Integer::I128),
886             _ => Err(format!("rust does not support integers with {} bits", size.bits())),
887         }
888     }
889 }
890 
891 /// Fundamental unit of memory access and layout.
892 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
893 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
894 pub enum Primitive {
895     /// The `bool` is the signedness of the `Integer` type.
896     ///
897     /// One would think we would not care about such details this low down,
898     /// but some ABIs are described in terms of C types and ISAs where the
899     /// integer arithmetic is done on {sign,zero}-extended registers, e.g.
900     /// a negative integer passed by zero-extension will appear positive in
901     /// the callee, and most operations on it will produce the wrong values.
902     Int(Integer, bool),
903     F32,
904     F64,
905     Pointer(AddressSpace),
906 }
907 
908 impl Primitive {
size<C: HasDataLayout>(self, cx: &C) -> Size909     pub fn size<C: HasDataLayout>(self, cx: &C) -> Size {
910         let dl = cx.data_layout();
911 
912         match self {
913             Int(i, _) => i.size(),
914             F32 => Size::from_bits(32),
915             F64 => Size::from_bits(64),
916             // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
917             // different address spaces can have different sizes
918             // (but TargetDataLayout doesn't currently parse that part of the DL string)
919             Pointer(_) => dl.pointer_size,
920         }
921     }
922 
align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign923     pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
924         let dl = cx.data_layout();
925 
926         match self {
927             Int(i, _) => i.align(dl),
928             F32 => dl.f32_align,
929             F64 => dl.f64_align,
930             // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
931             // different address spaces can have different alignments
932             // (but TargetDataLayout doesn't currently parse that part of the DL string)
933             Pointer(_) => dl.pointer_align,
934         }
935     }
936 }
937 
938 /// Inclusive wrap-around range of valid values, that is, if
939 /// start > end, it represents `start..=MAX`,
940 /// followed by `0..=end`.
941 ///
942 /// That is, for an i8 primitive, a range of `254..=2` means following
943 /// sequence:
944 ///
945 ///    254 (-2), 255 (-1), 0, 1, 2
946 ///
947 /// This is intended specifically to mirror LLVM’s `!range` metadata semantics.
948 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
949 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
950 pub struct WrappingRange {
951     pub start: u128,
952     pub end: u128,
953 }
954 
955 impl WrappingRange {
full(size: Size) -> Self956     pub fn full(size: Size) -> Self {
957         Self { start: 0, end: size.unsigned_int_max() }
958     }
959 
960     /// Returns `true` if `v` is contained in the range.
961     #[inline(always)]
contains(&self, v: u128) -> bool962     pub fn contains(&self, v: u128) -> bool {
963         if self.start <= self.end {
964             self.start <= v && v <= self.end
965         } else {
966             self.start <= v || v <= self.end
967         }
968     }
969 
970     /// Returns `self` with replaced `start`
971     #[inline(always)]
with_start(mut self, start: u128) -> Self972     pub fn with_start(mut self, start: u128) -> Self {
973         self.start = start;
974         self
975     }
976 
977     /// Returns `self` with replaced `end`
978     #[inline(always)]
with_end(mut self, end: u128) -> Self979     pub fn with_end(mut self, end: u128) -> Self {
980         self.end = end;
981         self
982     }
983 
984     /// Returns `true` if `size` completely fills the range.
985     #[inline]
is_full_for(&self, size: Size) -> bool986     pub fn is_full_for(&self, size: Size) -> bool {
987         let max_value = size.unsigned_int_max();
988         debug_assert!(self.start <= max_value && self.end <= max_value);
989         self.start == (self.end.wrapping_add(1) & max_value)
990     }
991 }
992 
993 impl fmt::Debug for WrappingRange {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result994     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
995         if self.start > self.end {
996             write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
997         } else {
998             write!(fmt, "{}..={}", self.start, self.end)?;
999         }
1000         Ok(())
1001     }
1002 }
1003 
1004 /// Information about one scalar component of a Rust type.
1005 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1006 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1007 pub enum Scalar {
1008     Initialized {
1009         value: Primitive,
1010 
1011         // FIXME(eddyb) always use the shortest range, e.g., by finding
1012         // the largest space between two consecutive valid values and
1013         // taking everything else as the (shortest) valid range.
1014         valid_range: WrappingRange,
1015     },
1016     Union {
1017         /// Even for unions, we need to use the correct registers for the kind of
1018         /// values inside the union, so we keep the `Primitive` type around. We
1019         /// also use it to compute the size of the scalar.
1020         /// However, unions never have niches and even allow undef,
1021         /// so there is no `valid_range`.
1022         value: Primitive,
1023     },
1024 }
1025 
1026 impl Scalar {
1027     #[inline]
is_bool(&self) -> bool1028     pub fn is_bool(&self) -> bool {
1029         matches!(
1030             self,
1031             Scalar::Initialized {
1032                 value: Int(I8, false),
1033                 valid_range: WrappingRange { start: 0, end: 1 }
1034             }
1035         )
1036     }
1037 
1038     /// Get the primitive representation of this type, ignoring the valid range and whether the
1039     /// value is allowed to be undefined (due to being a union).
primitive(&self) -> Primitive1040     pub fn primitive(&self) -> Primitive {
1041         match *self {
1042             Scalar::Initialized { value, .. } | Scalar::Union { value } => value,
1043         }
1044     }
1045 
align(self, cx: &impl HasDataLayout) -> AbiAndPrefAlign1046     pub fn align(self, cx: &impl HasDataLayout) -> AbiAndPrefAlign {
1047         self.primitive().align(cx)
1048     }
1049 
size(self, cx: &impl HasDataLayout) -> Size1050     pub fn size(self, cx: &impl HasDataLayout) -> Size {
1051         self.primitive().size(cx)
1052     }
1053 
1054     #[inline]
to_union(&self) -> Self1055     pub fn to_union(&self) -> Self {
1056         Self::Union { value: self.primitive() }
1057     }
1058 
1059     #[inline]
valid_range(&self, cx: &impl HasDataLayout) -> WrappingRange1060     pub fn valid_range(&self, cx: &impl HasDataLayout) -> WrappingRange {
1061         match *self {
1062             Scalar::Initialized { valid_range, .. } => valid_range,
1063             Scalar::Union { value } => WrappingRange::full(value.size(cx)),
1064         }
1065     }
1066 
1067     #[inline]
1068     /// Allows the caller to mutate the valid range. This operation will panic if attempted on a union.
valid_range_mut(&mut self) -> &mut WrappingRange1069     pub fn valid_range_mut(&mut self) -> &mut WrappingRange {
1070         match self {
1071             Scalar::Initialized { valid_range, .. } => valid_range,
1072             Scalar::Union { .. } => panic!("cannot change the valid range of a union"),
1073         }
1074     }
1075 
1076     /// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole layout
1077     #[inline]
is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool1078     pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
1079         match *self {
1080             Scalar::Initialized { valid_range, .. } => valid_range.is_full_for(self.size(cx)),
1081             Scalar::Union { .. } => true,
1082         }
1083     }
1084 
1085     /// Returns `true` if this type can be left uninit.
1086     #[inline]
is_uninit_valid(&self) -> bool1087     pub fn is_uninit_valid(&self) -> bool {
1088         match *self {
1089             Scalar::Initialized { .. } => false,
1090             Scalar::Union { .. } => true,
1091         }
1092     }
1093 }
1094 
1095 rustc_index::newtype_index! {
1096     /// The *source-order* index of a field in a variant.
1097     ///
1098     /// This is how most code after type checking refers to fields, rather than
1099     /// using names (as names have hygiene complications and more complex lookup).
1100     ///
1101     /// Particularly for `repr(Rust)` types, this may not be the same as *layout* order.
1102     /// (It is for `repr(C)` `struct`s, however.)
1103     ///
1104     /// For example, in the following types,
1105     /// ```rust
1106     /// # enum Never {}
1107     /// # #[repr(u16)]
1108     /// enum Demo1 {
1109     ///    Variant0 { a: Never, b: i32 } = 100,
1110     ///    Variant1 { c: u8, d: u64 } = 10,
1111     /// }
1112     /// struct Demo2 { e: u8, f: u16, g: u8 }
1113     /// ```
1114     /// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
1115     /// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
1116     /// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
1117     #[derive(HashStable_Generic)]
1118     pub struct FieldIdx {}
1119 }
1120 
1121 /// Describes how the fields of a type are located in memory.
1122 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
1123 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1124 pub enum FieldsShape {
1125     /// Scalar primitives and `!`, which never have fields.
1126     Primitive,
1127 
1128     /// All fields start at no offset. The `usize` is the field count.
1129     Union(NonZeroUsize),
1130 
1131     /// Array/vector-like placement, with all fields of identical types.
1132     Array { stride: Size, count: u64 },
1133 
1134     /// Struct-like placement, with precomputed offsets.
1135     ///
1136     /// Fields are guaranteed to not overlap, but note that gaps
1137     /// before, between and after all the fields are NOT always
1138     /// padding, and as such their contents may not be discarded.
1139     /// For example, enum variants leave a gap at the start,
1140     /// where the discriminant field in the enum layout goes.
1141     Arbitrary {
1142         /// Offsets for the first byte of each field,
1143         /// ordered to match the source definition order.
1144         /// This vector does not go in increasing order.
1145         // FIXME(eddyb) use small vector optimization for the common case.
1146         offsets: IndexVec<FieldIdx, Size>,
1147 
1148         /// Maps source order field indices to memory order indices,
1149         /// depending on how the fields were reordered (if at all).
1150         /// This is a permutation, with both the source order and the
1151         /// memory order using the same (0..n) index ranges.
1152         ///
1153         /// Note that during computation of `memory_index`, sometimes
1154         /// it is easier to operate on the inverse mapping (that is,
1155         /// from memory order to source order), and that is usually
1156         /// named `inverse_memory_index`.
1157         ///
1158         // FIXME(eddyb) build a better abstraction for permutations, if possible.
1159         // FIXME(camlorn) also consider small vector optimization here.
1160         memory_index: IndexVec<FieldIdx, u32>,
1161     },
1162 }
1163 
1164 impl FieldsShape {
1165     #[inline]
count(&self) -> usize1166     pub fn count(&self) -> usize {
1167         match *self {
1168             FieldsShape::Primitive => 0,
1169             FieldsShape::Union(count) => count.get(),
1170             FieldsShape::Array { count, .. } => count.try_into().unwrap(),
1171             FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
1172         }
1173     }
1174 
1175     #[inline]
offset(&self, i: usize) -> Size1176     pub fn offset(&self, i: usize) -> Size {
1177         match *self {
1178             FieldsShape::Primitive => {
1179                 unreachable!("FieldsShape::offset: `Primitive`s have no fields")
1180             }
1181             FieldsShape::Union(count) => {
1182                 assert!(
1183                     i < count.get(),
1184                     "tried to access field {} of union with {} fields",
1185                     i,
1186                     count
1187                 );
1188                 Size::ZERO
1189             }
1190             FieldsShape::Array { stride, count } => {
1191                 let i = u64::try_from(i).unwrap();
1192                 assert!(i < count);
1193                 stride * i
1194             }
1195             FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::from_usize(i)],
1196         }
1197     }
1198 
1199     #[inline]
memory_index(&self, i: usize) -> usize1200     pub fn memory_index(&self, i: usize) -> usize {
1201         match *self {
1202             FieldsShape::Primitive => {
1203                 unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
1204             }
1205             FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
1206             FieldsShape::Arbitrary { ref memory_index, .. } => {
1207                 memory_index[FieldIdx::from_usize(i)].try_into().unwrap()
1208             }
1209         }
1210     }
1211 
1212     /// Gets source indices of the fields by increasing offsets.
1213     #[inline]
index_by_increasing_offset(&self) -> impl Iterator<Item = usize> + '_1214     pub fn index_by_increasing_offset(&self) -> impl Iterator<Item = usize> + '_ {
1215         let mut inverse_small = [0u8; 64];
1216         let mut inverse_big = IndexVec::new();
1217         let use_small = self.count() <= inverse_small.len();
1218 
1219         // We have to write this logic twice in order to keep the array small.
1220         if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
1221             if use_small {
1222                 for (field_idx, &mem_idx) in memory_index.iter_enumerated() {
1223                     inverse_small[mem_idx as usize] = field_idx.as_u32() as u8;
1224                 }
1225             } else {
1226                 inverse_big = memory_index.invert_bijective_mapping();
1227             }
1228         }
1229 
1230         (0..self.count()).map(move |i| match *self {
1231             FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
1232             FieldsShape::Arbitrary { .. } => {
1233                 if use_small {
1234                     inverse_small[i] as usize
1235                 } else {
1236                     inverse_big[i as u32].as_usize()
1237                 }
1238             }
1239         })
1240     }
1241 }
1242 
1243 /// An identifier that specifies the address space that some operation
1244 /// should operate on. Special address spaces have an effect on code generation,
1245 /// depending on the target and the address spaces it implements.
1246 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1247 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1248 pub struct AddressSpace(pub u32);
1249 
1250 impl AddressSpace {
1251     /// The default address space, corresponding to data space.
1252     pub const DATA: Self = AddressSpace(0);
1253 }
1254 
1255 /// Describes how values of the type are passed by target ABIs,
1256 /// in terms of categories of C types there are ABI rules for.
1257 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1258 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1259 
1260 pub enum Abi {
1261     Uninhabited,
1262     Scalar(Scalar),
1263     ScalarPair(Scalar, Scalar),
1264     Vector {
1265         element: Scalar,
1266         count: u64,
1267     },
1268     Aggregate {
1269         /// If true, the size is exact, otherwise it's only a lower bound.
1270         sized: bool,
1271     },
1272 }
1273 
1274 impl Abi {
1275     /// Returns `true` if the layout corresponds to an unsized type.
1276     #[inline]
is_unsized(&self) -> bool1277     pub fn is_unsized(&self) -> bool {
1278         match *self {
1279             Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
1280             Abi::Aggregate { sized } => !sized,
1281         }
1282     }
1283 
1284     #[inline]
is_sized(&self) -> bool1285     pub fn is_sized(&self) -> bool {
1286         !self.is_unsized()
1287     }
1288 
1289     /// Returns `true` if this is a single signed integer scalar
1290     #[inline]
is_signed(&self) -> bool1291     pub fn is_signed(&self) -> bool {
1292         match self {
1293             Abi::Scalar(scal) => match scal.primitive() {
1294                 Primitive::Int(_, signed) => signed,
1295                 _ => false,
1296             },
1297             _ => panic!("`is_signed` on non-scalar ABI {:?}", self),
1298         }
1299     }
1300 
1301     /// Returns `true` if this is an uninhabited type
1302     #[inline]
is_uninhabited(&self) -> bool1303     pub fn is_uninhabited(&self) -> bool {
1304         matches!(*self, Abi::Uninhabited)
1305     }
1306 
1307     /// Returns `true` is this is a scalar type
1308     #[inline]
is_scalar(&self) -> bool1309     pub fn is_scalar(&self) -> bool {
1310         matches!(*self, Abi::Scalar(_))
1311     }
1312 
1313     /// Returns the fixed alignment of this ABI, if any is mandated.
inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign>1314     pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
1315         Some(match *self {
1316             Abi::Scalar(s) => s.align(cx),
1317             Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
1318             Abi::Vector { element, count } => {
1319                 cx.data_layout().vector_align(element.size(cx) * count)
1320             }
1321             Abi::Uninhabited | Abi::Aggregate { .. } => return None,
1322         })
1323     }
1324 
1325     /// Returns the fixed size of this ABI, if any is mandated.
inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size>1326     pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
1327         Some(match *self {
1328             Abi::Scalar(s) => {
1329                 // No padding in scalars.
1330                 s.size(cx)
1331             }
1332             Abi::ScalarPair(s1, s2) => {
1333                 // May have some padding between the pair.
1334                 let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
1335                 (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
1336             }
1337             Abi::Vector { element, count } => {
1338                 // No padding in vectors, except possibly for trailing padding
1339                 // to make the size a multiple of align (e.g. for vectors of size 3).
1340                 (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
1341             }
1342             Abi::Uninhabited | Abi::Aggregate { .. } => return None,
1343         })
1344     }
1345 
1346     /// Discard validity range information and allow undef.
to_union(&self) -> Self1347     pub fn to_union(&self) -> Self {
1348         assert!(self.is_sized());
1349         match *self {
1350             Abi::Scalar(s) => Abi::Scalar(s.to_union()),
1351             Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()),
1352             Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count },
1353             Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
1354         }
1355     }
1356 }
1357 
1358 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
1359 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1360 pub enum Variants {
1361     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
1362     Single { index: VariantIdx },
1363 
1364     /// Enum-likes with more than one inhabited variant: each variant comes with
1365     /// a *discriminant* (usually the same as the variant index but the user can
1366     /// assign explicit discriminant values). That discriminant is encoded
1367     /// as a *tag* on the machine. The layout of each variant is
1368     /// a struct, and they all have space reserved for the tag.
1369     /// For enums, the tag is the sole field of the layout.
1370     Multiple {
1371         tag: Scalar,
1372         tag_encoding: TagEncoding,
1373         tag_field: usize,
1374         variants: IndexVec<VariantIdx, LayoutS>,
1375     },
1376 }
1377 
1378 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
1379 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1380 pub enum TagEncoding {
1381     /// The tag directly stores the discriminant, but possibly with a smaller layout
1382     /// (so converting the tag to the discriminant can require sign extension).
1383     Direct,
1384 
1385     /// Niche (values invalid for a type) encoding the discriminant:
1386     /// Discriminant and variant index coincide.
1387     /// The variant `untagged_variant` contains a niche at an arbitrary
1388     /// offset (field `tag_field` of the enum), which for a variant with
1389     /// discriminant `d` is set to
1390     /// `(d - niche_variants.start).wrapping_add(niche_start)`.
1391     ///
1392     /// For example, `Option<(usize, &T)>`  is represented such that
1393     /// `None` has a null pointer for the second tuple field, and
1394     /// `Some` is the identity function (with a non-null reference).
1395     Niche {
1396         untagged_variant: VariantIdx,
1397         niche_variants: RangeInclusive<VariantIdx>,
1398         niche_start: u128,
1399     },
1400 }
1401 
1402 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1403 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1404 pub struct Niche {
1405     pub offset: Size,
1406     pub value: Primitive,
1407     pub valid_range: WrappingRange,
1408 }
1409 
1410 impl Niche {
from_scalar<C: HasDataLayout>(cx: &C, offset: Size, scalar: Scalar) -> Option<Self>1411     pub fn from_scalar<C: HasDataLayout>(cx: &C, offset: Size, scalar: Scalar) -> Option<Self> {
1412         let Scalar::Initialized { value, valid_range } = scalar else { return None };
1413         let niche = Niche { offset, value, valid_range };
1414         if niche.available(cx) > 0 { Some(niche) } else { None }
1415     }
1416 
available<C: HasDataLayout>(&self, cx: &C) -> u1281417     pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
1418         let Self { value, valid_range: v, .. } = *self;
1419         let size = value.size(cx);
1420         assert!(size.bits() <= 128);
1421         let max_value = size.unsigned_int_max();
1422 
1423         // Find out how many values are outside the valid range.
1424         let niche = v.end.wrapping_add(1)..v.start;
1425         niche.end.wrapping_sub(niche.start) & max_value
1426     }
1427 
reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)>1428     pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
1429         assert!(count > 0);
1430 
1431         let Self { value, valid_range: v, .. } = *self;
1432         let size = value.size(cx);
1433         assert!(size.bits() <= 128);
1434         let max_value = size.unsigned_int_max();
1435 
1436         let niche = v.end.wrapping_add(1)..v.start;
1437         let available = niche.end.wrapping_sub(niche.start) & max_value;
1438         if count > available {
1439             return None;
1440         }
1441 
1442         // Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
1443         // Given an eventual `Option<T>`, we try to maximize the chance for `None` to occupy the niche of zero.
1444         // This is accomplished by preferring enums with 2 variants(`count==1`) and always taking the shortest path to niche zero.
1445         // Having `None` in niche zero can enable some special optimizations.
1446         //
1447         // Bound selection criteria:
1448         // 1. Select closest to zero given wrapping semantics.
1449         // 2. Avoid moving past zero if possible.
1450         //
1451         // In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly.
1452         // If niche zero is already reserved, the selection of bounds are of little interest.
1453         let move_start = |v: WrappingRange| {
1454             let start = v.start.wrapping_sub(count) & max_value;
1455             Some((start, Scalar::Initialized { value, valid_range: v.with_start(start) }))
1456         };
1457         let move_end = |v: WrappingRange| {
1458             let start = v.end.wrapping_add(1) & max_value;
1459             let end = v.end.wrapping_add(count) & max_value;
1460             Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
1461         };
1462         let distance_end_zero = max_value - v.end;
1463         if v.start > v.end {
1464             // zero is unavailable because wrapping occurs
1465             move_end(v)
1466         } else if v.start <= distance_end_zero {
1467             if count <= v.start {
1468                 move_start(v)
1469             } else {
1470                 // moved past zero, use other bound
1471                 move_end(v)
1472             }
1473         } else {
1474             let end = v.end.wrapping_add(count) & max_value;
1475             let overshot_zero = (1..=v.end).contains(&end);
1476             if overshot_zero {
1477                 // moved past zero, use other bound
1478                 move_start(v)
1479             } else {
1480                 move_end(v)
1481             }
1482         }
1483     }
1484 }
1485 
1486 rustc_index::newtype_index! {
1487     /// The *source-order* index of a variant in a type.
1488     ///
1489     /// For enums, these are always `0..variant_count`, regardless of any
1490     /// custom discriminants that may have been defined, and including any
1491     /// variants that may end up uninhabited due to field types.  (Some of the
1492     /// variants may not be present in a monomorphized ABI [`Variants`], but
1493     /// those skipped variants are always counted when determining the *index*.)
1494     ///
1495     /// `struct`s, `tuples`, and `unions`s are considered to have a single variant
1496     /// with variant index zero, aka [`FIRST_VARIANT`].
1497     #[derive(HashStable_Generic)]
1498     pub struct VariantIdx {
1499         /// Equivalent to `VariantIdx(0)`.
1500         const FIRST_VARIANT = 0;
1501     }
1502 }
1503 
1504 #[derive(PartialEq, Eq, Hash, Clone)]
1505 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1506 pub struct LayoutS {
1507     /// Says where the fields are located within the layout.
1508     pub fields: FieldsShape,
1509 
1510     /// Encodes information about multi-variant layouts.
1511     /// Even with `Multiple` variants, a layout still has its own fields! Those are then
1512     /// shared between all variants. One of them will be the discriminant,
1513     /// but e.g. generators can have more.
1514     ///
1515     /// To access all fields of this layout, both `fields` and the fields of the active variant
1516     /// must be taken into account.
1517     pub variants: Variants,
1518 
1519     /// The `abi` defines how this data is passed between functions, and it defines
1520     /// value restrictions via `valid_range`.
1521     ///
1522     /// Note that this is entirely orthogonal to the recursive structure defined by
1523     /// `variants` and `fields`; for example, `ManuallyDrop<Result<isize, isize>>` has
1524     /// `Abi::ScalarPair`! So, even with non-`Aggregate` `abi`, `fields` and `variants`
1525     /// have to be taken into account to find all fields of this layout.
1526     pub abi: Abi,
1527 
1528     /// The leaf scalar with the largest number of invalid values
1529     /// (i.e. outside of its `valid_range`), if it exists.
1530     pub largest_niche: Option<Niche>,
1531 
1532     pub align: AbiAndPrefAlign,
1533     pub size: Size,
1534 }
1535 
1536 impl LayoutS {
scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self1537     pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
1538         let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
1539         let size = scalar.size(cx);
1540         let align = scalar.align(cx);
1541         LayoutS {
1542             variants: Variants::Single { index: FIRST_VARIANT },
1543             fields: FieldsShape::Primitive,
1544             abi: Abi::Scalar(scalar),
1545             largest_niche,
1546             size,
1547             align,
1548         }
1549     }
1550 }
1551 
1552 impl fmt::Debug for LayoutS {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1553     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1554         // This is how `Layout` used to print before it become
1555         // `Interned<LayoutS>`. We print it like this to avoid having to update
1556         // expected output in a lot of tests.
1557         let LayoutS { size, align, abi, fields, largest_niche, variants } = self;
1558         f.debug_struct("Layout")
1559             .field("size", size)
1560             .field("align", align)
1561             .field("abi", abi)
1562             .field("fields", fields)
1563             .field("largest_niche", largest_niche)
1564             .field("variants", variants)
1565             .finish()
1566     }
1567 }
1568 
1569 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
1570 #[rustc_pass_by_value]
1571 pub struct Layout<'a>(pub Interned<'a, LayoutS>);
1572 
1573 impl<'a> fmt::Debug for Layout<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1574     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1575         // See comment on `<LayoutS as Debug>::fmt` above.
1576         self.0.0.fmt(f)
1577     }
1578 }
1579 
1580 impl<'a> Layout<'a> {
fields(self) -> &'a FieldsShape1581     pub fn fields(self) -> &'a FieldsShape {
1582         &self.0.0.fields
1583     }
1584 
variants(self) -> &'a Variants1585     pub fn variants(self) -> &'a Variants {
1586         &self.0.0.variants
1587     }
1588 
abi(self) -> Abi1589     pub fn abi(self) -> Abi {
1590         self.0.0.abi
1591     }
1592 
largest_niche(self) -> Option<Niche>1593     pub fn largest_niche(self) -> Option<Niche> {
1594         self.0.0.largest_niche
1595     }
1596 
align(self) -> AbiAndPrefAlign1597     pub fn align(self) -> AbiAndPrefAlign {
1598         self.0.0.align
1599     }
1600 
size(self) -> Size1601     pub fn size(self) -> Size {
1602         self.0.0.size
1603     }
1604 
1605     /// Whether the layout is from a type that implements [`std::marker::PointerLike`].
1606     ///
1607     /// Currently, that means that the type is pointer-sized, pointer-aligned,
1608     /// and has a scalar ABI.
is_pointer_like(self, data_layout: &TargetDataLayout) -> bool1609     pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
1610         self.size() == data_layout.pointer_size
1611             && self.align().abi == data_layout.pointer_align.abi
1612             && matches!(self.abi(), Abi::Scalar(..))
1613     }
1614 }
1615 
1616 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1617 pub enum PointerKind {
1618     /// Shared reference. `frozen` indicates the absence of any `UnsafeCell`.
1619     SharedRef { frozen: bool },
1620     /// Mutable reference. `unpin` indicates the absence of any pinned data.
1621     MutableRef { unpin: bool },
1622     /// Box. `unpin` indicates the absence of any pinned data.
1623     Box { unpin: bool },
1624 }
1625 
1626 /// Note that this information is advisory only, and backends are free to ignore it.
1627 /// It can only be used to encode potential optimizations, but no critical information.
1628 #[derive(Copy, Clone, Debug)]
1629 pub struct PointeeInfo {
1630     pub size: Size,
1631     pub align: Align,
1632     pub safe: Option<PointerKind>,
1633 }
1634 
1635 impl LayoutS {
1636     /// Returns `true` if the layout corresponds to an unsized type.
is_unsized(&self) -> bool1637     pub fn is_unsized(&self) -> bool {
1638         self.abi.is_unsized()
1639     }
1640 
is_sized(&self) -> bool1641     pub fn is_sized(&self) -> bool {
1642         self.abi.is_sized()
1643     }
1644 
1645     /// Returns `true` if the type is a ZST and not unsized.
is_zst(&self) -> bool1646     pub fn is_zst(&self) -> bool {
1647         match self.abi {
1648             Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
1649             Abi::Uninhabited => self.size.bytes() == 0,
1650             Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
1651         }
1652     }
1653 }
1654 
1655 #[derive(Copy, Clone, Debug)]
1656 pub enum StructKind {
1657     /// A tuple, closure, or univariant which cannot be coerced to unsized.
1658     AlwaysSized,
1659     /// A univariant, the last field of which may be coerced to unsized.
1660     MaybeUnsized,
1661     /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag).
1662     Prefixed(Size, Align),
1663 }
1664