rustc_public/
abi.rs

1use std::fmt::{self, Debug};
2use std::num::NonZero;
3use std::ops::RangeInclusive;
4
5use serde::Serialize;
6
7use crate::compiler_interface::with;
8use crate::mir::FieldIdx;
9use crate::target::{MachineInfo, MachineSize as Size};
10use crate::ty::{Align, Ty, VariantIdx, index_impl};
11use crate::{Error, Opaque, ThreadLocalIndex, error};
12
13/// A function ABI definition.
14#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
15pub struct FnAbi {
16    /// The types of each argument.
17    pub args: Vec<ArgAbi>,
18
19    /// The expected return type.
20    pub ret: ArgAbi,
21
22    /// The count of non-variadic arguments.
23    ///
24    /// Should only be different from `args.len()` when a function is a C variadic function.
25    pub fixed_count: u32,
26
27    /// The ABI convention.
28    pub conv: CallConvention,
29
30    /// Whether this is a variadic C function,
31    pub c_variadic: bool,
32}
33
34/// Information about the ABI of a function's argument, or return value.
35#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
36pub struct ArgAbi {
37    pub ty: Ty,
38    pub layout: Layout,
39    pub mode: PassMode,
40}
41
42/// How a function argument should be passed in to the target function.
43#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
44pub enum PassMode {
45    /// Ignore the argument.
46    ///
47    /// The argument is either uninhabited or a ZST.
48    Ignore,
49    /// Pass the argument directly.
50    ///
51    /// The argument has a layout abi of `Scalar` or `Vector`.
52    Direct(Opaque),
53    /// Pass a pair's elements directly in two arguments.
54    ///
55    /// The argument has a layout abi of `ScalarPair`.
56    Pair(Opaque, Opaque),
57    /// Pass the argument after casting it.
58    Cast { pad_i32: bool, cast: Opaque },
59    /// Pass the argument indirectly via a hidden pointer.
60    Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool },
61}
62
63/// The layout of a type, alongside the type itself.
64#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
65pub struct TyAndLayout {
66    pub ty: Ty,
67    pub layout: Layout,
68}
69
70/// The layout of a type in memory.
71#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
72pub struct LayoutShape {
73    /// The fields location within the layout
74    pub fields: FieldsShape,
75
76    /// Encodes information about multi-variant layouts.
77    /// Even with `Multiple` variants, a layout still has its own fields! Those are then
78    /// shared between all variants.
79    ///
80    /// To access all fields of this layout, both `fields` and the fields of the active variant
81    /// must be taken into account.
82    pub variants: VariantsShape,
83
84    /// The `abi` defines how this data is passed between functions.
85    pub abi: ValueAbi,
86
87    /// The ABI mandated alignment in bytes.
88    pub abi_align: Align,
89
90    /// The size of this layout in bytes.
91    pub size: Size,
92}
93
94impl LayoutShape {
95    /// Returns `true` if the layout corresponds to an unsized type.
96    #[inline]
97    pub fn is_unsized(&self) -> bool {
98        self.abi.is_unsized()
99    }
100
101    #[inline]
102    pub fn is_sized(&self) -> bool {
103        !self.abi.is_unsized()
104    }
105
106    /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
107    pub fn is_1zst(&self) -> bool {
108        self.is_sized() && self.size.bits() == 0 && self.abi_align == 1
109    }
110}
111
112#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
113pub struct Layout(usize, ThreadLocalIndex);
114index_impl!(Layout);
115
116impl Layout {
117    pub fn shape(self) -> LayoutShape {
118        with(|cx| cx.layout_shape(self))
119    }
120}
121
122/// Describes how the fields of a type are shaped in memory.
123#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
124pub enum FieldsShape {
125    /// Scalar primitives and `!`, which never have fields.
126    Primitive,
127
128    /// All fields start at no offset. The `usize` is the field count.
129    Union(NonZero<usize>),
130
131    /// Array/vector-like placement, with all fields of identical types.
132    Array { stride: Size, count: u64 },
133
134    /// Struct-like placement, with precomputed offsets.
135    ///
136    /// Fields are guaranteed to not overlap, but note that gaps
137    /// before, between and after all the fields are NOT always
138    /// padding, and as such their contents may not be discarded.
139    /// For example, enum variants leave a gap at the start,
140    /// where the discriminant field in the enum layout goes.
141    Arbitrary {
142        /// Offsets for the first byte of each field,
143        /// ordered to match the source definition order.
144        /// I.e.: It follows the same order as [super::ty::VariantDef::fields()].
145        /// This vector does not go in increasing order.
146        offsets: Vec<Size>,
147    },
148}
149
150impl FieldsShape {
151    pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> {
152        match self {
153            FieldsShape::Primitive => vec![],
154            FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(),
155            FieldsShape::Arbitrary { offsets, .. } => {
156                let mut indices = (0..offsets.len()).collect::<Vec<_>>();
157                indices.sort_by_key(|idx| offsets[*idx]);
158                indices
159            }
160        }
161    }
162
163    pub fn count(&self) -> usize {
164        match self {
165            FieldsShape::Primitive => 0,
166            FieldsShape::Union(count) => count.get(),
167            FieldsShape::Array { count, .. } => *count as usize,
168            FieldsShape::Arbitrary { offsets, .. } => offsets.len(),
169        }
170    }
171}
172
173#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
174pub enum VariantsShape {
175    /// A type with no valid variants. Must be uninhabited.
176    Empty,
177
178    /// Single enum variants, structs/tuples, unions, and all non-ADTs.
179    Single { index: VariantIdx },
180
181    /// Enum-likes with more than one inhabited variant: each variant comes with
182    /// a *discriminant* (usually the same as the variant index but the user can
183    /// assign explicit discriminant values). That discriminant is encoded
184    /// as a *tag* on the machine. The layout of each variant is
185    /// a struct, and they all have space reserved for the tag.
186    /// For enums, the tag is the sole field of the layout.
187    Multiple {
188        tag: Scalar,
189        tag_encoding: TagEncoding,
190        tag_field: usize,
191        variants: Vec<LayoutShape>,
192    },
193}
194
195#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
196pub enum TagEncoding {
197    /// The tag directly stores the discriminant, but possibly with a smaller layout
198    /// (so converting the tag to the discriminant can require sign extension).
199    Direct,
200
201    /// Niche (values invalid for a type) encoding the discriminant:
202    /// Discriminant and variant index coincide.
203    /// The variant `untagged_variant` contains a niche at an arbitrary
204    /// offset (field `tag_field` of the enum), which for a variant with
205    /// discriminant `d` is set to
206    /// `(d - niche_variants.start).wrapping_add(niche_start)`.
207    ///
208    /// For example, `Option<(usize, &T)>`  is represented such that
209    /// `None` has a null pointer for the second tuple field, and
210    /// `Some` is the identity function (with a non-null reference).
211    Niche {
212        untagged_variant: VariantIdx,
213        niche_variants: RangeInclusive<VariantIdx>,
214        niche_start: u128,
215    },
216}
217
218/// Describes how values of the type are passed by target ABIs,
219/// in terms of categories of C types there are ABI rules for.
220#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
221pub enum ValueAbi {
222    Scalar(Scalar),
223    ScalarPair(Scalar, Scalar),
224    Vector {
225        element: Scalar,
226        count: u64,
227    },
228    ScalableVector {
229        element: Scalar,
230        count: u64,
231    },
232    Aggregate {
233        /// If true, the size is exact, otherwise it's only a lower bound.
234        sized: bool,
235    },
236}
237
238impl ValueAbi {
239    /// Returns `true` if the layout corresponds to an unsized type.
240    pub fn is_unsized(&self) -> bool {
241        match *self {
242            ValueAbi::Scalar(_)
243            | ValueAbi::ScalarPair(..)
244            | ValueAbi::Vector { .. }
245            // FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
246            // `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
247            // fully implemented, scalable vectors will remain `Sized`, they just won't be
248            // `const Sized` - whether `is_unsized` continues to return `false` at that point will
249            // need to be revisited and will depend on what `is_unsized` is used for.
250            | ValueAbi::ScalableVector { .. } => false,
251            ValueAbi::Aggregate { sized } => !sized,
252        }
253    }
254}
255
256/// Information about one scalar component of a Rust type.
257#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)]
258pub enum Scalar {
259    Initialized {
260        /// The primitive type used to represent this value.
261        value: Primitive,
262        /// The range that represents valid values.
263        /// The range must be valid for the `primitive` size.
264        valid_range: WrappingRange,
265    },
266    Union {
267        /// Unions never have niches, so there is no `valid_range`.
268        /// Even for unions, we need to use the correct registers for the kind of
269        /// values inside the union, so we keep the `Primitive` type around.
270        /// It is also used to compute the size of the scalar.
271        value: Primitive,
272    },
273}
274
275impl Scalar {
276    pub fn has_niche(&self, target: &MachineInfo) -> bool {
277        match self {
278            Scalar::Initialized { value, valid_range } => {
279                !valid_range.is_full(value.size(target)).unwrap()
280            }
281            Scalar::Union { .. } => false,
282        }
283    }
284}
285
286/// Fundamental unit of memory access and layout.
287#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)]
288pub enum Primitive {
289    /// The `bool` is the signedness of the `Integer` type.
290    ///
291    /// One would think we would not care about such details this low down,
292    /// but some ABIs are described in terms of C types and ISAs where the
293    /// integer arithmetic is done on {sign,zero}-extended registers, e.g.
294    /// a negative integer passed by zero-extension will appear positive in
295    /// the callee, and most operations on it will produce the wrong values.
296    Int {
297        length: IntegerLength,
298        signed: bool,
299    },
300    Float {
301        length: FloatLength,
302    },
303    Pointer(AddressSpace),
304}
305
306impl Primitive {
307    pub fn size(self, target: &MachineInfo) -> Size {
308        match self {
309            Primitive::Int { length, .. } => Size::from_bits(length.bits()),
310            Primitive::Float { length } => Size::from_bits(length.bits()),
311            Primitive::Pointer(_) => target.pointer_width,
312        }
313    }
314}
315
316/// Enum representing the existing integer lengths.
317#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
318pub enum IntegerLength {
319    I8,
320    I16,
321    I32,
322    I64,
323    I128,
324}
325
326/// Enum representing the existing float lengths.
327#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
328pub enum FloatLength {
329    F16,
330    F32,
331    F64,
332    F128,
333}
334
335impl IntegerLength {
336    pub fn bits(self) -> usize {
337        match self {
338            IntegerLength::I8 => 8,
339            IntegerLength::I16 => 16,
340            IntegerLength::I32 => 32,
341            IntegerLength::I64 => 64,
342            IntegerLength::I128 => 128,
343        }
344    }
345}
346
347impl FloatLength {
348    pub fn bits(self) -> usize {
349        match self {
350            FloatLength::F16 => 16,
351            FloatLength::F32 => 32,
352            FloatLength::F64 => 64,
353            FloatLength::F128 => 128,
354        }
355    }
356}
357
358/// An identifier that specifies the address space that some operation
359/// should operate on. Special address spaces have an effect on code generation,
360/// depending on the target and the address spaces it implements.
361#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
362pub struct AddressSpace(pub u32);
363
364impl AddressSpace {
365    /// The default address space, corresponding to data space.
366    pub const DATA: Self = AddressSpace(0);
367}
368
369/// Inclusive wrap-around range of valid values (bitwise representation), that is, if
370/// start > end, it represents `start..=MAX`, followed by `0..=end`.
371///
372/// That is, for an i8 primitive, a range of `254..=2` means following
373/// sequence:
374///
375///    254 (-2), 255 (-1), 0, 1, 2
376#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
377pub struct WrappingRange {
378    pub start: u128,
379    pub end: u128,
380}
381
382impl WrappingRange {
383    /// Returns `true` if `size` completely fills the range.
384    #[inline]
385    pub fn is_full(&self, size: Size) -> Result<bool, Error> {
386        let Some(max_value) = size.unsigned_int_max() else {
387            return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits()));
388        };
389        if self.start <= max_value && self.end <= max_value {
390            Ok(self.start == (self.end.wrapping_add(1) & max_value))
391        } else {
392            Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits()))
393        }
394    }
395
396    /// Returns `true` if `v` is contained in the range.
397    #[inline(always)]
398    pub fn contains(&self, v: u128) -> bool {
399        if self.wraps_around() {
400            self.start <= v || v <= self.end
401        } else {
402            self.start <= v && v <= self.end
403        }
404    }
405
406    /// Returns `true` if the range wraps around.
407    /// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`.
408    /// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`.
409    #[inline]
410    pub fn wraps_around(&self) -> bool {
411        self.start > self.end
412    }
413}
414
415impl Debug for WrappingRange {
416    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
417        if self.start > self.end {
418            write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
419        } else {
420            write!(fmt, "{}..={}", self.start, self.end)?;
421        }
422        Ok(())
423    }
424}
425
426/// General language calling conventions.
427#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
428pub enum CallConvention {
429    C,
430    Rust,
431
432    Cold,
433    PreserveMost,
434    PreserveAll,
435
436    Custom,
437
438    // Target-specific calling conventions.
439    ArmAapcs,
440    CCmseNonSecureCall,
441    CCmseNonSecureEntry,
442
443    Msp430Intr,
444
445    PtxKernel,
446
447    GpuKernel,
448
449    X86Fastcall,
450    X86Intr,
451    X86Stdcall,
452    X86ThisCall,
453    X86VectorCall,
454
455    X86_64SysV,
456    X86_64Win64,
457
458    AvrInterrupt,
459    AvrNonBlockingInterrupt,
460
461    RiscvInterrupt,
462}
463
464#[non_exhaustive]
465#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
466pub struct ReprFlags {
467    pub is_simd: bool,
468    pub is_c: bool,
469    pub is_transparent: bool,
470    pub is_linear: bool,
471}
472
473#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
474pub enum IntegerType {
475    /// Pointer-sized integer type, i.e. `isize` and `usize`.
476    Pointer {
477        /// Signedness. e.g. `true` for `isize`
478        is_signed: bool,
479    },
480    /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`.
481    Fixed {
482        /// Length of this integer type. e.g. `IntegerLength::I8` for `u8`.
483        length: IntegerLength,
484        /// Signedness. e.g. `false` for `u8`
485        is_signed: bool,
486    },
487}
488
489/// Representation options provided by the user
490#[non_exhaustive]
491#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
492pub struct ReprOptions {
493    pub int: Option<IntegerType>,
494    pub align: Option<Align>,
495    pub pack: Option<Align>,
496    pub flags: ReprFlags,
497}