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    Aggregate {
229        /// If true, the size is exact, otherwise it's only a lower bound.
230        sized: bool,
231    },
232}
233
234impl ValueAbi {
235    /// Returns `true` if the layout corresponds to an unsized type.
236    pub fn is_unsized(&self) -> bool {
237        match *self {
238            ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false,
239            ValueAbi::Aggregate { sized } => !sized,
240        }
241    }
242}
243
244/// Information about one scalar component of a Rust type.
245#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)]
246pub enum Scalar {
247    Initialized {
248        /// The primitive type used to represent this value.
249        value: Primitive,
250        /// The range that represents valid values.
251        /// The range must be valid for the `primitive` size.
252        valid_range: WrappingRange,
253    },
254    Union {
255        /// Unions never have niches, so there is no `valid_range`.
256        /// Even for unions, we need to use the correct registers for the kind of
257        /// values inside the union, so we keep the `Primitive` type around.
258        /// It is also used to compute the size of the scalar.
259        value: Primitive,
260    },
261}
262
263impl Scalar {
264    pub fn has_niche(&self, target: &MachineInfo) -> bool {
265        match self {
266            Scalar::Initialized { value, valid_range } => {
267                !valid_range.is_full(value.size(target)).unwrap()
268            }
269            Scalar::Union { .. } => false,
270        }
271    }
272}
273
274/// Fundamental unit of memory access and layout.
275#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)]
276pub enum Primitive {
277    /// The `bool` is the signedness of the `Integer` type.
278    ///
279    /// One would think we would not care about such details this low down,
280    /// but some ABIs are described in terms of C types and ISAs where the
281    /// integer arithmetic is done on {sign,zero}-extended registers, e.g.
282    /// a negative integer passed by zero-extension will appear positive in
283    /// the callee, and most operations on it will produce the wrong values.
284    Int {
285        length: IntegerLength,
286        signed: bool,
287    },
288    Float {
289        length: FloatLength,
290    },
291    Pointer(AddressSpace),
292}
293
294impl Primitive {
295    pub fn size(self, target: &MachineInfo) -> Size {
296        match self {
297            Primitive::Int { length, .. } => Size::from_bits(length.bits()),
298            Primitive::Float { length } => Size::from_bits(length.bits()),
299            Primitive::Pointer(_) => target.pointer_width,
300        }
301    }
302}
303
304/// Enum representing the existing integer lengths.
305#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
306pub enum IntegerLength {
307    I8,
308    I16,
309    I32,
310    I64,
311    I128,
312}
313
314/// Enum representing the existing float lengths.
315#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
316pub enum FloatLength {
317    F16,
318    F32,
319    F64,
320    F128,
321}
322
323impl IntegerLength {
324    pub fn bits(self) -> usize {
325        match self {
326            IntegerLength::I8 => 8,
327            IntegerLength::I16 => 16,
328            IntegerLength::I32 => 32,
329            IntegerLength::I64 => 64,
330            IntegerLength::I128 => 128,
331        }
332    }
333}
334
335impl FloatLength {
336    pub fn bits(self) -> usize {
337        match self {
338            FloatLength::F16 => 16,
339            FloatLength::F32 => 32,
340            FloatLength::F64 => 64,
341            FloatLength::F128 => 128,
342        }
343    }
344}
345
346/// An identifier that specifies the address space that some operation
347/// should operate on. Special address spaces have an effect on code generation,
348/// depending on the target and the address spaces it implements.
349#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
350pub struct AddressSpace(pub u32);
351
352impl AddressSpace {
353    /// The default address space, corresponding to data space.
354    pub const DATA: Self = AddressSpace(0);
355}
356
357/// Inclusive wrap-around range of valid values (bitwise representation), that is, if
358/// start > end, it represents `start..=MAX`, followed by `0..=end`.
359///
360/// That is, for an i8 primitive, a range of `254..=2` means following
361/// sequence:
362///
363///    254 (-2), 255 (-1), 0, 1, 2
364#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
365pub struct WrappingRange {
366    pub start: u128,
367    pub end: u128,
368}
369
370impl WrappingRange {
371    /// Returns `true` if `size` completely fills the range.
372    #[inline]
373    pub fn is_full(&self, size: Size) -> Result<bool, Error> {
374        let Some(max_value) = size.unsigned_int_max() else {
375            return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits()));
376        };
377        if self.start <= max_value && self.end <= max_value {
378            Ok(self.start == (self.end.wrapping_add(1) & max_value))
379        } else {
380            Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits()))
381        }
382    }
383
384    /// Returns `true` if `v` is contained in the range.
385    #[inline(always)]
386    pub fn contains(&self, v: u128) -> bool {
387        if self.wraps_around() {
388            self.start <= v || v <= self.end
389        } else {
390            self.start <= v && v <= self.end
391        }
392    }
393
394    /// Returns `true` if the range wraps around.
395    /// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`.
396    /// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`.
397    #[inline]
398    pub fn wraps_around(&self) -> bool {
399        self.start > self.end
400    }
401}
402
403impl Debug for WrappingRange {
404    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
405        if self.start > self.end {
406            write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
407        } else {
408            write!(fmt, "{}..={}", self.start, self.end)?;
409        }
410        Ok(())
411    }
412}
413
414/// General language calling conventions.
415#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
416pub enum CallConvention {
417    C,
418    Rust,
419
420    Cold,
421    PreserveMost,
422    PreserveAll,
423
424    Custom,
425
426    // Target-specific calling conventions.
427    ArmAapcs,
428    CCmseNonSecureCall,
429    CCmseNonSecureEntry,
430
431    Msp430Intr,
432
433    PtxKernel,
434
435    GpuKernel,
436
437    X86Fastcall,
438    X86Intr,
439    X86Stdcall,
440    X86ThisCall,
441    X86VectorCall,
442
443    X86_64SysV,
444    X86_64Win64,
445
446    AvrInterrupt,
447    AvrNonBlockingInterrupt,
448
449    RiscvInterrupt,
450}
451
452#[non_exhaustive]
453#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
454pub struct ReprFlags {
455    pub is_simd: bool,
456    pub is_c: bool,
457    pub is_transparent: bool,
458    pub is_linear: bool,
459}
460
461#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
462pub enum IntegerType {
463    /// Pointer-sized integer type, i.e. `isize` and `usize`.
464    Pointer {
465        /// Signedness. e.g. `true` for `isize`
466        is_signed: bool,
467    },
468    /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`.
469    Fixed {
470        /// Length of this integer type. e.g. `IntegerLength::I8` for `u8`.
471        length: IntegerLength,
472        /// Signedness. e.g. `false` for `u8`
473        is_signed: bool,
474    },
475}
476
477/// Representation options provided by the user
478#[non_exhaustive]
479#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
480pub struct ReprOptions {
481    pub int: Option<IntegerType>,
482    pub align: Option<Align>,
483    pub pack: Option<Align>,
484    pub flags: ReprFlags,
485}